Codebase list libgoogle-gson-java / 1433a51
New upstream version 2.9.0 tony mancill 1 year, 11 months ago
125 changed file(s) with 3933 addition(s) and 3475 deletion(s). Raw diff Collapse all Expand all
0 ---
1 name: Bug report
2 about: Report a Gson bug.
3 title: ''
4 labels: bug
5 assignees: ''
6
7 ---
8
9 # Gson version
10 <!-- Gson version you are using, for example '2.8.8' -->
11
12
13 # Java / Android version
14 <!-- Version of the Java or Android platform on which the bug occurred -->
15
16
17 # Used tools
18 <!-- List relevant build tools and plugins with version number here which might affect Gson -->
19 - [ ] Maven; version:
20 - [ ] Gradle; version:
21 - [ ] ProGuard (attach the configuration file please); version:
22 - [ ] ...
23
24 # Description
25 <!-- Describe the bug you experienced -->
26
27
28 ## Expected behavior
29 <!-- What behavior did you expect? -->
30
31
32 ## Actual behavior
33 <!-- What happened instead? -->
34
35
36 # Reproduction steps
37 <!-- Provide exact reproduction steps for reproducing the bug -->
38 <!-- Provide a short code snippet or link to a demo project -->
39
40 1. ...
41 2. ...
42
43 # Exception stack trace
44 <!-- In case an exception occurred, paste the COMPLETE exception stack trace in the code block below or attach it as file -->
45
46 ```
47
48 ```
0 contact_links:
1 - name: Usage question
2 url: https://stackoverflow.com/questions/tagged/gson
3 about: Ask usage questions on StackOverflow.
0 ---
1 name: Feature request
2 about: Request a feature. ⚠️ Gson is in maintenance mode; large feature requests might be rejected.
3 title: ''
4 labels: enhancement
5 assignees: ''
6
7 ---
8
9 # Problem solved by the feature
10 <!-- Describe which problem the requested feature solves -->
11
12
13 # Feature description
14 <!-- Describe the feature -->
15
16
17 # Alternatives / workarounds
18 <!-- Describe alternatives or workarounds in case you are aware of any -->
19
0 name: Build
1
2 on: [push, pull_request]
3
4 jobs:
5 build:
6 runs-on: ubuntu-latest
7
8 steps:
9 - uses: actions/checkout@v2
10 - name: Set up JDK 11
11 uses: actions/setup-java@v2
12 with:
13 distribution: 'temurin'
14 java-version: '11'
15 cache: 'maven'
16 - name: Build with Maven
17 run: mvn --batch-mode --update-snapshots verify
0 name: CIFuzz
1 on: [pull_request]
2 jobs:
3 Fuzzing:
4 runs-on: ubuntu-latest
5 steps:
6 - name: Build Fuzzers
7 id: build
8 uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@master
9 with:
10 oss-fuzz-project-name: 'gson'
11 dry-run: false
12 language: jvm
13 - name: Run Fuzzers
14 uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@master
15 with:
16 oss-fuzz-project-name: 'gson'
17 fuzz-seconds: 600
18 dry-run: false
19 - name: Upload Crash
20 uses: actions/upload-artifact@v1
21 if: failure() && steps.build.outcome == 'success'
22 with:
23 name: artifacts
24 path: ./out/artifacts
+0
-10
.github/workflows/gradle-wrapper-validation.yml less more
0 name: "Validate Gradle Wrapper"
1 on: [push, pull_request]
2
3 jobs:
4 validation:
5 name: "Validation"
6 runs-on: ubuntu-latest
7 steps:
8 - uses: actions/checkout@v2
9 - uses: gradle/wrapper-validation-action@v1
+0
-20
.travis.yml less more
0 language: java
1
2 jdk:
3 - openjdk11
4
5 install: mvn -f gson install -DskipTests=true
6 script: mvn -f gson test
7
8 branches:
9 except:
10 - gh-pages
11
12 notifications:
13 email: false
14
15 sudo: false
16
17 cache:
18 directories:
19 - $HOME/.m2
00 Change Log
11 ==========
2
3 ## Version 2.8.9
4
5 * Make OSGi bundle's dependency on `sun.misc` optional (#1993).
6 * Deprecate `Gson.excluder()` exposing internal `Excluder` class (#1986).
7 * Prevent Java deserialization of internal classes (#1991).
8 * Improve number strategy implementation (#1987).
9 * Fix LongSerializationPolicy null handling being inconsistent with Gson (#1990).
10 * Support arbitrary Number implementation for Object and Number deserialization (#1290).
11 * Bump proguard-maven-plugin from 2.4.0 to 2.5.1 (#1980).
12 * Don't exclude static local classes (#1969).
13 * Fix `RuntimeTypeAdapterFactory` depending on internal `Streams` class (#1959).
14 * Improve Maven build (#1964).
15 * Make dependency on `java.sql` optional (#1707).
16
17 ## Version 2.8.8
18
19 * Fixed issue with recursive types (#1390).
20 * Better behaviour with Java 9+ and `Unsafe` if there is a security manager (#1712).
21 * `EnumTypeAdapter` now works better when ProGuard has obfuscated enum fields (#1495).
222
323 ## Version 2.8.7
424
1616 Gradle:
1717 ```gradle
1818 dependencies {
19 implementation 'com.google.code.gson:gson:2.8.7'
19 implementation 'com.google.code.gson:gson:2.8.9'
2020 }
2121 ```
2222
2525 <dependency>
2626 <groupId>com.google.code.gson</groupId>
2727 <artifactId>gson</artifactId>
28 <version>2.8.7</version>
28 <version>2.8.9</version>
2929 </dependency>
3030 ```
3131
3232 [Gson jar downloads](https://maven-badges.herokuapp.com/maven-central/com.google.code.gson/gson) are available from Maven Central.
3333
34 [![Build Status](https://travis-ci.org/google/gson.svg?branch=master)](https://travis-ci.org/google/gson)
34 ![Build Status](https://github.com/google/gson/actions/workflows/build.yml/badge.svg)
35
36 ### Requirements
37 #### Minimum Java version
38 - Gson 2.9.0 and newer: Java 7
39 - Gson 2.8.9 and older: Java 6
40
41 Despite supporting older Java versions, Gson also provides a JPMS module descriptor (module name `com.google.gson`) for users of Java 9 or newer.
42
43 #### JPMS dependencies (Java 9+)
44 These are the optional Java Platform Module System (JPMS) JDK modules which Gson depends on.
45 This only applies when running Java 9 or newer.
46
47 - `java.sql` (optional since Gson 2.8.9)
48 When this module is present, Gson provides default adapters for some SQL date and time classes.
49
50 - `jdk.unsupported`, respectively class `sun.misc.Unsafe` (optional)
51 When this module is present, Gson can use the `Unsafe` class to create instances of classes without no-args constructor.
52 However, care should be taken when relying on this. `Unsafe` is not available in all environments and its usage has some pitfalls,
53 see [`GsonBuilder.disableJdkUnsafe()`](https://javadoc.io/doc/com.google.code.gson/gson/latest/com.google.gson/com/google/gson/GsonBuilder.html#disableJdkUnsafe()).
3554
3655 ### Documentation
3756 * [API Javadoc](https://www.javadoc.io/doc/com.google.code.gson/gson): Documentation for the current release
3958 * [Change log](https://github.com/google/gson/blob/master/CHANGELOG.md): Changes in the recent versions
4059 * [Design document](https://github.com/google/gson/blob/master/GsonDesignDocument.md): This document discusses issues we faced while designing Gson. It also includes a comparison of Gson with other Java libraries that can be used for Json conversion
4160
42 Please use the 'gson' tag on StackOverflow or the [google-gson Google group](https://groups.google.com/group/google-gson) to discuss Gson or to post questions.
61 Please use the ['gson' tag on StackOverflow](https://stackoverflow.com/questions/tagged/gson) or the [google-gson Google group](https://groups.google.com/group/google-gson) to discuss Gson or to post questions.
4362
4463 ### Related Content Created by Third Parties
4564 * [Gson Tutorial](https://www.studytrails.com/java/json/java-google-json-introduction/) by `StudyTrails`
7373 ## <a name="TOC-Gson-With-Gradle"></a>Using Gson with Gradle/Android
7474 ```
7575 dependencies {
76 implementation 'com.google.code.gson:gson:2.8.7'
76 implementation 'com.google.code.gson:gson:2.8.9'
7777 }
7878 ```
7979 ## <a name="TOC-Gson-With-Maven"></a>Using Gson with Maven
8585 <dependency>
8686 <groupId>com.google.code.gson</groupId>
8787 <artifactId>gson</artifactId>
88 <version>2.8.7</version>
88 <version>2.8.9</version>
8989 <scope>compile</scope>
9090 </dependency>
9191 </dependencies>
428428 public Id<?> createInstance(Type type) {
429429 Type[] typeParameters = ((ParameterizedType)type).getActualTypeArguments();
430430 Type idType = typeParameters[0]; // Id has only one parameterized type T
431 return Id.get((Class)idType, 0L);
431 return new Id((Class)idType, 0L);
432432 }
433433 }
434434 ```
+0
-12
build.gradle less more
0 buildscript {
1 repositories {
2 mavenCentral()
3 }
4 }
5
6 allprojects {
7 repositories {
8 mavenCentral()
9 }
10 }
11
0 # codegen
1
2 This Maven module contains the source code for automatically generating Gson type adapters.
3
4 :warning: This module is currently non-functional and might be removed in the future.
00 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
11 <modelVersion>4.0.0</modelVersion>
2 <groupId>com.google.code.gson</groupId>
2 <parent>
3 <groupId>com.google.code.gson</groupId>
4 <artifactId>gson-parent</artifactId>
5 <version>2.9.0</version>
6 </parent>
7
38 <artifactId>gson-codegen</artifactId>
4 <packaging>jar</packaging>
5 <version>1.0-SNAPSHOT</version>
69 <inceptionYear>2008</inceptionYear>
710 <name>Gson Code Gen</name>
8 <parent>
9 <groupId>org.sonatype.oss</groupId>
10 <artifactId>oss-parent</artifactId>
11 <version>7</version>
12 </parent>
13 <url>http://code.google.com/p/google-gson/</url>
1411 <description>Google Gson grab bag of utilities, type adapters, etc.</description>
15 <properties>
16 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
17 </properties>
12
1813 <licenses>
1914 <license>
20 <name>The Apache Software License, Version 2.0</name>
21 <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
22 <distribution>repo</distribution>
15 <name>Apache-2.0</name>
16 <url>https://www.apache.org/licenses/LICENSE-2.0.txt</url>
2317 </license>
2418 </licenses>
25 <scm>
26 <connection>scm:svn:http://google-gson.googlecode.com/svn/trunk/extras</connection>
27 <developerConnection>scm:svn:https://google-gson.googlecode.com/svn/trunk/extras</developerConnection>
28 <url>http://google-gson.codegoogle.com/svn/trunk/extras</url>
29 </scm>
30 <issueManagement>
31 <system>Google Code Issue Tracking</system>
32 <url>http://code.google.com/p/google-gson/issues/list</url>
33 </issueManagement>
19
3420 <organization>
3521 <name>Google, Inc.</name>
36 <url>http://www.google.com</url>
22 <url>https://www.google.com</url>
3723 </organization>
24
3825 <dependencies>
3926 <dependency>
4027 <groupId>junit</groupId>
4128 <artifactId>junit</artifactId>
42 <version>4.13.1</version>
4329 <scope>test</scope>
4430 </dependency>
4531 </dependencies>
46 <profiles>
47 <!-- Activate PGP signing only when performing a release -->
48 <profile>
49 <id>release-sign-artifacts</id>
50 <activation>
51 <property>
52 <name>performRelease</name>
53 <value>true</value>
54 </property>
55 </activation>
56 <build>
57 <plugins>
58 <plugin>
59 <groupId>org.apache.maven.plugins</groupId>
60 <artifactId>maven-gpg-plugin</artifactId>
61 <version>1.4</version>
62 <executions>
63 <execution>
64 <id>sign-artifacts</id>
65 <phase>verify</phase>
66 <goals>
67 <goal>sign</goal>
68 </goals>
69 </execution>
70 </executions>
71 </plugin>
72 </plugins>
73 </build>
74 </profile>
75 </profiles>
32
7633 <build>
77 <defaultGoal>package</defaultGoal>
7834 <plugins>
7935 <plugin>
8036 <groupId>org.apache.maven.plugins</groupId>
8137 <artifactId>maven-compiler-plugin</artifactId>
82 <version>2.5.1</version>
83 <configuration>
84 <source>1.6</source>
85 <target>1.6</target>
86 <compilerArgument>-proc:none</compilerArgument>
87 </configuration>
88 </plugin>
89 <plugin>
90 <groupId>org.apache.maven.plugins</groupId>
91 <artifactId>maven-jar-plugin</artifactId>
92 <version>2.4</version>
9338 <executions>
39 <!-- First compile without without annotation processing, then
40 compile again, see https://stackoverflow.com/a/36250332 -->
9441 <execution>
95 <phase>package</phase>
42 <id>default-compile</id>
43 <configuration>
44 <compilerArgument>-proc:none</compilerArgument>
45 </configuration>
46 </execution>
47 <execution>
48 <id>compile-project</id>
49 <phase>compile</phase>
9650 <goals>
97 <goal>jar</goal>
51 <goal>compile</goal>
9852 </goals>
9953 </execution>
10054 </executions>
101 <configuration>
102 <archive>
103 <addMavenDescriptor>false</addMavenDescriptor>
104 </archive>
105 </configuration>
106 </plugin>
107 <plugin>
108 <groupId>org.apache.maven.plugins</groupId>
109 <artifactId>maven-source-plugin</artifactId>
110 <version>2.1.2</version>
111 <executions>
112 <execution>
113 <id>attach-sources</id>
114 <phase>verify</phase>
115 <goals>
116 <goal>jar</goal>
117 </goals>
118 </execution>
119 </executions>
120 </plugin>
121 <plugin>
122 <groupId>org.apache.maven.plugins</groupId>
123 <artifactId>maven-javadoc-plugin</artifactId>
124 <version>2.8.1</version>
125 <executions>
126 <execution>
127 <id>attach-javadocs</id>
128 <goals>
129 <goal>jar</goal>
130 </goals>
131 </execution>
132 </executions>
133 <configuration>
134 <links>
135 <link>http://download.oracle.com/javase/1.5.0/docs/api/</link>
136 </links>
137 <version>true</version>
138 <show>public</show>
139 </configuration>
140 </plugin>
141 <plugin>
142 <groupId>org.apache.maven.plugins</groupId>
143 <artifactId>maven-eclipse-plugin</artifactId>
144 <version>2.9</version>
145 <configuration>
146 <downloadSources>true</downloadSources>
147 <downloadJavadocs>true</downloadJavadocs>
148 <workspace>
149 ../eclipse-ws/
150 </workspace>
151 <workspaceCodeStylesURL>
152 file:///${basedir}/../lib/gson-formatting-styles.xml
153 </workspaceCodeStylesURL>
154 </configuration>
155 </plugin>
156 <plugin>
157 <groupId>org.apache.maven.plugins</groupId>
158 <artifactId>maven-release-plugin</artifactId>
159 <!-- version>2.3.2</version -->
160 <configuration>
161 <arguments>-DenableCiProfile=true</arguments>
162 <tagBase>https://google-gson.googlecode.com/svn/tags/</tagBase>
163 </configuration>
16455 </plugin>
16556 </plugins>
57
58 <pluginManagement>
59 <plugins>
60 <plugin>
61 <groupId>org.apache.maven.plugins</groupId>
62 <artifactId>maven-deploy-plugin</artifactId>
63 <version>3.0.0-M2</version>
64 <configuration>
65 <!-- Not deployed -->
66 <skip>true</skip>
67 </configuration>
68 </plugin>
69 </plugins>
70 </pluginManagement>
16671 </build>
72
16773 <developers>
16874 <developer>
16975 <name>Inderjeet Singh</name>
5252 System.out.println("Generating type adapter: " + typeAdapterName + " in " + sourceFile.getName());
5353
5454 JavaWriter writer = new JavaWriter(sourceFile.openWriter());
55 writer.addPackage(CodeGen.getPackage(type).getQualifiedName().toString());
56 writer.beginType(typeAdapterName, "class", FINAL, null);
57 writer.endType();
58 writer.close();
55 try {
56 writer.addPackage(CodeGen.getPackage(type).getQualifiedName().toString());
57 writer.beginType(typeAdapterName, "class", FINAL, null);
58 writer.endType();
59 } finally {
60 writer.close();
61 }
5962 }
6063 }
0 # android-proguard-example
1
2 Example Android project showing how to properly configure [ProGuard](https://www.guardsquare.com/proguard).
3 ProGuard is a tool for 'shrinking' and obfuscating compiled classes. It can rename methods and fields,
4 or remove them if they appear to be unused. This can cause issues for Gson which uses Java reflection to
5 access the fields of a class. It is necessary to configure ProGuard to make sure that Gson works correctly.
6
7 Also have a look at the [ProGuard manual](https://www.guardsquare.com/manual/configuration/usage#keepoverview)
8 for more details on how ProGuard can be configured.
9
10 The R8 code shrinker uses the same rule format as ProGuard, but there are differences between these two
11 tools. Have a look at R8's Compatibility FAQ, and especially at the [Gson section](https://r8.googlesource.com/r8/+/refs/heads/main/compatibility-faq.md#gson).
0 # extras
1
2 This Maven module contains the source code for supplementary Gson features which
3 are not included by default.
4
5 The artifacts created by this module are currently not deployed to Maven Central.
00 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
11 <modelVersion>4.0.0</modelVersion>
2 <groupId>com.google.code.gson</groupId>
2 <parent>
3 <groupId>com.google.code.gson</groupId>
4 <artifactId>gson-parent</artifactId>
5 <version>2.9.0</version>
6 </parent>
7
38 <artifactId>gson-extras</artifactId>
4 <packaging>jar</packaging>
5 <version>1.0-SNAPSHOT</version>
69 <inceptionYear>2008</inceptionYear>
710 <name>Gson Extras</name>
8 <parent>
9 <groupId>org.sonatype.oss</groupId>
10 <artifactId>oss-parent</artifactId>
11 <version>9</version>
12 </parent>
13 <url>http://code.google.com/p/google-gson/</url>
1411 <description>Google Gson grab bag of utilities, type adapters, etc.</description>
15 <properties>
16 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
17 </properties>
12
1813 <licenses>
1914 <license>
20 <name>The Apache Software License, Version 2.0</name>
21 <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
22 <distribution>repo</distribution>
15 <name>Apache-2.0</name>
16 <url>https://www.apache.org/licenses/LICENSE-2.0.txt</url>
2317 </license>
2418 </licenses>
25 <scm>
26 <connection>scm:svn:http://google-gson.googlecode.com/svn/trunk/extras</connection>
27 <developerConnection>scm:svn:https://google-gson.googlecode.com/svn/trunk/extras</developerConnection>
28 <url>http://google-gson.codegoogle.com/svn/trunk/extras</url>
29 </scm>
30 <issueManagement>
31 <system>Google Code Issue Tracking</system>
32 <url>http://code.google.com/p/google-gson/issues/list</url>
33 </issueManagement>
19
3420 <organization>
3521 <name>Google, Inc.</name>
36 <url>http://www.google.com</url>
22 <url>https://www.google.com</url>
3723 </organization>
24
3825 <dependencies>
3926 <dependency>
4027 <groupId>com.google.code.gson</groupId>
4128 <artifactId>gson</artifactId>
42 <version>2.7</version>
43 <scope>compile</scope>
29 <version>${project.parent.version}</version>
4430 </dependency>
4531 <dependency>
4632 <groupId>javax.annotation</groupId>
5036 <dependency>
5137 <groupId>junit</groupId>
5238 <artifactId>junit</artifactId>
53 <version>4.13.1</version>
5439 <scope>test</scope>
5540 </dependency>
5641 </dependencies>
57 <profiles>
58 <!-- Activate PGP signing only when performing a release -->
59 <profile>
60 <id>release-sign-artifacts</id>
61 <activation>
62 <property>
63 <name>performRelease</name>
64 <value>true</value>
65 </property>
66 </activation>
67 <build>
68 <plugins>
69 <plugin>
70 <groupId>org.apache.maven.plugins</groupId>
71 <artifactId>maven-gpg-plugin</artifactId>
72 <version>1.5</version>
73 <executions>
74 <execution>
75 <id>sign-artifacts</id>
76 <phase>verify</phase>
77 <goals>
78 <goal>sign</goal>
79 </goals>
80 </execution>
81 </executions>
82 </plugin>
83 </plugins>
84 </build>
85 </profile>
86 </profiles>
42
8743 <build>
88 <defaultGoal>package</defaultGoal>
89 <plugins>
90 <plugin>
91 <groupId>org.apache.maven.plugins</groupId>
92 <artifactId>maven-compiler-plugin</artifactId>
93 <version>3.5.1</version>
94 <configuration>
95 <source>1.6</source>
96 <target>1.6</target>
97 </configuration>
98 </plugin>
99 <plugin>
100 <groupId>org.apache.maven.plugins</groupId>
101 <artifactId>maven-jar-plugin</artifactId>
102 <version>3.0.2</version>
103 <executions>
104 <execution>
105 <phase>package</phase>
106 <goals>
107 <goal>jar</goal>
108 </goals>
109 </execution>
110 </executions>
111 <configuration>
112 <archive>
113 <addMavenDescriptor>false</addMavenDescriptor>
114 </archive>
115 </configuration>
116 </plugin>
117 <plugin>
118 <groupId>org.apache.maven.plugins</groupId>
119 <artifactId>maven-source-plugin</artifactId>
120 <version>3.0.1</version>
121 <executions>
122 <execution>
123 <id>attach-sources</id>
124 <phase>verify</phase>
125 <goals>
126 <goal>jar</goal>
127 </goals>
128 </execution>
129 </executions>
130 </plugin>
131 <plugin>
132 <groupId>org.apache.maven.plugins</groupId>
133 <artifactId>maven-javadoc-plugin</artifactId>
134 <version>2.10.4</version>
135 <executions>
136 <execution>
137 <id>attach-javadocs</id>
138 <goals>
139 <goal>jar</goal>
140 </goals>
141 </execution>
142 </executions>
143 <configuration>
144 <links>
145 <link>http://download.oracle.com/javase/1.5.0/docs/api/</link>
146 </links>
147 <version>true</version>
148 <show>public</show>
149 </configuration>
150 </plugin>
151 <plugin>
152 <groupId>org.apache.maven.plugins</groupId>
153 <artifactId>maven-eclipse-plugin</artifactId>
154 <version>2.10</version>
155 <configuration>
156 <downloadSources>true</downloadSources>
157 <downloadJavadocs>true</downloadJavadocs>
158 <workspace>
159 ../eclipse-ws/
160 </workspace>
161 <workspaceCodeStylesURL>
162 file:///${basedir}/../lib/gson-formatting-styles.xml
163 </workspaceCodeStylesURL>
164 </configuration>
165 </plugin>
166 <plugin>
167 <groupId>org.apache.maven.plugins</groupId>
168 <artifactId>maven-release-plugin</artifactId>
169 <!-- version>2.3.2</version -->
170 <configuration>
171 <arguments>-DenableCiProfile=true</arguments>
172 <tagBase>https://google-gson.googlecode.com/svn/tags/</tagBase>
173 </configuration>
174 </plugin>
175 </plugins>
44 <pluginManagement>
45 <plugins>
46 <plugin>
47 <groupId>org.apache.maven.plugins</groupId>
48 <artifactId>maven-deploy-plugin</artifactId>
49 <version>3.0.0-M2</version>
50 <configuration>
51 <!-- Currently not deployed -->
52 <skip>true</skip>
53 </configuration>
54 </plugin>
55 </plugins>
56 </pluginManagement>
17657 </build>
58
17759 <developers>
17860 <developer>
17961 <name>Inderjeet Singh</name>
4444 collection.add(new Event("GREETINGS", "guest"));
4545 String json = gson.toJson(collection);
4646 System.out.println("Using Gson.toJson() on a raw collection: " + json);
47 JsonParser parser = new JsonParser();
48 JsonArray array = parser.parse(json).getAsJsonArray();
47 JsonArray array = JsonParser.parseString(json).getAsJsonArray();
4948 String message = gson.fromJson(array.get(0), String.class);
5049 int number = gson.fromJson(array.get(1), int.class);
5150 Event event = gson.fromJson(array.get(2), Event.class);
4646
4747 public GraphAdapterBuilder() {
4848 this.instanceCreators = new HashMap<Type, InstanceCreator<?>>();
49 this.constructorConstructor = new ConstructorConstructor(instanceCreators);
49 this.constructorConstructor = new ConstructorConstructor(instanceCreators, true);
5050 }
5151 public GraphAdapterBuilder addType(Type type) {
5252 final ObjectConstructor<?> objectConstructor = constructorConstructor.get(TypeToken.get(type));
5353 InstanceCreator<Object> instanceCreator = new InstanceCreator<Object>() {
54 @Override
5455 public Object createInstance(Type type) {
5556 return objectConstructor.construct();
5657 }
8283 this.instanceCreators = instanceCreators;
8384 }
8485
86 @Override
8587 public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
8688 if (!instanceCreators.containsKey(type.getType())) {
8789 return null;
211213 * that is only when we've called back into Gson to deserialize a tree.
212214 */
213215 @SuppressWarnings("unchecked")
216 @Override
214217 public Object createInstance(Type type) {
215218 Graph graph = graphThreadLocal.get();
216219 if (graph == null || graph.nextCreate == null) {
2727 * after it has been deserialized from Json.
2828 * Here is an example of how this annotation is used:
2929 * <p>Here is an example of how this annotation is used:
30 * <p><pre>
31 * &#64Intercept(postDeserialize=UserValidator.class)
30 * <pre>
31 * &#64;Intercept(postDeserialize=UserValidator.class)
3232 * public class User {
3333 * String name;
3434 * String password;
4646 * }
4747 * }
4848 * }
49 * </pre></p>
49 * </pre>
5050 *
5151 * @author Inderjeet Singh
5252 */
2626 import com.google.gson.JsonPrimitive;
2727 import com.google.gson.TypeAdapter;
2828 import com.google.gson.TypeAdapterFactory;
29 import com.google.gson.internal.Streams;
3029 import com.google.gson.reflect.TypeToken;
3130 import com.google.gson.stream.JsonReader;
3231 import com.google.gson.stream.JsonWriter;
203202 return registerSubtype(type, type.getSimpleName());
204203 }
205204
205 @Override
206206 public <R> TypeAdapter<R> create(Gson gson, TypeToken<R> type) {
207207 if (type.getRawType() != baseType) {
208208 return null;
209209 }
210210
211 final TypeAdapter<JsonElement> jsonElementAdapter = gson.getAdapter(JsonElement.class);
211212 final Map<String, TypeAdapter<?>> labelToDelegate
212213 = new LinkedHashMap<String, TypeAdapter<?>>();
213214 final Map<Class<?>, TypeAdapter<?>> subtypeToDelegate
220221
221222 return new TypeAdapter<R>() {
222223 @Override public R read(JsonReader in) throws IOException {
223 JsonElement jsonElement = Streams.parse(in);
224 JsonElement jsonElement = jsonElementAdapter.read(in);
224225 JsonElement labelJsonElement;
225226 if (maintainType) {
226227 labelJsonElement = jsonElement.getAsJsonObject().get(typeFieldName);
254255 JsonObject jsonObject = delegate.toJsonTree(value).getAsJsonObject();
255256
256257 if (maintainType) {
257 Streams.write(jsonObject, out);
258 jsonElementAdapter.write(out, jsonObject);
258259 return;
259260 }
260261
269270 for (Map.Entry<String, JsonElement> e : jsonObject.entrySet()) {
270271 clone.add(e.getKey(), e.getValue());
271272 }
272 Streams.write(clone, out);
273 jsonElementAdapter.write(out, clone);
273274 }
274275 }.nullSafe();
275276 }
1515
1616 package com.google.gson.graph;
1717
18 import com.google.gson.Gson;
19 import com.google.gson.GsonBuilder;
20 import com.google.gson.reflect.TypeToken;
18 import static org.junit.Assert.assertEquals;
19 import static org.junit.Assert.assertSame;
20
2121 import java.lang.reflect.Type;
2222 import java.util.ArrayList;
2323 import java.util.Collections;
2424 import java.util.List;
25 import junit.framework.TestCase;
2625
27 public final class GraphAdapterBuilderTest extends TestCase {
26 import org.junit.Test;
27
28 import com.google.gson.Gson;
29 import com.google.gson.GsonBuilder;
30 import com.google.gson.reflect.TypeToken;
31
32 public final class GraphAdapterBuilderTest {
33 @Test
2834 public void testSerialization() {
2935 Roshambo rock = new Roshambo("ROCK");
3036 Roshambo scissors = new Roshambo("SCISSORS");
4551 gson.toJson(rock).replace('"', '\''));
4652 }
4753
54 @Test
4855 public void testDeserialization() {
4956 String json = "{'0x1':{'name':'ROCK','beats':'0x2'}," +
5057 "'0x2':{'name':'SCISSORS','beats':'0x3'}," +
6572 assertSame(rock, paper.beats);
6673 }
6774
68 public void testSerializationDirectSelfReference() {
69 Roshambo suicide = new Roshambo("SUICIDE");
70 suicide.beats = suicide;
71
72 GsonBuilder gsonBuilder = new GsonBuilder();
73 new GraphAdapterBuilder()
74 .addType(Roshambo.class)
75 .registerOn(gsonBuilder);
76 Gson gson = gsonBuilder.create();
77
78 assertEquals("{'0x1':{'name':'SUICIDE','beats':'0x1'}}",
79 gson.toJson(suicide).replace('"', '\''));
80 }
81
75 @Test
8276 public void testDeserializationDirectSelfReference() {
8377 String json = "{'0x1':{'name':'SUICIDE','beats':'0x1'}}";
8478
9387 assertSame(suicide, suicide.beats);
9488 }
9589
90 @Test
9691 public void testSerializeListOfLists() {
9792 Type listOfListsType = new TypeToken<List<List<?>>>() {}.getType();
9893 Type listOfAnyType = new TypeToken<List<?>>() {}.getType();
112107 assertEquals("{'0x1':['0x1','0x2'],'0x2':[]}", json.replace('"', '\''));
113108 }
114109
110 @Test
115111 public void testDeserializeListOfLists() {
116112 Type listOfAnyType = new TypeToken<List<?>>() {}.getType();
117113 Type listOfListsType = new TypeToken<List<List<?>>>() {}.getType();
129125 assertEquals(Collections.emptyList(), listOfLists.get(1));
130126 }
131127
128 @Test
132129 public void testSerializationWithMultipleTypes() {
133130 Company google = new Company("Google");
134131 new Employee("Jesse", google);
147144 gson.toJson(google).replace('"', '\''));
148145 }
149146
147 @Test
150148 public void testDeserializationWithMultipleTypes() {
151149 GsonBuilder gsonBuilder = new GsonBuilder();
152150 new GraphAdapterBuilder()
+0
-6
gradle/wrapper/gradle-wrapper.properties less more
0 #Fri Apr 27 17:41:01 PDT 2018
1 distributionBase=GRADLE_USER_HOME
2 distributionPath=wrapper/dists
3 zipStoreBase=GRADLE_USER_HOME
4 zipStorePath=wrapper/dists
5 distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
+0
-7
gson/README less more
0 Gson is a Java library that can be used to convert Java Objects into their
1 JSON representation. It can also be used to convert a JSON string to an
2 equivalent Java object. Gson can work with arbitrary Java objects including
3 pre-existing objects that you do not have source-code of.
4
5 Complete Gson documentation is available at its project page
6 https://github.com/google/gson
0 # gson
1
2 This Maven module contains the Gson source code. The artifacts created by this module
3 are deployed to Maven Central under the coordinates `com.google.code.gson:gson`.
22 Bundle-Description: ${project.description}
33 Bundle-Vendor: Google Gson Project
44 Bundle-ContactAddress: ${project.parent.url}
5 Bundle-RequiredExecutionEnvironment: JavaSE-1.6, JavaSE-1.7, JavaSE-1.8
6 Require-Capability: osgi.ee;filter:="(&(osgi.ee=JavaSE)(version=1.6))"
5 Bundle-RequiredExecutionEnvironment: JavaSE-1.7, JavaSE-1.8
6 Require-Capability: osgi.ee;filter:="(&(osgi.ee=JavaSE)(version=1.7))"
7
8 # Optional dependency for JDK's sun.misc.Unsafe
9 # https://bnd.bndtools.org/chapters/920-faq.html#remove-unwanted-imports-
10 Import-Package: sun.misc;resolution:=optional, *
711
812 -removeheaders: Private-Package
913
33 group = 'com.google.code.gson'
44 version = '2.8.6-SNAPSHOT'
55
6 sourceCompatibility = 1.6
7 targetCompatibility = 1.6
6 sourceCompatibility = 1.7
7 targetCompatibility = 1.7
88
99 sourceSets.main.java.exclude("**/module-info.java")
1010 dependencies {
33 <parent>
44 <groupId>com.google.code.gson</groupId>
55 <artifactId>gson-parent</artifactId>
6 <version>2.8.8</version>
6 <version>2.9.0</version>
77 </parent>
88
99 <artifactId>gson</artifactId>
1010 <name>Gson</name>
11
12 <licenses>
13 <license>
14 <name>Apache-2.0</name>
15 <url>https://www.apache.org/licenses/LICENSE-2.0.txt</url>
16 </license>
17 </licenses>
1118
1219 <dependencies>
1320 <dependency>
1522 <artifactId>junit</artifactId>
1623 <scope>test</scope>
1724 </dependency>
18 <dependency>
19 <groupId>com.github.wvengen</groupId>
20 <artifactId>proguard-maven-plugin</artifactId>
21 <version>2.4.0</version>
22 <scope>test</scope>
23 </dependency>
2425 </dependencies>
25
26
2627 <build>
2728 <plugins>
2829 <plugin>
2930 <groupId>org.apache.maven.plugins</groupId>
31 <artifactId>maven-compiler-plugin</artifactId>
32 <executions>
33 <execution>
34 <id>default-compile</id>
35 <configuration>
36 <excludes>
37 <!-- module-info.java is compiled using ModiTect -->
38 <exclude>module-info.java</exclude>
39 </excludes>
40 </configuration>
41 </execution>
42 </executions>
43 </plugin>
44 <!-- Note: Javadoc plugin has to be run in combination with >= `package`
45 phase, e.g. `mvn package javadoc:javadoc`, otherwise it fails with
46 "Aggregator report contains named and unnamed modules" -->
47 <plugin>
48 <groupId>org.apache.maven.plugins</groupId>
49 <artifactId>maven-surefire-plugin</artifactId>
50 <version>3.0.0-M5</version>
51 <configuration>
52 <!-- Deny illegal access, this is required for ReflectionAccessTest -->
53 <!-- Requires Java >= 9; Important: In case future Java versions
54 don't support this flag anymore, don't remove it unless CI also runs with
55 that Java version. Ideally would use toolchain to specify that this should
56 run with e.g. Java 11, but Maven toolchain requirements (unlike Gradle ones)
57 don't seem to be portable (every developer would have to set up toolchain
58 configuration locally). -->
59 <argLine>--illegal-access=deny</argLine>
60 </configuration>
61 </plugin>
62 <plugin>
63 <groupId>org.apache.maven.plugins</groupId>
3064 <artifactId>maven-javadoc-plugin</artifactId>
3165 <configuration>
32 <includePackageNames>com.google.gson</includePackageNames>
3366 <excludePackageNames>com.google.gson.internal:com.google.gson.internal.bind</excludePackageNames>
34 <links>
35 <link>https://docs.oracle.com/javase/6/docs/api/</link>
36 </links>
37 </configuration>
67 </configuration>
68 </plugin>
69 <!-- Add module-info to JAR, see https://github.com/moditect/moditect#adding-module-descriptors-to-existing-jar-files -->
70 <!-- Uses ModiTect instead of separate maven-compiler-plugin executions
71 for better Eclipse IDE support, see https://github.com/eclipse-m2e/m2e-core/issues/393 -->
72 <plugin>
73 <groupId>org.moditect</groupId>
74 <artifactId>moditect-maven-plugin</artifactId>
75 <version>1.0.0.RC2</version>
76 <executions>
77 <execution>
78 <id>add-module-info</id>
79 <phase>package</phase>
80 <goals>
81 <goal>add-module-info</goal>
82 </goals>
83 <configuration>
84 <jvmVersion>9</jvmVersion>
85 <module>
86 <moduleInfoFile>${project.build.sourceDirectory}/module-info.java</moduleInfoFile>
87 </module>
88 </configuration>
89 </execution>
90 </executions>
3891 </plugin>
3992 <plugin>
4093 <groupId>biz.aQute.bnd</groupId>
4194 <artifactId>bnd-maven-plugin</artifactId>
42 <version>5.3.0</version>
95 <version>6.1.0</version>
4396 <executions>
4497 <execution>
4598 <goals>
53106 <artifactId>maven-jar-plugin</artifactId>
54107 <configuration>
55108 <archive>
109 <!-- Use existing manifest generated by BND plugin -->
56110 <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
57111 </archive>
58112 </configuration>
103157 <plugin>
104158 <groupId>com.github.wvengen</groupId>
105159 <artifactId>proguard-maven-plugin</artifactId>
160 <version>2.5.3</version>
106161 <executions>
107162 <execution>
108163 <phase>process-test-classes</phase>
109 <goals><goal>proguard</goal></goals>
110 </execution>
111 </executions>
112 <configuration>
113 <proguardVersion>6.2.2</proguardVersion>
164 <goals>
165 <goal>proguard</goal>
166 </goals>
167 </execution>
168 </executions>
169 <configuration>
114170 <obfuscate>true</obfuscate>
115171 <injar>test-classes-obfuscated-injar</injar>
116172 <outjar>test-classes-obfuscated-outjar</outjar>
121177 <lib>${java.home}/jmods/java.base.jmod</lib>
122178 </libs>
123179 </configuration>
124 <dependencies>
125 <dependency>
126 <groupId>net.sf.proguard</groupId>
127 <artifactId>proguard-base</artifactId>
128 <version>6.2.2</version>
129 <scope>runtime</scope>
130 </dependency>
131 </dependencies>
132180 </plugin>
133181 <plugin>
134182 <artifactId>maven-resources-plugin</artifactId>
+0
-165
gson/src/main/java/com/google/gson/DefaultDateTypeAdapter.java less more
0 /*
1 * Copyright (C) 2008 Google Inc.
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 package com.google.gson;
17
18 import java.io.IOException;
19 import java.sql.Timestamp;
20 import java.text.DateFormat;
21 import java.text.ParseException;
22 import java.text.ParsePosition;
23 import java.text.SimpleDateFormat;
24 import java.util.ArrayList;
25 import java.util.Date;
26 import java.util.List;
27 import java.util.Locale;
28
29 import com.google.gson.internal.JavaVersion;
30 import com.google.gson.internal.PreJava9DateFormatProvider;
31 import com.google.gson.internal.bind.util.ISO8601Utils;
32 import com.google.gson.stream.JsonReader;
33 import com.google.gson.stream.JsonToken;
34 import com.google.gson.stream.JsonWriter;
35
36 /**
37 * This type adapter supports three subclasses of date: Date, Timestamp, and
38 * java.sql.Date.
39 *
40 * @author Inderjeet Singh
41 * @author Joel Leitch
42 */
43 final class DefaultDateTypeAdapter extends TypeAdapter<Date> {
44
45 private static final String SIMPLE_NAME = "DefaultDateTypeAdapter";
46
47 private final Class<? extends Date> dateType;
48
49 /**
50 * List of 1 or more different date formats used for de-serialization attempts.
51 * The first of them is used for serialization as well.
52 */
53 private final List<DateFormat> dateFormats = new ArrayList<DateFormat>();
54
55 DefaultDateTypeAdapter(Class<? extends Date> dateType) {
56 this.dateType = verifyDateType(dateType);
57 dateFormats.add(DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT, Locale.US));
58 if (!Locale.getDefault().equals(Locale.US)) {
59 dateFormats.add(DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT));
60 }
61 if (JavaVersion.isJava9OrLater()) {
62 dateFormats.add(PreJava9DateFormatProvider.getUSDateTimeFormat(DateFormat.DEFAULT, DateFormat.DEFAULT));
63 }
64 }
65
66 DefaultDateTypeAdapter(Class<? extends Date> dateType, String datePattern) {
67 this.dateType = verifyDateType(dateType);
68 dateFormats.add(new SimpleDateFormat(datePattern, Locale.US));
69 if (!Locale.getDefault().equals(Locale.US)) {
70 dateFormats.add(new SimpleDateFormat(datePattern));
71 }
72 }
73
74 DefaultDateTypeAdapter(Class<? extends Date> dateType, int style) {
75 this.dateType = verifyDateType(dateType);
76 dateFormats.add(DateFormat.getDateInstance(style, Locale.US));
77 if (!Locale.getDefault().equals(Locale.US)) {
78 dateFormats.add(DateFormat.getDateInstance(style));
79 }
80 if (JavaVersion.isJava9OrLater()) {
81 dateFormats.add(PreJava9DateFormatProvider.getUSDateFormat(style));
82 }
83 }
84
85 public DefaultDateTypeAdapter(int dateStyle, int timeStyle) {
86 this(Date.class, dateStyle, timeStyle);
87 }
88
89 public DefaultDateTypeAdapter(Class<? extends Date> dateType, int dateStyle, int timeStyle) {
90 this.dateType = verifyDateType(dateType);
91 dateFormats.add(DateFormat.getDateTimeInstance(dateStyle, timeStyle, Locale.US));
92 if (!Locale.getDefault().equals(Locale.US)) {
93 dateFormats.add(DateFormat.getDateTimeInstance(dateStyle, timeStyle));
94 }
95 if (JavaVersion.isJava9OrLater()) {
96 dateFormats.add(PreJava9DateFormatProvider.getUSDateTimeFormat(dateStyle, timeStyle));
97 }
98 }
99
100 private static Class<? extends Date> verifyDateType(Class<? extends Date> dateType) {
101 if ( dateType != Date.class && dateType != java.sql.Date.class && dateType != Timestamp.class ) {
102 throw new IllegalArgumentException("Date type must be one of " + Date.class + ", " + Timestamp.class + ", or " + java.sql.Date.class + " but was " + dateType);
103 }
104 return dateType;
105 }
106
107 // These methods need to be synchronized since JDK DateFormat classes are not thread-safe
108 // See issue 162
109 @Override
110 public void write(JsonWriter out, Date value) throws IOException {
111 if (value == null) {
112 out.nullValue();
113 return;
114 }
115 synchronized(dateFormats) {
116 String dateFormatAsString = dateFormats.get(0).format(value);
117 out.value(dateFormatAsString);
118 }
119 }
120
121 @Override
122 public Date read(JsonReader in) throws IOException {
123 if (in.peek() == JsonToken.NULL) {
124 in.nextNull();
125 return null;
126 }
127 Date date = deserializeToDate(in.nextString());
128 if (dateType == Date.class) {
129 return date;
130 } else if (dateType == Timestamp.class) {
131 return new Timestamp(date.getTime());
132 } else if (dateType == java.sql.Date.class) {
133 return new java.sql.Date(date.getTime());
134 } else {
135 // This must never happen: dateType is guarded in the primary constructor
136 throw new AssertionError();
137 }
138 }
139
140 private Date deserializeToDate(String s) {
141 synchronized (dateFormats) {
142 for (DateFormat dateFormat : dateFormats) {
143 try {
144 return dateFormat.parse(s);
145 } catch (ParseException ignored) {}
146 }
147 try {
148 return ISO8601Utils.parse(s, new ParsePosition(0));
149 } catch (ParseException e) {
150 throw new JsonSyntaxException(s, e);
151 }
152 }
153 }
154
155 @Override
156 public String toString() {
157 DateFormat defaultFormat = dateFormats.get(0);
158 if (defaultFormat instanceof SimpleDateFormat) {
159 return SIMPLE_NAME + '(' + ((SimpleDateFormat) defaultFormat).toPattern() + ')';
160 } else {
161 return SIMPLE_NAME + '(' + defaultFormat.getClass().getSimpleName() + ')';
162 }
163 }
164 }
4343 * Using this naming policy with Gson will ensure that the first "letter" of the Java
4444 * field name is capitalized when serialized to its JSON form.
4545 *
46 * <p>Here's a few examples of the form "Java Field Name" ---&gt; "JSON Field Name":</p>
46 * <p>Here are a few examples of the form "Java Field Name" ---&gt; "JSON Field Name":</p>
4747 * <ul>
4848 * <li>someFieldName ---&gt; SomeFieldName</li>
4949 * <li>_someFieldName ---&gt; _SomeFieldName</li>
6060 * field name is capitalized when serialized to its JSON form and the words will be
6161 * separated by a space.
6262 *
63 * <p>Here's a few examples of the form "Java Field Name" ---&gt; "JSON Field Name":</p>
63 * <p>Here are a few examples of the form "Java Field Name" ---&gt; "JSON Field Name":</p>
6464 * <ul>
6565 * <li>someFieldName ---&gt; Some Field Name</li>
6666 * <li>_someFieldName ---&gt; _Some Field Name</li>
7070 */
7171 UPPER_CAMEL_CASE_WITH_SPACES() {
7272 @Override public String translateName(Field f) {
73 return upperCaseFirstLetter(separateCamelCase(f.getName(), " "));
73 return upperCaseFirstLetter(separateCamelCase(f.getName(), ' '));
74 }
75 },
76
77 /**
78 * Using this naming policy with Gson will modify the Java Field name from its camel cased
79 * form to an upper case field name where each word is separated by an underscore (_).
80 *
81 * <p>Here are a few examples of the form "Java Field Name" ---&gt; "JSON Field Name":</p>
82 * <ul>
83 * <li>someFieldName ---&gt; SOME_FIELD_NAME</li>
84 * <li>_someFieldName ---&gt; _SOME_FIELD_NAME</li>
85 * <li>aStringField ---&gt; A_STRING_FIELD</li>
86 * <li>aURL ---&gt; A_U_R_L</li>
87 * </ul>
88 */
89 UPPER_CASE_WITH_UNDERSCORES() {
90 @Override public String translateName(Field f) {
91 return separateCamelCase(f.getName(), '_').toUpperCase(Locale.ENGLISH);
7492 }
7593 },
7694
7896 * Using this naming policy with Gson will modify the Java Field name from its camel cased
7997 * form to a lower case field name where each word is separated by an underscore (_).
8098 *
81 * <p>Here's a few examples of the form "Java Field Name" ---&gt; "JSON Field Name":</p>
99 * <p>Here are a few examples of the form "Java Field Name" ---&gt; "JSON Field Name":</p>
82100 * <ul>
83101 * <li>someFieldName ---&gt; some_field_name</li>
84102 * <li>_someFieldName ---&gt; _some_field_name</li>
88106 */
89107 LOWER_CASE_WITH_UNDERSCORES() {
90108 @Override public String translateName(Field f) {
91 return separateCamelCase(f.getName(), "_").toLowerCase(Locale.ENGLISH);
109 return separateCamelCase(f.getName(), '_').toLowerCase(Locale.ENGLISH);
92110 }
93111 },
94112
96114 * Using this naming policy with Gson will modify the Java Field name from its camel cased
97115 * form to a lower case field name where each word is separated by a dash (-).
98116 *
99 * <p>Here's a few examples of the form "Java Field Name" ---&gt; "JSON Field Name":</p>
117 * <p>Here are a few examples of the form "Java Field Name" ---&gt; "JSON Field Name":</p>
100118 * <ul>
101119 * <li>someFieldName ---&gt; some-field-name</li>
102120 * <li>_someFieldName ---&gt; _some-field-name</li>
111129 */
112130 LOWER_CASE_WITH_DASHES() {
113131 @Override public String translateName(Field f) {
114 return separateCamelCase(f.getName(), "-").toLowerCase(Locale.ENGLISH);
132 return separateCamelCase(f.getName(), '-').toLowerCase(Locale.ENGLISH);
115133 }
116134 },
117135
119137 * Using this naming policy with Gson will modify the Java Field name from its camel cased
120138 * form to a lower case field name where each word is separated by a dot (.).
121139 *
122 * <p>Here's a few examples of the form "Java Field Name" ---&gt; "JSON Field Name":</p>
140 * <p>Here are a few examples of the form "Java Field Name" ---&gt; "JSON Field Name":</p>
123141 * <ul>
124142 * <li>someFieldName ---&gt; some.field.name</li>
125143 * <li>_someFieldName ---&gt; _some.field.name</li>
134152 */
135153 LOWER_CASE_WITH_DOTS() {
136154 @Override public String translateName(Field f) {
137 return separateCamelCase(f.getName(), ".").toLowerCase(Locale.ENGLISH);
155 return separateCamelCase(f.getName(), '.').toLowerCase(Locale.ENGLISH);
138156 }
139157 };
140158
141159 /**
142160 * Converts the field name that uses camel-case define word separation into
143 * separate words that are separated by the provided {@code separatorString}.
144 */
145 static String separateCamelCase(String name, String separator) {
161 * separate words that are separated by the provided {@code separator}.
162 */
163 static String separateCamelCase(String name, char separator) {
146164 StringBuilder translation = new StringBuilder();
147165 for (int i = 0, length = name.length(); i < length; i++) {
148166 char character = name.charAt(i);
157175 /**
158176 * Ensures the JSON field names begins with an upper case letter.
159177 */
160 static String upperCaseFirstLetter(String name) {
161 int firstLetterIndex = 0;
162 int limit = name.length() - 1;
163 for(; !Character.isLetter(name.charAt(firstLetterIndex)) && firstLetterIndex < limit; ++firstLetterIndex);
164
165 char firstLetter = name.charAt(firstLetterIndex);
166 if(Character.isUpperCase(firstLetter)) { //The letter is already uppercased, return the original
167 return name;
168 }
169
170 char uppercased = Character.toUpperCase(firstLetter);
171 if(firstLetterIndex == 0) { //First character in the string is the first letter, saves 1 substring
172 return uppercased + name.substring(1);
173 }
174
175 return name.substring(0, firstLetterIndex) + uppercased + name.substring(firstLetterIndex + 1);
178 static String upperCaseFirstLetter(String s) {
179 int length = s.length();
180 for (int i = 0; i < length; i++) {
181 char c = s.charAt(i);
182 if (Character.isLetter(c)) {
183 if (Character.isUpperCase(c)) {
184 return s;
185 }
186
187 char uppercased = Character.toUpperCase(c);
188 // For leading letter only need one substring
189 if (i == 0) {
190 return uppercased + s.substring(1);
191 } else {
192 return s.substring(0, i) + uppercased + s.substring(i + 1);
193 }
194 }
195 }
196
197 return s;
176198 }
177199 }
3737 import com.google.gson.internal.ConstructorConstructor;
3838 import com.google.gson.internal.Excluder;
3939 import com.google.gson.internal.GsonBuildConfig;
40 import com.google.gson.internal.LazilyParsedNumber;
4041 import com.google.gson.internal.Primitives;
4142 import com.google.gson.internal.Streams;
4243 import com.google.gson.internal.bind.ArrayTypeAdapter;
4647 import com.google.gson.internal.bind.JsonTreeReader;
4748 import com.google.gson.internal.bind.JsonTreeWriter;
4849 import com.google.gson.internal.bind.MapTypeAdapterFactory;
50 import com.google.gson.internal.bind.NumberTypeAdapter;
4951 import com.google.gson.internal.bind.ObjectTypeAdapter;
5052 import com.google.gson.internal.bind.ReflectiveTypeAdapterFactory;
51 import com.google.gson.internal.bind.SqlDateTypeAdapter;
52 import com.google.gson.internal.bind.TimeTypeAdapter;
5353 import com.google.gson.internal.bind.TypeAdapters;
54 import com.google.gson.internal.sql.SqlTypesSupport;
5455 import com.google.gson.reflect.TypeToken;
5556 import com.google.gson.stream.JsonReader;
5657 import com.google.gson.stream.JsonToken;
7576 * MyType target = new MyType();
7677 * String json = gson.toJson(target); // serializes target to Json
7778 * MyType target2 = gson.fromJson(json, MyType.class); // deserializes json into target2
78 * </pre></p>
79 * </pre>
7980 *
8081 * <p>If the object that your are serializing/deserializing is a {@code ParameterizedType}
8182 * (i.e. contains at least one type parameter and may be an array) then you must use the
9091 * Gson gson = new Gson();
9192 * String json = gson.toJson(target, listType);
9293 * List&lt;String&gt; target2 = gson.fromJson(json, listType);
93 * </pre></p>
94 * </pre>
9495 *
9596 * <p>See the <a href="https://sites.google.com/site/gson/gson-user-guide">Gson User Guide</a>
9697 * for a more complete set of examples.</p>
109110 static final boolean DEFAULT_SERIALIZE_NULLS = false;
110111 static final boolean DEFAULT_COMPLEX_MAP_KEYS = false;
111112 static final boolean DEFAULT_SPECIALIZE_FLOAT_VALUES = false;
113 static final boolean DEFAULT_USE_JDK_UNSAFE = true;
114 static final String DEFAULT_DATE_PATTERN = null;
115 static final FieldNamingStrategy DEFAULT_FIELD_NAMING_STRATEGY = FieldNamingPolicy.IDENTITY;
116 static final ToNumberStrategy DEFAULT_OBJECT_TO_NUMBER_STRATEGY = ToNumberPolicy.DOUBLE;
117 static final ToNumberStrategy DEFAULT_NUMBER_TO_NUMBER_STRATEGY = ToNumberPolicy.LAZILY_PARSED_NUMBER;
112118
113119 private static final TypeToken<?> NULL_KEY_SURROGATE = TypeToken.get(Object.class);
114120 private static final String JSON_NON_EXECUTABLE_PREFIX = ")]}'\n";
140146 final boolean prettyPrinting;
141147 final boolean lenient;
142148 final boolean serializeSpecialFloatingPointValues;
149 final boolean useJdkUnsafe;
143150 final String datePattern;
144151 final int dateStyle;
145152 final int timeStyle;
146153 final LongSerializationPolicy longSerializationPolicy;
147154 final List<TypeAdapterFactory> builderFactories;
148155 final List<TypeAdapterFactory> builderHierarchyFactories;
156 final ToNumberStrategy objectToNumberStrategy;
157 final ToNumberStrategy numberToNumberStrategy;
149158
150159 /**
151160 * Constructs a Gson object with default configuration. The default configuration has the
182191 * </ul>
183192 */
184193 public Gson() {
185 this(Excluder.DEFAULT, FieldNamingPolicy.IDENTITY,
194 this(Excluder.DEFAULT, DEFAULT_FIELD_NAMING_STRATEGY,
186195 Collections.<Type, InstanceCreator<?>>emptyMap(), DEFAULT_SERIALIZE_NULLS,
187196 DEFAULT_COMPLEX_MAP_KEYS, DEFAULT_JSON_NON_EXECUTABLE, DEFAULT_ESCAPE_HTML,
188197 DEFAULT_PRETTY_PRINT, DEFAULT_LENIENT, DEFAULT_SPECIALIZE_FLOAT_VALUES,
189 LongSerializationPolicy.DEFAULT, null, DateFormat.DEFAULT, DateFormat.DEFAULT,
198 DEFAULT_USE_JDK_UNSAFE,
199 LongSerializationPolicy.DEFAULT, DEFAULT_DATE_PATTERN, DateFormat.DEFAULT, DateFormat.DEFAULT,
190200 Collections.<TypeAdapterFactory>emptyList(), Collections.<TypeAdapterFactory>emptyList(),
191 Collections.<TypeAdapterFactory>emptyList());
201 Collections.<TypeAdapterFactory>emptyList(), DEFAULT_OBJECT_TO_NUMBER_STRATEGY, DEFAULT_NUMBER_TO_NUMBER_STRATEGY);
192202 }
193203
194204 Gson(Excluder excluder, FieldNamingStrategy fieldNamingStrategy,
195205 Map<Type, InstanceCreator<?>> instanceCreators, boolean serializeNulls,
196206 boolean complexMapKeySerialization, boolean generateNonExecutableGson, boolean htmlSafe,
197207 boolean prettyPrinting, boolean lenient, boolean serializeSpecialFloatingPointValues,
208 boolean useJdkUnsafe,
198209 LongSerializationPolicy longSerializationPolicy, String datePattern, int dateStyle,
199210 int timeStyle, List<TypeAdapterFactory> builderFactories,
200211 List<TypeAdapterFactory> builderHierarchyFactories,
201 List<TypeAdapterFactory> factoriesToBeAdded) {
212 List<TypeAdapterFactory> factoriesToBeAdded,
213 ToNumberStrategy objectToNumberStrategy, ToNumberStrategy numberToNumberStrategy) {
202214 this.excluder = excluder;
203215 this.fieldNamingStrategy = fieldNamingStrategy;
204216 this.instanceCreators = instanceCreators;
205 this.constructorConstructor = new ConstructorConstructor(instanceCreators);
217 this.constructorConstructor = new ConstructorConstructor(instanceCreators, useJdkUnsafe);
206218 this.serializeNulls = serializeNulls;
207219 this.complexMapKeySerialization = complexMapKeySerialization;
208220 this.generateNonExecutableJson = generateNonExecutableGson;
210222 this.prettyPrinting = prettyPrinting;
211223 this.lenient = lenient;
212224 this.serializeSpecialFloatingPointValues = serializeSpecialFloatingPointValues;
225 this.useJdkUnsafe = useJdkUnsafe;
213226 this.longSerializationPolicy = longSerializationPolicy;
214227 this.datePattern = datePattern;
215228 this.dateStyle = dateStyle;
216229 this.timeStyle = timeStyle;
217230 this.builderFactories = builderFactories;
218231 this.builderHierarchyFactories = builderHierarchyFactories;
232 this.objectToNumberStrategy = objectToNumberStrategy;
233 this.numberToNumberStrategy = numberToNumberStrategy;
219234
220235 List<TypeAdapterFactory> factories = new ArrayList<TypeAdapterFactory>();
221236
222237 // built-in type adapters that cannot be overridden
223238 factories.add(TypeAdapters.JSON_ELEMENT_FACTORY);
224 factories.add(ObjectTypeAdapter.FACTORY);
239 factories.add(ObjectTypeAdapter.getFactory(objectToNumberStrategy));
225240
226241 // the excluder must precede all adapters that handle user-defined types
227242 factories.add(excluder);
241256 doubleAdapter(serializeSpecialFloatingPointValues)));
242257 factories.add(TypeAdapters.newFactory(float.class, Float.class,
243258 floatAdapter(serializeSpecialFloatingPointValues)));
244 factories.add(TypeAdapters.NUMBER_FACTORY);
259 factories.add(NumberTypeAdapter.getFactory(numberToNumberStrategy));
245260 factories.add(TypeAdapters.ATOMIC_INTEGER_FACTORY);
246261 factories.add(TypeAdapters.ATOMIC_BOOLEAN_FACTORY);
247262 factories.add(TypeAdapters.newFactory(AtomicLong.class, atomicLongAdapter(longAdapter)));
252267 factories.add(TypeAdapters.STRING_BUFFER_FACTORY);
253268 factories.add(TypeAdapters.newFactory(BigDecimal.class, TypeAdapters.BIG_DECIMAL));
254269 factories.add(TypeAdapters.newFactory(BigInteger.class, TypeAdapters.BIG_INTEGER));
270 // Add adapter for LazilyParsedNumber because user can obtain it from Gson and then try to serialize it again
271 factories.add(TypeAdapters.newFactory(LazilyParsedNumber.class, TypeAdapters.LAZILY_PARSED_NUMBER));
255272 factories.add(TypeAdapters.URL_FACTORY);
256273 factories.add(TypeAdapters.URI_FACTORY);
257274 factories.add(TypeAdapters.UUID_FACTORY);
261278 factories.add(TypeAdapters.BIT_SET_FACTORY);
262279 factories.add(DateTypeAdapter.FACTORY);
263280 factories.add(TypeAdapters.CALENDAR_FACTORY);
264 factories.add(TimeTypeAdapter.FACTORY);
265 factories.add(SqlDateTypeAdapter.FACTORY);
266 factories.add(TypeAdapters.TIMESTAMP_FACTORY);
281
282 if (SqlTypesSupport.SUPPORTS_SQL_TYPES) {
283 factories.add(SqlTypesSupport.TIME_FACTORY);
284 factories.add(SqlTypesSupport.DATE_FACTORY);
285 factories.add(SqlTypesSupport.TIMESTAMP_FACTORY);
286 }
287
267288 factories.add(ArrayTypeAdapter.FACTORY);
268289 factories.add(TypeAdapters.CLASS_FACTORY);
269290
289310 return new GsonBuilder(this);
290311 }
291312
313 /**
314 * @deprecated This method by accident exposes an internal Gson class; it might be removed in a
315 * future version.
316 */
317 @Deprecated
292318 public Excluder excluder() {
293319 return excluder;
294320 }
295321
322 /**
323 * Returns the field naming strategy used by this Gson instance.
324 *
325 * @see GsonBuilder#setFieldNamingStrategy(FieldNamingStrategy)
326 */
296327 public FieldNamingStrategy fieldNamingStrategy() {
297328 return fieldNamingStrategy;
298329 }
299330
331 /**
332 * Returns whether this Gson instance is serializing JSON object properties with
333 * {@code null} values, or just omits them.
334 *
335 * @see GsonBuilder#serializeNulls()
336 */
300337 public boolean serializeNulls() {
301338 return serializeNulls;
302339 }
303340
341 /**
342 * Returns whether this Gson instance produces JSON output which is
343 * HTML-safe, that means all HTML characters are escaped.
344 *
345 * @see GsonBuilder#disableHtmlEscaping()
346 */
304347 public boolean htmlSafe() {
305348 return htmlSafe;
306349 }
516559 * read or written.
517560 * @param skipPast The type adapter factory that needs to be skipped while searching for
518561 * a matching type adapter. In most cases, you should just pass <i>this</i> (the type adapter
519 * factory from where {@link #getDelegateAdapter} method is being invoked).
562 * factory from where {@code getDelegateAdapter} method is being invoked).
520563 * @param type Type for which the delegate adapter is being searched for.
521564 *
522565 * @since 2.2
746789
747790 /**
748791 * Returns a new JSON writer configured for the settings on this Gson instance.
792 *
793 * <p>The following settings are considered:
794 * <ul>
795 * <li>{@link GsonBuilder#disableHtmlEscaping()}</li>
796 * <li>{@link GsonBuilder#generateNonExecutableJson()}</li>
797 * <li>{@link GsonBuilder#serializeNulls()}</li>
798 * <li>{@link GsonBuilder#setLenient()}</li>
799 * <li>{@link GsonBuilder#setPrettyPrinting()}</li>
800 * </ul>
749801 */
750802 public JsonWriter newJsonWriter(Writer writer) throws IOException {
751803 if (generateNonExecutableJson) {
755807 if (prettyPrinting) {
756808 jsonWriter.setIndent(" ");
757809 }
810 jsonWriter.setHtmlSafe(htmlSafe);
811 jsonWriter.setLenient(lenient);
758812 jsonWriter.setSerializeNulls(serializeNulls);
759813 return jsonWriter;
760814 }
761815
762816 /**
763817 * Returns a new JSON reader configured for the settings on this Gson instance.
818 *
819 * <p>The following settings are considered:
820 * <ul>
821 * <li>{@link GsonBuilder#setLenient()}</li>
822 * </ul>
764823 */
765824 public JsonReader newJsonReader(Reader reader) {
766825 JsonReader jsonReader = new JsonReader(reader);
1616 package com.google.gson;
1717
1818 import java.lang.reflect.Type;
19 import java.sql.Timestamp;
2019 import java.text.DateFormat;
2120 import java.util.ArrayList;
2221 import java.util.Collections;
2726
2827 import com.google.gson.internal.$Gson$Preconditions;
2928 import com.google.gson.internal.Excluder;
29 import com.google.gson.internal.bind.DefaultDateTypeAdapter;
3030 import com.google.gson.internal.bind.TreeTypeAdapter;
3131 import com.google.gson.internal.bind.TypeAdapters;
32 import com.google.gson.internal.sql.SqlTypesSupport;
3233 import com.google.gson.reflect.TypeToken;
3334 import com.google.gson.stream.JsonReader;
3435
3536 import static com.google.gson.Gson.DEFAULT_COMPLEX_MAP_KEYS;
37 import static com.google.gson.Gson.DEFAULT_DATE_PATTERN;
3638 import static com.google.gson.Gson.DEFAULT_ESCAPE_HTML;
3739 import static com.google.gson.Gson.DEFAULT_JSON_NON_EXECUTABLE;
3840 import static com.google.gson.Gson.DEFAULT_LENIENT;
41 import static com.google.gson.Gson.DEFAULT_NUMBER_TO_NUMBER_STRATEGY;
42 import static com.google.gson.Gson.DEFAULT_OBJECT_TO_NUMBER_STRATEGY;
3943 import static com.google.gson.Gson.DEFAULT_PRETTY_PRINT;
4044 import static com.google.gson.Gson.DEFAULT_SERIALIZE_NULLS;
4145 import static com.google.gson.Gson.DEFAULT_SPECIALIZE_FLOAT_VALUES;
46 import static com.google.gson.Gson.DEFAULT_USE_JDK_UNSAFE;
4247
4348 /**
4449 * <p>Use this builder to construct a {@link Gson} instance when you need to set configuration
5964 * .setPrettyPrinting()
6065 * .setVersion(1.0)
6166 * .create();
62 * </pre></p>
67 * </pre>
6368 *
6469 * <p>NOTES:
6570 * <ul>
6772 * <li> The default serialization of {@link Date} and its subclasses in Gson does
6873 * not contain time-zone information. So, if you are using date/time instances,
6974 * use {@code GsonBuilder} and its {@code setDateFormat} methods.</li>
70 * </ul>
71 * </p>
75 * </ul>
7276 *
7377 * @author Inderjeet Singh
7478 * @author Joel Leitch
8488 /** tree-style hierarchy factories. These come after factories for backwards compatibility. */
8589 private final List<TypeAdapterFactory> hierarchyFactories = new ArrayList<TypeAdapterFactory>();
8690 private boolean serializeNulls = DEFAULT_SERIALIZE_NULLS;
87 private String datePattern;
91 private String datePattern = DEFAULT_DATE_PATTERN;
8892 private int dateStyle = DateFormat.DEFAULT;
8993 private int timeStyle = DateFormat.DEFAULT;
9094 private boolean complexMapKeySerialization = DEFAULT_COMPLEX_MAP_KEYS;
9397 private boolean prettyPrinting = DEFAULT_PRETTY_PRINT;
9498 private boolean generateNonExecutableJson = DEFAULT_JSON_NON_EXECUTABLE;
9599 private boolean lenient = DEFAULT_LENIENT;
100 private boolean useJdkUnsafe = DEFAULT_USE_JDK_UNSAFE;
101 private ToNumberStrategy objectToNumberStrategy = DEFAULT_OBJECT_TO_NUMBER_STRATEGY;
102 private ToNumberStrategy numberToNumberStrategy = DEFAULT_NUMBER_TO_NUMBER_STRATEGY;
96103
97104 /**
98105 * Creates a GsonBuilder instance that can be used to build Gson with various configuration
126133 this.timeStyle = gson.timeStyle;
127134 this.factories.addAll(gson.builderFactories);
128135 this.hierarchyFactories.addAll(gson.builderHierarchyFactories);
136 this.useJdkUnsafe = gson.useJdkUnsafe;
137 this.objectToNumberStrategy = gson.objectToNumberStrategy;
138 this.numberToNumberStrategy = gson.numberToNumberStrategy;
129139 }
130140
131141 /**
245255 * original.put(new Point(8, 8), "b");
246256 * System.out.println(gson.toJson(original, type));
247257 * }
258 * </pre>
248259 *
249260 * The JSON output would look as follows:
250261 * <pre> {@code
325336 }
326337
327338 /**
339 * Configures Gson to apply a specific number strategy during deserialization of {@link Object}.
340 *
341 * @param objectToNumberStrategy the actual object-to-number strategy
342 * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
343 * @see ToNumberPolicy#DOUBLE The default object-to-number strategy
344 */
345 public GsonBuilder setObjectToNumberStrategy(ToNumberStrategy objectToNumberStrategy) {
346 this.objectToNumberStrategy = objectToNumberStrategy;
347 return this;
348 }
349
350 /**
351 * Configures Gson to apply a specific number strategy during deserialization of {@link Number}.
352 *
353 * @param numberToNumberStrategy the actual number-to-number strategy
354 * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
355 * @see ToNumberPolicy#LAZILY_PARSED_NUMBER The default number-to-number strategy
356 */
357 public GsonBuilder setNumberToNumberStrategy(ToNumberStrategy numberToNumberStrategy) {
358 this.numberToNumberStrategy = numberToNumberStrategy;
359 return this;
360 }
361
362 /**
328363 * Configures Gson to apply a set of exclusion strategies during both serialization and
329364 * deserialization. Each of the {@code strategies} will be applied as a disjunction rule.
330365 * This means that if one of the {@code strategies} suggests that a field (or class) should be
416451 * call this method or {@link #setDateFormat(int)} multiple times, but only the last invocation
417452 * will be used to decide the serialization format.
418453 *
419 * <p>The date format will be used to serialize and deserialize {@link java.util.Date}, {@link
420 * java.sql.Timestamp} and {@link java.sql.Date}.
454 * <p>The date format will be used to serialize and deserialize {@link java.util.Date} and in case
455 * the {@code java.sql} module is present, also {@link java.sql.Timestamp} and {@link java.sql.Date}.
421456 *
422457 * <p>Note that this pattern must abide by the convention provided by {@code SimpleDateFormat}
423458 * class. See the documentation in {@link java.text.SimpleDateFormat} for more information on
577612 }
578613
579614 /**
615 * Disables usage of JDK's {@code sun.misc.Unsafe}.
616 *
617 * <p>By default Gson uses {@code Unsafe} to create instances of classes which don't have
618 * a no-args constructor. However, {@code Unsafe} might not be available for all Java
619 * runtimes. For example Android does not provide {@code Unsafe}, or only with limited
620 * functionality. Additionally {@code Unsafe} creates instances without executing any
621 * constructor or initializer block, or performing initialization of field values. This can
622 * lead to surprising and difficult to debug errors.
623 * Therefore, to get reliable behavior regardless of which runtime is used, and to detect
624 * classes which cannot be deserialized in an early stage of development, this method allows
625 * disabling usage of {@code Unsafe}.
626 *
627 * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
628 */
629 public GsonBuilder disableJdkUnsafe() {
630 this.useJdkUnsafe = false;
631 return this;
632 }
633
634 /**
580635 * Creates a {@link Gson} instance based on the current configuration. This method is free of
581636 * side-effects to this {@code GsonBuilder} instance and hence can be called multiple times.
582637 *
596651 return new Gson(excluder, fieldNamingPolicy, instanceCreators,
597652 serializeNulls, complexMapKeySerialization,
598653 generateNonExecutableJson, escapeHtmlChars, prettyPrinting, lenient,
599 serializeSpecialFloatingPointValues, longSerializationPolicy,
654 serializeSpecialFloatingPointValues, useJdkUnsafe, longSerializationPolicy,
600655 datePattern, dateStyle, timeStyle,
601 this.factories, this.hierarchyFactories, factories);
602 }
603
604 @SuppressWarnings("unchecked")
656 this.factories, this.hierarchyFactories, factories, objectToNumberStrategy, numberToNumberStrategy);
657 }
658
605659 private void addTypeAdaptersForDate(String datePattern, int dateStyle, int timeStyle,
606660 List<TypeAdapterFactory> factories) {
607 DefaultDateTypeAdapter dateTypeAdapter;
608 TypeAdapter<Timestamp> timestampTypeAdapter;
609 TypeAdapter<java.sql.Date> javaSqlDateTypeAdapter;
610 if (datePattern != null && !"".equals(datePattern.trim())) {
611 dateTypeAdapter = new DefaultDateTypeAdapter(Date.class, datePattern);
612 timestampTypeAdapter = (TypeAdapter) new DefaultDateTypeAdapter(Timestamp.class, datePattern);
613 javaSqlDateTypeAdapter = (TypeAdapter) new DefaultDateTypeAdapter(java.sql.Date.class, datePattern);
661 TypeAdapterFactory dateAdapterFactory;
662 boolean sqlTypesSupported = SqlTypesSupport.SUPPORTS_SQL_TYPES;
663 TypeAdapterFactory sqlTimestampAdapterFactory = null;
664 TypeAdapterFactory sqlDateAdapterFactory = null;
665
666 if (datePattern != null && !datePattern.trim().isEmpty()) {
667 dateAdapterFactory = DefaultDateTypeAdapter.DateType.DATE.createAdapterFactory(datePattern);
668
669 if (sqlTypesSupported) {
670 sqlTimestampAdapterFactory = SqlTypesSupport.TIMESTAMP_DATE_TYPE.createAdapterFactory(datePattern);
671 sqlDateAdapterFactory = SqlTypesSupport.DATE_DATE_TYPE.createAdapterFactory(datePattern);
672 }
614673 } else if (dateStyle != DateFormat.DEFAULT && timeStyle != DateFormat.DEFAULT) {
615 dateTypeAdapter = new DefaultDateTypeAdapter(Date.class, dateStyle, timeStyle);
616 timestampTypeAdapter = (TypeAdapter) new DefaultDateTypeAdapter(Timestamp.class, dateStyle, timeStyle);
617 javaSqlDateTypeAdapter = (TypeAdapter) new DefaultDateTypeAdapter(java.sql.Date.class, dateStyle, timeStyle);
674 dateAdapterFactory = DefaultDateTypeAdapter.DateType.DATE.createAdapterFactory(dateStyle, timeStyle);
675
676 if (sqlTypesSupported) {
677 sqlTimestampAdapterFactory = SqlTypesSupport.TIMESTAMP_DATE_TYPE.createAdapterFactory(dateStyle, timeStyle);
678 sqlDateAdapterFactory = SqlTypesSupport.DATE_DATE_TYPE.createAdapterFactory(dateStyle, timeStyle);
679 }
618680 } else {
619681 return;
620682 }
621683
622 factories.add(TypeAdapters.newFactory(Date.class, dateTypeAdapter));
623 factories.add(TypeAdapters.newFactory(Timestamp.class, timestampTypeAdapter));
624 factories.add(TypeAdapters.newFactory(java.sql.Date.class, javaSqlDateTypeAdapter));
684 factories.add(dateAdapterFactory);
685 if (sqlTypesSupported) {
686 factories.add(sqlTimestampAdapterFactory);
687 factories.add(sqlDateAdapterFactory);
688 }
625689 }
626690 }
343343 @Override
344344 public char getAsCharacter() {
345345 if (elements.size() == 1) {
346 return elements.get(0).getAsCharacter();
346 JsonElement element = elements.get(0);
347 @SuppressWarnings("deprecation")
348 char result = element.getAsCharacter();
349 return result;
347350 }
348351 throw new IllegalStateException();
349352 }
2525 * <p>Let us look at example where defining a serializer will be useful. The {@code Id} class
2626 * defined below has two fields: {@code clazz} and {@code value}.</p>
2727 *
28 * <p><pre>
28 * <pre>
2929 * public class Id&lt;T&gt; {
3030 * private final Class&lt;T&gt; clazz;
3131 * private final long value;
3939 * return value;
4040 * }
4141 * }
42 * </pre></p>
42 * </pre>
4343 *
4444 * <p>The default serialization of {@code Id(com.foo.MyObject.class, 20L)} will be
4545 * <code>{"clazz":com.foo.MyObject,"value":20}</code>. Suppose, you just want the output to be
4646 * the value instead, which is {@code 20} in this case. You can achieve that by writing a custom
4747 * serializer:</p>
4848 *
49 * <p><pre>
49 * <pre>
5050 * class IdSerializer implements JsonSerializer&lt;Id&gt;() {
5151 * public JsonElement serialize(Id id, Type typeOfId, JsonSerializationContext context) {
5252 * return new JsonPrimitive(id.getValue());
5353 * }
5454 * }
55 * </pre></p>
55 * </pre>
5656 *
5757 * <p>You will also need to register {@code IdSerializer} with Gson as follows:</p>
5858 * <pre>
1616 package com.google.gson;
1717
1818 /**
19 * Defines the expected format for a {@code long} or {@code Long} type when its serialized.
19 * Defines the expected format for a {@code long} or {@code Long} type when it is serialized.
2020 *
2121 * @since 1.3
2222 *
2525 */
2626 public enum LongSerializationPolicy {
2727 /**
28 * This is the "default" serialization policy that will output a {@code long} object as a JSON
28 * This is the "default" serialization policy that will output a {@code Long} object as a JSON
2929 * number. For example, assume an object has a long field named "f" then the serialized output
3030 * would be:
31 * {@code {"f":123}}.
31 * {@code {"f":123}}
32 *
33 * <p>A {@code null} value is serialized as {@link JsonNull}.
3234 */
3335 DEFAULT() {
3436 @Override public JsonElement serialize(Long value) {
37 if (value == null) {
38 return JsonNull.INSTANCE;
39 }
3540 return new JsonPrimitive(value);
3641 }
3742 },
3944 /**
4045 * Serializes a long value as a quoted string. For example, assume an object has a long field
4146 * named "f" then the serialized output would be:
42 * {@code {"f":"123"}}.
47 * {@code {"f":"123"}}
48 *
49 * <p>A {@code null} value is serialized as {@link JsonNull}.
4350 */
4451 STRING() {
4552 @Override public JsonElement serialize(Long value) {
46 return new JsonPrimitive(String.valueOf(value));
53 if (value == null) {
54 return JsonNull.INSTANCE;
55 }
56 return new JsonPrimitive(value.toString());
4757 }
4858 };
4959
0 /*
1 * Copyright (C) 2021 Google Inc.
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 package com.google.gson;
17
18 import java.io.IOException;
19 import java.math.BigDecimal;
20
21 import com.google.gson.internal.LazilyParsedNumber;
22 import com.google.gson.stream.JsonReader;
23 import com.google.gson.stream.MalformedJsonException;
24
25 /**
26 * An enumeration that defines two standard number reading strategies and a couple of
27 * strategies to overcome some historical Gson limitations while deserializing numbers as
28 * {@link Object} and {@link Number}.
29 *
30 * @see ToNumberStrategy
31 */
32 public enum ToNumberPolicy implements ToNumberStrategy {
33
34 /**
35 * Using this policy will ensure that numbers will be read as {@link Double} values.
36 * This is the default strategy used during deserialization of numbers as {@link Object}.
37 */
38 DOUBLE {
39 @Override public Double readNumber(JsonReader in) throws IOException {
40 return in.nextDouble();
41 }
42 },
43
44 /**
45 * Using this policy will ensure that numbers will be read as a lazily parsed number backed
46 * by a string. This is the default strategy used during deserialization of numbers as
47 * {@link Number}.
48 */
49 LAZILY_PARSED_NUMBER {
50 @Override public Number readNumber(JsonReader in) throws IOException {
51 return new LazilyParsedNumber(in.nextString());
52 }
53 },
54
55 /**
56 * Using this policy will ensure that numbers will be read as {@link Long} or {@link Double}
57 * values depending on how JSON numbers are represented: {@code Long} if the JSON number can
58 * be parsed as a {@code Long} value, or otherwise {@code Double} if it can be parsed as a
59 * {@code Double} value. If the parsed double-precision number results in a positive or negative
60 * infinity ({@link Double#isInfinite()}) or a NaN ({@link Double#isNaN()}) value and the
61 * {@code JsonReader} is not {@link JsonReader#isLenient() lenient}, a {@link MalformedJsonException}
62 * is thrown.
63 */
64 LONG_OR_DOUBLE {
65 @Override public Number readNumber(JsonReader in) throws IOException, JsonParseException {
66 String value = in.nextString();
67 try {
68 return Long.parseLong(value);
69 } catch (NumberFormatException longE) {
70 try {
71 Double d = Double.valueOf(value);
72 if ((d.isInfinite() || d.isNaN()) && !in.isLenient()) {
73 throw new MalformedJsonException("JSON forbids NaN and infinities: " + d + "; at path " + in.getPreviousPath());
74 }
75 return d;
76 } catch (NumberFormatException doubleE) {
77 throw new JsonParseException("Cannot parse " + value + "; at path " + in.getPreviousPath(), doubleE);
78 }
79 }
80 }
81 },
82
83 /**
84 * Using this policy will ensure that numbers will be read as numbers of arbitrary length
85 * using {@link BigDecimal}.
86 */
87 BIG_DECIMAL {
88 @Override public BigDecimal readNumber(JsonReader in) throws IOException {
89 String value = in.nextString();
90 try {
91 return new BigDecimal(value);
92 } catch (NumberFormatException e) {
93 throw new JsonParseException("Cannot parse " + value + "; at path " + in.getPreviousPath(), e);
94 }
95 }
96 }
97
98 }
0 /*
1 * Copyright (C) 2021 Google Inc.
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 package com.google.gson;
17
18 import java.io.IOException;
19
20 import com.google.gson.stream.JsonReader;
21
22 /**
23 * A strategy that is used to control how numbers should be deserialized for {@link Object} and {@link Number}
24 * when a concrete type of the deserialized number is unknown in advance. By default, Gson uses the following
25 * deserialization strategies:
26 *
27 * <ul>
28 * <li>{@link Double} values are returned for JSON numbers if the deserialization type is declared as
29 * {@code Object}, see {@link ToNumberPolicy#DOUBLE};</li>
30 * <li>Lazily parsed number values are returned if the deserialization type is declared as {@code Number},
31 * see {@link ToNumberPolicy#LAZILY_PARSED_NUMBER}.</li>
32 * </ul>
33 *
34 * <p>For historical reasons, Gson does not support deserialization of arbitrary-length numbers for
35 * {@code Object} and {@code Number} by default, potentially causing precision loss. However,
36 * <a href="https://tools.ietf.org/html/rfc8259#section-6">RFC 8259</a> permits this:
37 *
38 * <pre>
39 * This specification allows implementations to set limits on the range
40 * and precision of numbers accepted. Since software that implements
41 * IEEE 754 binary64 (double precision) numbers [IEEE754] is generally
42 * available and widely used, good interoperability can be achieved by
43 * implementations that expect no more precision or range than these
44 * provide, in the sense that implementations will approximate JSON
45 * numbers within the expected precision. A JSON number such as 1E400
46 * or 3.141592653589793238462643383279 may indicate potential
47 * interoperability problems, since it suggests that the software that
48 * created it expects receiving software to have greater capabilities
49 * for numeric magnitude and precision than is widely available.
50 * </pre>
51 *
52 * <p>To overcome the precision loss, use for example {@link ToNumberPolicy#LONG_OR_DOUBLE} or
53 * {@link ToNumberPolicy#BIG_DECIMAL}.</p>
54 *
55 * @see ToNumberPolicy
56 * @see GsonBuilder#setObjectToNumberStrategy(ToNumberStrategy)
57 * @see GsonBuilder#setNumberToNumberStrategy(ToNumberStrategy)
58 */
59 public interface ToNumberStrategy {
60
61 /**
62 * Reads a number from the given JSON reader. A strategy is supposed to read a single value from the
63 * reader, and the read value is guaranteed never to be {@code null}.
64 *
65 * @param in JSON reader to read a number from
66 * @return number read from the JSON reader.
67 */
68 public Number readNumber(JsonReader in) throws IOException;
69 }
3131 * method.</p>
3232 *
3333 * <p>Here is an example of how this annotation is meant to be used:
34 * <p><pre>
34 * <pre>
3535 * public class User {
3636 * &#64;Expose private String firstName;
3737 * &#64;Expose(serialize = false) private String lastName;
3838 * &#64;Expose (serialize = false, deserialize = false) private String emailAddress;
3939 * private String password;
4040 * }
41 * </pre></p>
41 * </pre>
4242 * If you created Gson with {@code new Gson()}, the {@code toJson()} and {@code fromJson()}
4343 * methods will use the {@code password} field along-with {@code firstName}, {@code lastName},
4444 * and {@code emailAddress} for serialization and deserialization. However, if you created Gson
338338 }
339339
340340 public static Type resolve(Type context, Class<?> contextRawType, Type toResolve) {
341
341342 return resolve(context, contextRawType, toResolve, new HashMap<TypeVariable<?>, Type>());
342343 }
343344
572573
573574 /**
574575 * The WildcardType interface supports multiple upper bounds and multiple
575 * lower bounds. We only support what the Java 6 language needs - at most one
576 * bound. If a lower bound is set, the upper bound must be Object.class.
576 * lower bounds. We only support what the target Java version supports - at most one
577 * bound, see also https://bugs.openjdk.java.net/browse/JDK-8250660. If a lower bound
578 * is set, the upper bound must be Object.class.
577579 */
578580 private static final class WildcardTypeImpl implements WildcardType, Serializable {
579581 private final Type upperBound;
1717
1818 import java.lang.reflect.Constructor;
1919 import java.lang.reflect.InvocationTargetException;
20 import java.lang.reflect.Modifier;
2021 import java.lang.reflect.ParameterizedType;
2122 import java.lang.reflect.Type;
2223 import java.util.ArrayDeque;
2324 import java.util.ArrayList;
2425 import java.util.Collection;
26 import java.util.EnumMap;
2527 import java.util.EnumSet;
2628 import java.util.LinkedHashMap;
2729 import java.util.LinkedHashSet;
3941
4042 import com.google.gson.InstanceCreator;
4143 import com.google.gson.JsonIOException;
42 import com.google.gson.internal.reflect.ReflectionAccessor;
44 import com.google.gson.internal.reflect.ReflectionHelper;
4345 import com.google.gson.reflect.TypeToken;
4446
4547 /**
4749 */
4850 public final class ConstructorConstructor {
4951 private final Map<Type, InstanceCreator<?>> instanceCreators;
50 private final ReflectionAccessor accessor = ReflectionAccessor.getInstance();
51
52 public ConstructorConstructor(Map<Type, InstanceCreator<?>> instanceCreators) {
52 private final boolean useJdkUnsafe;
53
54 public ConstructorConstructor(Map<Type, InstanceCreator<?>> instanceCreators, boolean useJdkUnsafe) {
5355 this.instanceCreators = instanceCreators;
56 this.useJdkUnsafe = useJdkUnsafe;
5457 }
5558
5659 public <T> ObjectConstructor<T> get(TypeToken<T> typeToken) {
9295 }
9396
9497 // finally try unsafe
95 return newUnsafeAllocator(type, rawType);
98 return newUnsafeAllocator(rawType);
9699 }
97100
98101 private <T> ObjectConstructor<T> newDefaultConstructor(Class<? super T> rawType) {
102 // Cannot invoke constructor of abstract class
103 if (Modifier.isAbstract(rawType.getModifiers())) {
104 return null;
105 }
106
107 final Constructor<? super T> constructor;
99108 try {
100 final Constructor<? super T> constructor = rawType.getDeclaredConstructor();
101 if (!constructor.isAccessible()) {
102 accessor.makeAccessible(constructor);
103 }
104 return new ObjectConstructor<T>() {
105 @SuppressWarnings("unchecked") // T is the same raw type as is requested
106 @Override public T construct() {
107 try {
108 Object[] args = null;
109 return (T) constructor.newInstance(args);
110 } catch (InstantiationException e) {
111 // TODO: JsonParseException ?
112 throw new RuntimeException("Failed to invoke " + constructor + " with no args", e);
113 } catch (InvocationTargetException e) {
114 // TODO: don't wrap if cause is unchecked!
115 // TODO: JsonParseException ?
116 throw new RuntimeException("Failed to invoke " + constructor + " with no args",
117 e.getTargetException());
118 } catch (IllegalAccessException e) {
119 throw new AssertionError(e);
120 }
121 }
122 };
109 constructor = rawType.getDeclaredConstructor();
123110 } catch (NoSuchMethodException e) {
124111 return null;
125112 }
113
114 final String exceptionMessage = ReflectionHelper.tryMakeAccessible(constructor);
115 if (exceptionMessage != null) {
116 /*
117 * Create ObjectConstructor which throws exception.
118 * This keeps backward compatibility (compared to returning `null` which
119 * would then choose another way of creating object).
120 * And it supports types which are only serialized but not deserialized
121 * (compared to directly throwing exception here), e.g. when runtime type
122 * of object is inaccessible, but compile-time type is accessible.
123 */
124 return new ObjectConstructor<T>() {
125 @Override
126 public T construct() {
127 // New exception is created every time to avoid keeping reference
128 // to exception with potentially long stack trace, causing a
129 // memory leak
130 throw new JsonIOException(exceptionMessage);
131 }
132 };
133 }
134
135 return new ObjectConstructor<T>() {
136 @Override public T construct() {
137 try {
138 @SuppressWarnings("unchecked") // T is the same raw type as is requested
139 T newInstance = (T) constructor.newInstance();
140 return newInstance;
141 } catch (InstantiationException e) {
142 // TODO: JsonParseException ?
143 throw new RuntimeException("Failed to invoke " + constructor + " with no args", e);
144 } catch (InvocationTargetException e) {
145 // TODO: don't wrap if cause is unchecked!
146 // TODO: JsonParseException ?
147 throw new RuntimeException("Failed to invoke " + constructor + " with no args",
148 e.getTargetException());
149 } catch (IllegalAccessException e) {
150 throw new AssertionError(e);
151 }
152 }
153 };
126154 }
127155
128156 /**
177205 }
178206
179207 if (Map.class.isAssignableFrom(rawType)) {
180 if (ConcurrentNavigableMap.class.isAssignableFrom(rawType)) {
208 // Only support creation of EnumMap, but not of custom subtypes; for them type parameters
209 // and constructor parameter might have completely different meaning
210 if (rawType == EnumMap.class) {
211 return new ObjectConstructor<T>() {
212 @Override public T construct() {
213 if (type instanceof ParameterizedType) {
214 Type elementType = ((ParameterizedType) type).getActualTypeArguments()[0];
215 if (elementType instanceof Class) {
216 @SuppressWarnings("rawtypes")
217 T map = (T) new EnumMap((Class) elementType);
218 return map;
219 } else {
220 throw new JsonIOException("Invalid EnumMap type: " + type.toString());
221 }
222 } else {
223 throw new JsonIOException("Invalid EnumMap type: " + type.toString());
224 }
225 }
226 };
227 } else if (ConcurrentNavigableMap.class.isAssignableFrom(rawType)) {
181228 return new ObjectConstructor<T>() {
182229 @Override public T construct() {
183230 return (T) new ConcurrentSkipListMap<Object, Object>();
214261 return null;
215262 }
216263
217 private <T> ObjectConstructor<T> newUnsafeAllocator(
218 final Type type, final Class<? super T> rawType) {
219 return new ObjectConstructor<T>() {
220 private final UnsafeAllocator unsafeAllocator = UnsafeAllocator.create();
221 @SuppressWarnings("unchecked")
222 @Override public T construct() {
223 try {
224 Object newInstance = unsafeAllocator.newInstance(rawType);
225 return (T) newInstance;
226 } catch (Exception e) {
227 throw new RuntimeException(("Unable to invoke no-args constructor for " + type + ". "
228 + "Registering an InstanceCreator with Gson for this type may fix this problem."), e);
229 }
230 }
231 };
264 private <T> ObjectConstructor<T> newUnsafeAllocator(final Class<? super T> rawType) {
265 if (useJdkUnsafe) {
266 return new ObjectConstructor<T>() {
267 private final UnsafeAllocator unsafeAllocator = UnsafeAllocator.create();
268 @Override public T construct() {
269 try {
270 @SuppressWarnings("unchecked")
271 T newInstance = (T) unsafeAllocator.newInstance(rawType);
272 return newInstance;
273 } catch (Exception e) {
274 throw new RuntimeException(("Unable to create instance of " + rawType + ". "
275 + "Registering an InstanceCreator or a TypeAdapter for this type, or adding a no-args "
276 + "constructor may fix this problem."), e);
277 }
278 }
279 };
280 } else {
281 final String exceptionMessage = "Unable to create instance of " + rawType + "; usage of JDK Unsafe "
282 + "is disabled. Registering an InstanceCreator or a TypeAdapter for this type, adding a no-args "
283 + "constructor, or enabling usage of JDK Unsafe may fix this problem.";
284 return new ObjectConstructor<T>() {
285 @Override public T construct() {
286 throw new JsonIOException(exceptionMessage);
287 }
288 };
289 }
232290 }
233291
234292 @Override public String toString() {
172172 return true;
173173 }
174174
175 if (isAnonymousOrLocal(field.getType())) {
175 if (isAnonymousOrNonStaticLocal(field.getType())) {
176176 return true;
177177 }
178178
198198 return true;
199199 }
200200
201 if (isAnonymousOrLocal(clazz)) {
201 if (isAnonymousOrNonStaticLocal(clazz)) {
202202 return true;
203203 }
204204
220220 return false;
221221 }
222222
223 private boolean isAnonymousOrLocal(Class<?> clazz) {
224 return !Enum.class.isAssignableFrom(clazz)
223 private boolean isAnonymousOrNonStaticLocal(Class<?> clazz) {
224 return !Enum.class.isAssignableFrom(clazz) && !isStatic(clazz)
225225 && (clazz.isAnonymousClass() || clazz.isLocalClass());
226226 }
227227
1414 */
1515 package com.google.gson.internal;
1616
17 import java.io.IOException;
18 import java.io.InvalidObjectException;
19 import java.io.ObjectInputStream;
1720 import java.io.ObjectStreamException;
1821 import java.math.BigDecimal;
1922
7679 return new BigDecimal(value);
7780 }
7881
82 private void readObject(ObjectInputStream in) throws IOException {
83 // Don't permit directly deserializing this class; writeReplace() should have written a replacement
84 throw new InvalidObjectException("Deserialization is unsupported");
85 }
86
7987 @Override
8088 public int hashCode() {
8189 return value.hashCode();
+0
-864
gson/src/main/java/com/google/gson/internal/LinkedHashTreeMap.java less more
0 /*
1 * Copyright (C) 2010 The Android Open Source Project
2 * Copyright (C) 2012 Google Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package com.google.gson.internal;
18
19 import java.io.ObjectStreamException;
20 import java.io.Serializable;
21 import java.util.AbstractMap;
22 import java.util.AbstractSet;
23 import java.util.Arrays;
24 import java.util.Comparator;
25 import java.util.ConcurrentModificationException;
26 import java.util.Iterator;
27 import java.util.LinkedHashMap;
28 import java.util.NoSuchElementException;
29 import java.util.Set;
30
31 /**
32 * A map of comparable keys to values. Unlike {@code TreeMap}, this class uses
33 * insertion order for iteration order. Comparison order is only used as an
34 * optimization for efficient insertion and removal.
35 *
36 * <p>This implementation was derived from Android 4.1's TreeMap and
37 * LinkedHashMap classes.
38 */
39 public final class LinkedHashTreeMap<K, V> extends AbstractMap<K, V> implements Serializable {
40 @SuppressWarnings({ "unchecked", "rawtypes" }) // to avoid Comparable<Comparable<Comparable<...>>>
41 private static final Comparator<Comparable> NATURAL_ORDER = new Comparator<Comparable>() {
42 public int compare(Comparable a, Comparable b) {
43 return a.compareTo(b);
44 }
45 };
46
47 Comparator<? super K> comparator;
48 Node<K, V>[] table;
49 final Node<K, V> header;
50 int size = 0;
51 int modCount = 0;
52 int threshold;
53
54 /**
55 * Create a natural order, empty tree map whose keys must be mutually
56 * comparable and non-null.
57 */
58 @SuppressWarnings("unchecked") // unsafe! this assumes K is comparable
59 public LinkedHashTreeMap() {
60 this((Comparator<? super K>) NATURAL_ORDER);
61 }
62
63 /**
64 * Create a tree map ordered by {@code comparator}. This map's keys may only
65 * be null if {@code comparator} permits.
66 *
67 * @param comparator the comparator to order elements with, or {@code null} to
68 * use the natural ordering.
69 */
70 @SuppressWarnings({ "unchecked", "rawtypes" }) // unsafe! if comparator is null, this assumes K is comparable
71 public LinkedHashTreeMap(Comparator<? super K> comparator) {
72 this.comparator = comparator != null
73 ? comparator
74 : (Comparator) NATURAL_ORDER;
75 this.header = new Node<K, V>();
76 this.table = new Node[16]; // TODO: sizing/resizing policies
77 this.threshold = (table.length / 2) + (table.length / 4); // 3/4 capacity
78 }
79
80 @Override public int size() {
81 return size;
82 }
83
84 @Override public V get(Object key) {
85 Node<K, V> node = findByObject(key);
86 return node != null ? node.value : null;
87 }
88
89 @Override public boolean containsKey(Object key) {
90 return findByObject(key) != null;
91 }
92
93 @Override public V put(K key, V value) {
94 if (key == null) {
95 throw new NullPointerException("key == null");
96 }
97 Node<K, V> created = find(key, true);
98 V result = created.value;
99 created.value = value;
100 return result;
101 }
102
103 @Override public void clear() {
104 Arrays.fill(table, null);
105 size = 0;
106 modCount++;
107
108 // Clear all links to help GC
109 Node<K, V> header = this.header;
110 for (Node<K, V> e = header.next; e != header; ) {
111 Node<K, V> next = e.next;
112 e.next = e.prev = null;
113 e = next;
114 }
115
116 header.next = header.prev = header;
117 }
118
119 @Override public V remove(Object key) {
120 Node<K, V> node = removeInternalByKey(key);
121 return node != null ? node.value : null;
122 }
123
124 /**
125 * Returns the node at or adjacent to the given key, creating it if requested.
126 *
127 * @throws ClassCastException if {@code key} and the tree's keys aren't
128 * mutually comparable.
129 */
130 Node<K, V> find(K key, boolean create) {
131 Comparator<? super K> comparator = this.comparator;
132 Node<K, V>[] table = this.table;
133 int hash = secondaryHash(key.hashCode());
134 int index = hash & (table.length - 1);
135 Node<K, V> nearest = table[index];
136 int comparison = 0;
137
138 if (nearest != null) {
139 // Micro-optimization: avoid polymorphic calls to Comparator.compare().
140 @SuppressWarnings("unchecked") // Throws a ClassCastException below if there's trouble.
141 Comparable<Object> comparableKey = (comparator == NATURAL_ORDER)
142 ? (Comparable<Object>) key
143 : null;
144
145 while (true) {
146 comparison = (comparableKey != null)
147 ? comparableKey.compareTo(nearest.key)
148 : comparator.compare(key, nearest.key);
149
150 // We found the requested key.
151 if (comparison == 0) {
152 return nearest;
153 }
154
155 // If it exists, the key is in a subtree. Go deeper.
156 Node<K, V> child = (comparison < 0) ? nearest.left : nearest.right;
157 if (child == null) {
158 break;
159 }
160
161 nearest = child;
162 }
163 }
164
165 // The key doesn't exist in this tree.
166 if (!create) {
167 return null;
168 }
169
170 // Create the node and add it to the tree or the table.
171 Node<K, V> header = this.header;
172 Node<K, V> created;
173 if (nearest == null) {
174 // Check that the value is comparable if we didn't do any comparisons.
175 if (comparator == NATURAL_ORDER && !(key instanceof Comparable)) {
176 throw new ClassCastException(key.getClass().getName() + " is not Comparable");
177 }
178 created = new Node<K, V>(nearest, key, hash, header, header.prev);
179 table[index] = created;
180 } else {
181 created = new Node<K, V>(nearest, key, hash, header, header.prev);
182 if (comparison < 0) { // nearest.key is higher
183 nearest.left = created;
184 } else { // comparison > 0, nearest.key is lower
185 nearest.right = created;
186 }
187 rebalance(nearest, true);
188 }
189
190 if (size++ > threshold) {
191 doubleCapacity();
192 }
193 modCount++;
194
195 return created;
196 }
197
198 @SuppressWarnings("unchecked")
199 Node<K, V> findByObject(Object key) {
200 try {
201 return key != null ? find((K) key, false) : null;
202 } catch (ClassCastException e) {
203 return null;
204 }
205 }
206
207 /**
208 * Returns this map's entry that has the same key and value as {@code
209 * entry}, or null if this map has no such entry.
210 *
211 * <p>This method uses the comparator for key equality rather than {@code
212 * equals}. If this map's comparator isn't consistent with equals (such as
213 * {@code String.CASE_INSENSITIVE_ORDER}), then {@code remove()} and {@code
214 * contains()} will violate the collections API.
215 */
216 Node<K, V> findByEntry(Entry<?, ?> entry) {
217 Node<K, V> mine = findByObject(entry.getKey());
218 boolean valuesEqual = mine != null && equal(mine.value, entry.getValue());
219 return valuesEqual ? mine : null;
220 }
221
222 private boolean equal(Object a, Object b) {
223 return a == b || (a != null && a.equals(b));
224 }
225
226 /**
227 * Applies a supplemental hash function to a given hashCode, which defends
228 * against poor quality hash functions. This is critical because HashMap
229 * uses power-of-two length hash tables, that otherwise encounter collisions
230 * for hashCodes that do not differ in lower or upper bits.
231 */
232 private static int secondaryHash(int h) {
233 // Doug Lea's supplemental hash function
234 h ^= (h >>> 20) ^ (h >>> 12);
235 return h ^ (h >>> 7) ^ (h >>> 4);
236 }
237
238 /**
239 * Removes {@code node} from this tree, rearranging the tree's structure as
240 * necessary.
241 *
242 * @param unlink true to also unlink this node from the iteration linked list.
243 */
244 void removeInternal(Node<K, V> node, boolean unlink) {
245 if (unlink) {
246 node.prev.next = node.next;
247 node.next.prev = node.prev;
248 node.next = node.prev = null; // Help the GC (for performance)
249 }
250
251 Node<K, V> left = node.left;
252 Node<K, V> right = node.right;
253 Node<K, V> originalParent = node.parent;
254 if (left != null && right != null) {
255
256 /*
257 * To remove a node with both left and right subtrees, move an
258 * adjacent node from one of those subtrees into this node's place.
259 *
260 * Removing the adjacent node may change this node's subtrees. This
261 * node may no longer have two subtrees once the adjacent node is
262 * gone!
263 */
264
265 Node<K, V> adjacent = (left.height > right.height) ? left.last() : right.first();
266 removeInternal(adjacent, false); // takes care of rebalance and size--
267
268 int leftHeight = 0;
269 left = node.left;
270 if (left != null) {
271 leftHeight = left.height;
272 adjacent.left = left;
273 left.parent = adjacent;
274 node.left = null;
275 }
276 int rightHeight = 0;
277 right = node.right;
278 if (right != null) {
279 rightHeight = right.height;
280 adjacent.right = right;
281 right.parent = adjacent;
282 node.right = null;
283 }
284 adjacent.height = Math.max(leftHeight, rightHeight) + 1;
285 replaceInParent(node, adjacent);
286 return;
287 } else if (left != null) {
288 replaceInParent(node, left);
289 node.left = null;
290 } else if (right != null) {
291 replaceInParent(node, right);
292 node.right = null;
293 } else {
294 replaceInParent(node, null);
295 }
296
297 rebalance(originalParent, false);
298 size--;
299 modCount++;
300 }
301
302 Node<K, V> removeInternalByKey(Object key) {
303 Node<K, V> node = findByObject(key);
304 if (node != null) {
305 removeInternal(node, true);
306 }
307 return node;
308 }
309
310 private void replaceInParent(Node<K, V> node, Node<K, V> replacement) {
311 Node<K, V> parent = node.parent;
312 node.parent = null;
313 if (replacement != null) {
314 replacement.parent = parent;
315 }
316
317 if (parent != null) {
318 if (parent.left == node) {
319 parent.left = replacement;
320 } else {
321 assert (parent.right == node);
322 parent.right = replacement;
323 }
324 } else {
325 int index = node.hash & (table.length - 1);
326 table[index] = replacement;
327 }
328 }
329
330 /**
331 * Rebalances the tree by making any AVL rotations necessary between the
332 * newly-unbalanced node and the tree's root.
333 *
334 * @param insert true if the node was unbalanced by an insert; false if it
335 * was by a removal.
336 */
337 private void rebalance(Node<K, V> unbalanced, boolean insert) {
338 for (Node<K, V> node = unbalanced; node != null; node = node.parent) {
339 Node<K, V> left = node.left;
340 Node<K, V> right = node.right;
341 int leftHeight = left != null ? left.height : 0;
342 int rightHeight = right != null ? right.height : 0;
343
344 int delta = leftHeight - rightHeight;
345 if (delta == -2) {
346 Node<K, V> rightLeft = right.left;
347 Node<K, V> rightRight = right.right;
348 int rightRightHeight = rightRight != null ? rightRight.height : 0;
349 int rightLeftHeight = rightLeft != null ? rightLeft.height : 0;
350
351 int rightDelta = rightLeftHeight - rightRightHeight;
352 if (rightDelta == -1 || (rightDelta == 0 && !insert)) {
353 rotateLeft(node); // AVL right right
354 } else {
355 assert (rightDelta == 1);
356 rotateRight(right); // AVL right left
357 rotateLeft(node);
358 }
359 if (insert) {
360 break; // no further rotations will be necessary
361 }
362
363 } else if (delta == 2) {
364 Node<K, V> leftLeft = left.left;
365 Node<K, V> leftRight = left.right;
366 int leftRightHeight = leftRight != null ? leftRight.height : 0;
367 int leftLeftHeight = leftLeft != null ? leftLeft.height : 0;
368
369 int leftDelta = leftLeftHeight - leftRightHeight;
370 if (leftDelta == 1 || (leftDelta == 0 && !insert)) {
371 rotateRight(node); // AVL left left
372 } else {
373 assert (leftDelta == -1);
374 rotateLeft(left); // AVL left right
375 rotateRight(node);
376 }
377 if (insert) {
378 break; // no further rotations will be necessary
379 }
380
381 } else if (delta == 0) {
382 node.height = leftHeight + 1; // leftHeight == rightHeight
383 if (insert) {
384 break; // the insert caused balance, so rebalancing is done!
385 }
386
387 } else {
388 assert (delta == -1 || delta == 1);
389 node.height = Math.max(leftHeight, rightHeight) + 1;
390 if (!insert) {
391 break; // the height hasn't changed, so rebalancing is done!
392 }
393 }
394 }
395 }
396
397 /**
398 * Rotates the subtree so that its root's right child is the new root.
399 */
400 private void rotateLeft(Node<K, V> root) {
401 Node<K, V> left = root.left;
402 Node<K, V> pivot = root.right;
403 Node<K, V> pivotLeft = pivot.left;
404 Node<K, V> pivotRight = pivot.right;
405
406 // move the pivot's left child to the root's right
407 root.right = pivotLeft;
408 if (pivotLeft != null) {
409 pivotLeft.parent = root;
410 }
411
412 replaceInParent(root, pivot);
413
414 // move the root to the pivot's left
415 pivot.left = root;
416 root.parent = pivot;
417
418 // fix heights
419 root.height = Math.max(left != null ? left.height : 0,
420 pivotLeft != null ? pivotLeft.height : 0) + 1;
421 pivot.height = Math.max(root.height,
422 pivotRight != null ? pivotRight.height : 0) + 1;
423 }
424
425 /**
426 * Rotates the subtree so that its root's left child is the new root.
427 */
428 private void rotateRight(Node<K, V> root) {
429 Node<K, V> pivot = root.left;
430 Node<K, V> right = root.right;
431 Node<K, V> pivotLeft = pivot.left;
432 Node<K, V> pivotRight = pivot.right;
433
434 // move the pivot's right child to the root's left
435 root.left = pivotRight;
436 if (pivotRight != null) {
437 pivotRight.parent = root;
438 }
439
440 replaceInParent(root, pivot);
441
442 // move the root to the pivot's right
443 pivot.right = root;
444 root.parent = pivot;
445
446 // fixup heights
447 root.height = Math.max(right != null ? right.height : 0,
448 pivotRight != null ? pivotRight.height : 0) + 1;
449 pivot.height = Math.max(root.height,
450 pivotLeft != null ? pivotLeft.height : 0) + 1;
451 }
452
453 private EntrySet entrySet;
454 private KeySet keySet;
455
456 @Override public Set<Entry<K, V>> entrySet() {
457 EntrySet result = entrySet;
458 return result != null ? result : (entrySet = new EntrySet());
459 }
460
461 @Override public Set<K> keySet() {
462 KeySet result = keySet;
463 return result != null ? result : (keySet = new KeySet());
464 }
465
466 static final class Node<K, V> implements Entry<K, V> {
467 Node<K, V> parent;
468 Node<K, V> left;
469 Node<K, V> right;
470 Node<K, V> next;
471 Node<K, V> prev;
472 final K key;
473 final int hash;
474 V value;
475 int height;
476
477 /** Create the header entry */
478 Node() {
479 key = null;
480 hash = -1;
481 next = prev = this;
482 }
483
484 /** Create a regular entry */
485 Node(Node<K, V> parent, K key, int hash, Node<K, V> next, Node<K, V> prev) {
486 this.parent = parent;
487 this.key = key;
488 this.hash = hash;
489 this.height = 1;
490 this.next = next;
491 this.prev = prev;
492 prev.next = this;
493 next.prev = this;
494 }
495
496 public K getKey() {
497 return key;
498 }
499
500 public V getValue() {
501 return value;
502 }
503
504 public V setValue(V value) {
505 V oldValue = this.value;
506 this.value = value;
507 return oldValue;
508 }
509
510 @SuppressWarnings("rawtypes")
511 @Override public boolean equals(Object o) {
512 if (o instanceof Entry) {
513 Entry other = (Entry) o;
514 return (key == null ? other.getKey() == null : key.equals(other.getKey()))
515 && (value == null ? other.getValue() == null : value.equals(other.getValue()));
516 }
517 return false;
518 }
519
520 @Override public int hashCode() {
521 return (key == null ? 0 : key.hashCode())
522 ^ (value == null ? 0 : value.hashCode());
523 }
524
525 @Override public String toString() {
526 return key + "=" + value;
527 }
528
529 /**
530 * Returns the first node in this subtree.
531 */
532 public Node<K, V> first() {
533 Node<K, V> node = this;
534 Node<K, V> child = node.left;
535 while (child != null) {
536 node = child;
537 child = node.left;
538 }
539 return node;
540 }
541
542 /**
543 * Returns the last node in this subtree.
544 */
545 public Node<K, V> last() {
546 Node<K, V> node = this;
547 Node<K, V> child = node.right;
548 while (child != null) {
549 node = child;
550 child = node.right;
551 }
552 return node;
553 }
554 }
555
556 private void doubleCapacity() {
557 table = doubleCapacity(table);
558 threshold = (table.length / 2) + (table.length / 4); // 3/4 capacity
559 }
560
561 /**
562 * Returns a new array containing the same nodes as {@code oldTable}, but with
563 * twice as many trees, each of (approximately) half the previous size.
564 */
565 static <K, V> Node<K, V>[] doubleCapacity(Node<K, V>[] oldTable) {
566 // TODO: don't do anything if we're already at MAX_CAPACITY
567 int oldCapacity = oldTable.length;
568 @SuppressWarnings("unchecked") // Arrays and generics don't get along.
569 Node<K, V>[] newTable = new Node[oldCapacity * 2];
570 AvlIterator<K, V> iterator = new AvlIterator<K, V>();
571 AvlBuilder<K, V> leftBuilder = new AvlBuilder<K, V>();
572 AvlBuilder<K, V> rightBuilder = new AvlBuilder<K, V>();
573
574 // Split each tree into two trees.
575 for (int i = 0; i < oldCapacity; i++) {
576 Node<K, V> root = oldTable[i];
577 if (root == null) {
578 continue;
579 }
580
581 // Compute the sizes of the left and right trees.
582 iterator.reset(root);
583 int leftSize = 0;
584 int rightSize = 0;
585 for (Node<K, V> node; (node = iterator.next()) != null; ) {
586 if ((node.hash & oldCapacity) == 0) {
587 leftSize++;
588 } else {
589 rightSize++;
590 }
591 }
592
593 // Split the tree into two.
594 leftBuilder.reset(leftSize);
595 rightBuilder.reset(rightSize);
596 iterator.reset(root);
597 for (Node<K, V> node; (node = iterator.next()) != null; ) {
598 if ((node.hash & oldCapacity) == 0) {
599 leftBuilder.add(node);
600 } else {
601 rightBuilder.add(node);
602 }
603 }
604
605 // Populate the enlarged array with these new roots.
606 newTable[i] = leftSize > 0 ? leftBuilder.root() : null;
607 newTable[i + oldCapacity] = rightSize > 0 ? rightBuilder.root() : null;
608 }
609 return newTable;
610 }
611
612 /**
613 * Walks an AVL tree in iteration order. Once a node has been returned, its
614 * left, right and parent links are <strong>no longer used</strong>. For this
615 * reason it is safe to transform these links as you walk a tree.
616 *
617 * <p><strong>Warning:</strong> this iterator is destructive. It clears the
618 * parent node of all nodes in the tree. It is an error to make a partial
619 * iteration of a tree.
620 */
621 static class AvlIterator<K, V> {
622 /** This stack is a singly linked list, linked by the 'parent' field. */
623 private Node<K, V> stackTop;
624
625 void reset(Node<K, V> root) {
626 Node<K, V> stackTop = null;
627 for (Node<K, V> n = root; n != null; n = n.left) {
628 n.parent = stackTop;
629 stackTop = n; // Stack push.
630 }
631 this.stackTop = stackTop;
632 }
633
634 public Node<K, V> next() {
635 Node<K, V> stackTop = this.stackTop;
636 if (stackTop == null) {
637 return null;
638 }
639 Node<K, V> result = stackTop;
640 stackTop = result.parent;
641 result.parent = null;
642 for (Node<K, V> n = result.right; n != null; n = n.left) {
643 n.parent = stackTop;
644 stackTop = n; // Stack push.
645 }
646 this.stackTop = stackTop;
647 return result;
648 }
649 }
650
651 /**
652 * Builds AVL trees of a predetermined size by accepting nodes of increasing
653 * value. To use:
654 * <ol>
655 * <li>Call {@link #reset} to initialize the target size <i>size</i>.
656 * <li>Call {@link #add} <i>size</i> times with increasing values.
657 * <li>Call {@link #root} to get the root of the balanced tree.
658 * </ol>
659 *
660 * <p>The returned tree will satisfy the AVL constraint: for every node
661 * <i>N</i>, the height of <i>N.left</i> and <i>N.right</i> is different by at
662 * most 1. It accomplishes this by omitting deepest-level leaf nodes when
663 * building trees whose size isn't a power of 2 minus 1.
664 *
665 * <p>Unlike rebuilding a tree from scratch, this approach requires no value
666 * comparisons. Using this class to create a tree of size <i>S</i> is
667 * {@code O(S)}.
668 */
669 final static class AvlBuilder<K, V> {
670 /** This stack is a singly linked list, linked by the 'parent' field. */
671 private Node<K, V> stack;
672 private int leavesToSkip;
673 private int leavesSkipped;
674 private int size;
675
676 void reset(int targetSize) {
677 // compute the target tree size. This is a power of 2 minus one, like 15 or 31.
678 int treeCapacity = Integer.highestOneBit(targetSize) * 2 - 1;
679 leavesToSkip = treeCapacity - targetSize;
680 size = 0;
681 leavesSkipped = 0;
682 stack = null;
683 }
684
685 void add(Node<K, V> node) {
686 node.left = node.parent = node.right = null;
687 node.height = 1;
688
689 // Skip a leaf if necessary.
690 if (leavesToSkip > 0 && (size & 1) == 0) {
691 size++;
692 leavesToSkip--;
693 leavesSkipped++;
694 }
695
696 node.parent = stack;
697 stack = node; // Stack push.
698 size++;
699
700 // Skip a leaf if necessary.
701 if (leavesToSkip > 0 && (size & 1) == 0) {
702 size++;
703 leavesToSkip--;
704 leavesSkipped++;
705 }
706
707 /*
708 * Combine 3 nodes into subtrees whenever the size is one less than a
709 * multiple of 4. For example we combine the nodes A, B, C into a
710 * 3-element tree with B as the root.
711 *
712 * Combine two subtrees and a spare single value whenever the size is one
713 * less than a multiple of 8. For example at 8 we may combine subtrees
714 * (A B C) and (E F G) with D as the root to form ((A B C) D (E F G)).
715 *
716 * Just as we combine single nodes when size nears a multiple of 4, and
717 * 3-element trees when size nears a multiple of 8, we combine subtrees of
718 * size (N-1) whenever the total size is 2N-1 whenever N is a power of 2.
719 */
720 for (int scale = 4; (size & scale - 1) == scale - 1; scale *= 2) {
721 if (leavesSkipped == 0) {
722 // Pop right, center and left, then make center the top of the stack.
723 Node<K, V> right = stack;
724 Node<K, V> center = right.parent;
725 Node<K, V> left = center.parent;
726 center.parent = left.parent;
727 stack = center;
728 // Construct a tree.
729 center.left = left;
730 center.right = right;
731 center.height = right.height + 1;
732 left.parent = center;
733 right.parent = center;
734 } else if (leavesSkipped == 1) {
735 // Pop right and center, then make center the top of the stack.
736 Node<K, V> right = stack;
737 Node<K, V> center = right.parent;
738 stack = center;
739 // Construct a tree with no left child.
740 center.right = right;
741 center.height = right.height + 1;
742 right.parent = center;
743 leavesSkipped = 0;
744 } else if (leavesSkipped == 2) {
745 leavesSkipped = 0;
746 }
747 }
748 }
749
750 Node<K, V> root() {
751 Node<K, V> stackTop = this.stack;
752 if (stackTop.parent != null) {
753 throw new IllegalStateException();
754 }
755 return stackTop;
756 }
757 }
758
759 private abstract class LinkedTreeMapIterator<T> implements Iterator<T> {
760 Node<K, V> next = header.next;
761 Node<K, V> lastReturned = null;
762 int expectedModCount = modCount;
763
764 LinkedTreeMapIterator() {
765 }
766
767 public final boolean hasNext() {
768 return next != header;
769 }
770
771 final Node<K, V> nextNode() {
772 Node<K, V> e = next;
773 if (e == header) {
774 throw new NoSuchElementException();
775 }
776 if (modCount != expectedModCount) {
777 throw new ConcurrentModificationException();
778 }
779 next = e.next;
780 return lastReturned = e;
781 }
782
783 public final void remove() {
784 if (lastReturned == null) {
785 throw new IllegalStateException();
786 }
787 removeInternal(lastReturned, true);
788 lastReturned = null;
789 expectedModCount = modCount;
790 }
791 }
792
793 final class EntrySet extends AbstractSet<Entry<K, V>> {
794 @Override public int size() {
795 return size;
796 }
797
798 @Override public Iterator<Entry<K, V>> iterator() {
799 return new LinkedTreeMapIterator<Entry<K, V>>() {
800 public Entry<K, V> next() {
801 return nextNode();
802 }
803 };
804 }
805
806 @Override public boolean contains(Object o) {
807 return o instanceof Entry && findByEntry((Entry<?, ?>) o) != null;
808 }
809
810 @Override public boolean remove(Object o) {
811 if (!(o instanceof Entry)) {
812 return false;
813 }
814
815 Node<K, V> node = findByEntry((Entry<?, ?>) o);
816 if (node == null) {
817 return false;
818 }
819 removeInternal(node, true);
820 return true;
821 }
822
823 @Override public void clear() {
824 LinkedHashTreeMap.this.clear();
825 }
826 }
827
828 final class KeySet extends AbstractSet<K> {
829 @Override public int size() {
830 return size;
831 }
832
833 @Override public Iterator<K> iterator() {
834 return new LinkedTreeMapIterator<K>() {
835 public K next() {
836 return nextNode().key;
837 }
838 };
839 }
840
841 @Override public boolean contains(Object o) {
842 return containsKey(o);
843 }
844
845 @Override public boolean remove(Object key) {
846 return removeInternalByKey(key) != null;
847 }
848
849 @Override public void clear() {
850 LinkedHashTreeMap.this.clear();
851 }
852 }
853
854 /**
855 * If somebody is unlucky enough to have to serialize one of these, serialize
856 * it as a LinkedHashMap so that they won't need Gson on the other side to
857 * deserialize it. Using serialization defeats our DoS defence, so most apps
858 * shouldn't use it.
859 */
860 private Object writeReplace() throws ObjectStreamException {
861 return new LinkedHashMap<K, V>(this);
862 }
863 }
1616
1717 package com.google.gson.internal;
1818
19 import java.io.IOException;
20 import java.io.InvalidObjectException;
21 import java.io.ObjectInputStream;
1922 import java.io.ObjectStreamException;
2023 import java.io.Serializable;
2124 import java.util.AbstractMap;
626629 private Object writeReplace() throws ObjectStreamException {
627630 return new LinkedHashMap<K, V>(this);
628631 }
632
633 private void readObject(ObjectInputStream in) throws IOException {
634 // Don't permit directly deserializing this class; writeReplace() should have written a replacement
635 throw new InvalidObjectException("Deserialization is unsupported");
636 }
629637 }
100100 return new UnsafeAllocator() {
101101 @Override
102102 public <T> T newInstance(Class<T> c) {
103 throw new UnsupportedOperationException("Cannot allocate " + c);
103 throw new UnsupportedOperationException("Cannot allocate " + c + ". Usage of JDK sun.misc.Unsafe is enabled, "
104 + "but it could not be used. Make sure your runtime is configured correctly.");
104105 }
105106 };
106107 }
7171 in.nextNull();
7272 return null;
7373 }
74 return deserializeToDate(in.nextString());
74 return deserializeToDate(in);
7575 }
7676
77 private synchronized Date deserializeToDate(String json) {
78 for (DateFormat dateFormat : dateFormats) {
79 try {
80 return dateFormat.parse(json);
81 } catch (ParseException ignored) {}
77 private Date deserializeToDate(JsonReader in) throws IOException {
78 String s = in.nextString();
79 synchronized (dateFormats) {
80 for (DateFormat dateFormat : dateFormats) {
81 try {
82 return dateFormat.parse(s);
83 } catch (ParseException ignored) {}
84 }
8285 }
8386 try {
84 return ISO8601Utils.parse(json, new ParsePosition(0));
87 return ISO8601Utils.parse(s, new ParsePosition(0));
8588 } catch (ParseException e) {
86 throw new JsonSyntaxException(json, e);
89 throw new JsonSyntaxException("Failed parsing '" + s + "' as Date; at path " + in.getPreviousPath(), e);
8790 }
8891 }
8992
90 @Override public synchronized void write(JsonWriter out, Date value) throws IOException {
93 @Override public void write(JsonWriter out, Date value) throws IOException {
9194 if (value == null) {
9295 out.nullValue();
9396 return;
9497 }
95 String dateFormatAsString = dateFormats.get(0).format(value);
98
99 DateFormat dateFormat = dateFormats.get(0);
100 String dateFormatAsString;
101 synchronized (dateFormats) {
102 dateFormatAsString = dateFormat.format(value);
103 }
96104 out.value(dateFormatAsString);
97105 }
98
99
100106 }
0 /*
1 * Copyright (C) 2008 Google Inc.
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 package com.google.gson.internal.bind;
17
18 import java.io.IOException;
19 import java.text.DateFormat;
20 import java.text.ParseException;
21 import java.text.ParsePosition;
22 import java.text.SimpleDateFormat;
23 import java.util.ArrayList;
24 import java.util.Date;
25 import java.util.List;
26 import java.util.Locale;
27
28 import com.google.gson.JsonSyntaxException;
29 import com.google.gson.TypeAdapter;
30 import com.google.gson.TypeAdapterFactory;
31 import com.google.gson.internal.$Gson$Preconditions;
32 import com.google.gson.internal.JavaVersion;
33 import com.google.gson.internal.PreJava9DateFormatProvider;
34 import com.google.gson.internal.bind.util.ISO8601Utils;
35 import com.google.gson.stream.JsonReader;
36 import com.google.gson.stream.JsonToken;
37 import com.google.gson.stream.JsonWriter;
38
39 /**
40 * This type adapter supports subclasses of date by defining a
41 * {@link DefaultDateTypeAdapter.DateType} and then using its {@code createAdapterFactory}
42 * methods.
43 *
44 * @author Inderjeet Singh
45 * @author Joel Leitch
46 */
47 public final class DefaultDateTypeAdapter<T extends Date> extends TypeAdapter<T> {
48 private static final String SIMPLE_NAME = "DefaultDateTypeAdapter";
49
50 public static abstract class DateType<T extends Date> {
51 public static final DateType<Date> DATE = new DateType<Date>(Date.class) {
52 @Override protected Date deserialize(Date date) {
53 return date;
54 }
55 };
56
57 private final Class<T> dateClass;
58
59 protected DateType(Class<T> dateClass) {
60 this.dateClass = dateClass;
61 }
62
63 protected abstract T deserialize(Date date);
64
65 private final TypeAdapterFactory createFactory(DefaultDateTypeAdapter<T> adapter) {
66 return TypeAdapters.newFactory(dateClass, adapter);
67 }
68
69 public final TypeAdapterFactory createAdapterFactory(String datePattern) {
70 return createFactory(new DefaultDateTypeAdapter<T>(this, datePattern));
71 }
72
73 public final TypeAdapterFactory createAdapterFactory(int style) {
74 return createFactory(new DefaultDateTypeAdapter<T>(this, style));
75 }
76
77 public final TypeAdapterFactory createAdapterFactory(int dateStyle, int timeStyle) {
78 return createFactory(new DefaultDateTypeAdapter<T>(this, dateStyle, timeStyle));
79 }
80
81 public final TypeAdapterFactory createDefaultsAdapterFactory() {
82 return createFactory(new DefaultDateTypeAdapter<T>(this, DateFormat.DEFAULT, DateFormat.DEFAULT));
83 }
84 }
85
86 private final DateType<T> dateType;
87
88 /**
89 * List of 1 or more different date formats used for de-serialization attempts.
90 * The first of them is used for serialization as well.
91 */
92 private final List<DateFormat> dateFormats = new ArrayList<DateFormat>();
93
94 private DefaultDateTypeAdapter(DateType<T> dateType, String datePattern) {
95 this.dateType = $Gson$Preconditions.checkNotNull(dateType);
96 dateFormats.add(new SimpleDateFormat(datePattern, Locale.US));
97 if (!Locale.getDefault().equals(Locale.US)) {
98 dateFormats.add(new SimpleDateFormat(datePattern));
99 }
100 }
101
102 private DefaultDateTypeAdapter(DateType<T> dateType, int style) {
103 this.dateType = $Gson$Preconditions.checkNotNull(dateType);
104 dateFormats.add(DateFormat.getDateInstance(style, Locale.US));
105 if (!Locale.getDefault().equals(Locale.US)) {
106 dateFormats.add(DateFormat.getDateInstance(style));
107 }
108 if (JavaVersion.isJava9OrLater()) {
109 dateFormats.add(PreJava9DateFormatProvider.getUSDateFormat(style));
110 }
111 }
112
113 private DefaultDateTypeAdapter(DateType<T> dateType, int dateStyle, int timeStyle) {
114 this.dateType = $Gson$Preconditions.checkNotNull(dateType);
115 dateFormats.add(DateFormat.getDateTimeInstance(dateStyle, timeStyle, Locale.US));
116 if (!Locale.getDefault().equals(Locale.US)) {
117 dateFormats.add(DateFormat.getDateTimeInstance(dateStyle, timeStyle));
118 }
119 if (JavaVersion.isJava9OrLater()) {
120 dateFormats.add(PreJava9DateFormatProvider.getUSDateTimeFormat(dateStyle, timeStyle));
121 }
122 }
123
124 // These methods need to be synchronized since JDK DateFormat classes are not thread-safe
125 // See issue 162
126 @Override
127 public void write(JsonWriter out, Date value) throws IOException {
128 if (value == null) {
129 out.nullValue();
130 return;
131 }
132
133 DateFormat dateFormat = dateFormats.get(0);
134 String dateFormatAsString;
135 synchronized (dateFormats) {
136 dateFormatAsString = dateFormat.format(value);
137 }
138 out.value(dateFormatAsString);
139 }
140
141 @Override
142 public T read(JsonReader in) throws IOException {
143 if (in.peek() == JsonToken.NULL) {
144 in.nextNull();
145 return null;
146 }
147 Date date = deserializeToDate(in);
148 return dateType.deserialize(date);
149 }
150
151 private Date deserializeToDate(JsonReader in) throws IOException {
152 String s = in.nextString();
153 synchronized (dateFormats) {
154 for (DateFormat dateFormat : dateFormats) {
155 try {
156 return dateFormat.parse(s);
157 } catch (ParseException ignored) {}
158 }
159 }
160
161 try {
162 return ISO8601Utils.parse(s, new ParsePosition(0));
163 } catch (ParseException e) {
164 throw new JsonSyntaxException("Failed parsing '" + s + "' as Date; at path " + in.getPreviousPath(), e);
165 }
166 }
167
168 @Override
169 public String toString() {
170 DateFormat defaultFormat = dateFormats.get(0);
171 if (defaultFormat instanceof SimpleDateFormat) {
172 return SIMPLE_NAME + '(' + ((SimpleDateFormat) defaultFormat).toPattern() + ')';
173 } else {
174 return SIMPLE_NAME + '(' + defaultFormat.getClass().getSimpleName() + ')';
175 }
176 }
177 }
100100
101101 @Override public boolean hasNext() throws IOException {
102102 JsonToken token = peek();
103 return token != JsonToken.END_OBJECT && token != JsonToken.END_ARRAY;
103 return token != JsonToken.END_OBJECT && token != JsonToken.END_ARRAY && token != JsonToken.END_DOCUMENT;
104104 }
105105
106106 @Override public JsonToken peek() throws IOException {
248248 return result;
249249 }
250250
251 JsonElement nextJsonElement() throws IOException {
252 final JsonToken peeked = peek();
253 if (peeked == JsonToken.NAME
254 || peeked == JsonToken.END_ARRAY
255 || peeked == JsonToken.END_OBJECT
256 || peeked == JsonToken.END_DOCUMENT) {
257 throw new IllegalStateException("Unexpected " + peeked + " when reading a JsonElement.");
258 }
259 final JsonElement element = (JsonElement) peekStack();
260 skipValue();
261 return element;
262 }
263
251264 @Override public void close() throws IOException {
252265 stack = new Object[] { SENTINEL_CLOSED };
253266 stackSize = 1;
269282 }
270283
271284 @Override public String toString() {
272 return getClass().getSimpleName();
285 return getClass().getSimpleName() + locationString();
273286 }
274287
275288 public void promoteNameToValue() throws IOException {
290303 stack[stackSize++] = newTop;
291304 }
292305
293 @Override public String getPath() {
306 private String getPath(boolean usePreviousPath) {
294307 StringBuilder result = new StringBuilder().append('$');
295308 for (int i = 0; i < stackSize; i++) {
296309 if (stack[i] instanceof JsonArray) {
297 if (stack[++i] instanceof Iterator) {
298 result.append('[').append(pathIndices[i]).append(']');
310 if (++i < stackSize && stack[i] instanceof Iterator) {
311 int pathIndex = pathIndices[i];
312 // If index is last path element it points to next array element; have to decrement
313 // `- 1` covers case where iterator for next element is on stack
314 // `- 2` covers case where peek() already pushed next element onto stack
315 if (usePreviousPath && pathIndex > 0 && (i == stackSize - 1 || i == stackSize - 2)) {
316 pathIndex--;
317 }
318 result.append('[').append(pathIndex).append(']');
299319 }
300320 } else if (stack[i] instanceof JsonObject) {
301 if (stack[++i] instanceof Iterator) {
321 if (++i < stackSize && stack[i] instanceof Iterator) {
302322 result.append('.');
303323 if (pathNames[i] != null) {
304324 result.append(pathNames[i]);
309329 return result.toString();
310330 }
311331
332 @Override public String getPreviousPath() {
333 return getPath(true);
334 }
335
336 @Override public String getPath() {
337 return getPath(false);
338 }
339
312340 private String locationString() {
313341 return " at path " + getPath();
314342 }
0 /*
1 * Copyright (C) 2020 Google Inc.
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 package com.google.gson.internal.bind;
17
18 import com.google.gson.Gson;
19 import com.google.gson.JsonSyntaxException;
20 import com.google.gson.ToNumberStrategy;
21 import com.google.gson.ToNumberPolicy;
22 import com.google.gson.TypeAdapter;
23 import com.google.gson.TypeAdapterFactory;
24 import com.google.gson.reflect.TypeToken;
25 import com.google.gson.stream.JsonReader;
26 import com.google.gson.stream.JsonToken;
27 import com.google.gson.stream.JsonWriter;
28
29 import java.io.IOException;
30
31 /**
32 * Type adapter for {@link Number}.
33 */
34 public final class NumberTypeAdapter extends TypeAdapter<Number> {
35 /**
36 * Gson default factory using {@link ToNumberPolicy#LAZILY_PARSED_NUMBER}.
37 */
38 private static final TypeAdapterFactory LAZILY_PARSED_NUMBER_FACTORY = newFactory(ToNumberPolicy.LAZILY_PARSED_NUMBER);
39
40 private final ToNumberStrategy toNumberStrategy;
41
42 private NumberTypeAdapter(ToNumberStrategy toNumberStrategy) {
43 this.toNumberStrategy = toNumberStrategy;
44 }
45
46 private static TypeAdapterFactory newFactory(ToNumberStrategy toNumberStrategy) {
47 final NumberTypeAdapter adapter = new NumberTypeAdapter(toNumberStrategy);
48 return new TypeAdapterFactory() {
49 @SuppressWarnings("unchecked")
50 @Override public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
51 return type.getRawType() == Number.class ? (TypeAdapter<T>) adapter : null;
52 }
53 };
54 }
55
56 public static TypeAdapterFactory getFactory(ToNumberStrategy toNumberStrategy) {
57 if (toNumberStrategy == ToNumberPolicy.LAZILY_PARSED_NUMBER) {
58 return LAZILY_PARSED_NUMBER_FACTORY;
59 } else {
60 return newFactory(toNumberStrategy);
61 }
62 }
63
64 @Override public Number read(JsonReader in) throws IOException {
65 JsonToken jsonToken = in.peek();
66 switch (jsonToken) {
67 case NULL:
68 in.nextNull();
69 return null;
70 case NUMBER:
71 case STRING:
72 return toNumberStrategy.readNumber(in);
73 default:
74 throw new JsonSyntaxException("Expecting number, got: " + jsonToken + "; at path " + in.getPath());
75 }
76 }
77
78 @Override public void write(JsonWriter out, Number value) throws IOException {
79 out.value(value);
80 }
81 }
1616 package com.google.gson.internal.bind;
1717
1818 import com.google.gson.Gson;
19 import com.google.gson.ToNumberStrategy;
20 import com.google.gson.ToNumberPolicy;
1921 import com.google.gson.TypeAdapter;
2022 import com.google.gson.TypeAdapterFactory;
2123 import com.google.gson.internal.LinkedTreeMap;
3436 * serialization and a primitive/Map/List on deserialization.
3537 */
3638 public final class ObjectTypeAdapter extends TypeAdapter<Object> {
37 public static final TypeAdapterFactory FACTORY = new TypeAdapterFactory() {
38 @SuppressWarnings("unchecked")
39 @Override public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
40 if (type.getRawType() == Object.class) {
41 return (TypeAdapter<T>) new ObjectTypeAdapter(gson);
42 }
43 return null;
44 }
45 };
39 /**
40 * Gson default factory using {@link ToNumberPolicy#DOUBLE}.
41 */
42 private static final TypeAdapterFactory DOUBLE_FACTORY = newFactory(ToNumberPolicy.DOUBLE);
4643
4744 private final Gson gson;
45 private final ToNumberStrategy toNumberStrategy;
4846
49 ObjectTypeAdapter(Gson gson) {
47 private ObjectTypeAdapter(Gson gson, ToNumberStrategy toNumberStrategy) {
5048 this.gson = gson;
49 this.toNumberStrategy = toNumberStrategy;
50 }
51
52 private static TypeAdapterFactory newFactory(final ToNumberStrategy toNumberStrategy) {
53 return new TypeAdapterFactory() {
54 @SuppressWarnings("unchecked")
55 @Override public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
56 if (type.getRawType() == Object.class) {
57 return (TypeAdapter<T>) new ObjectTypeAdapter(gson, toNumberStrategy);
58 }
59 return null;
60 }
61 };
62 }
63
64 public static TypeAdapterFactory getFactory(ToNumberStrategy toNumberStrategy) {
65 if (toNumberStrategy == ToNumberPolicy.DOUBLE) {
66 return DOUBLE_FACTORY;
67 } else {
68 return newFactory(toNumberStrategy);
69 }
5170 }
5271
5372 @Override public Object read(JsonReader in) throws IOException {
7594 return in.nextString();
7695
7796 case NUMBER:
78 return in.nextDouble();
97 return toNumberStrategy.readNumber(in);
7998
8099 case BOOLEAN:
81100 return in.nextBoolean();
2727 import com.google.gson.internal.Excluder;
2828 import com.google.gson.internal.ObjectConstructor;
2929 import com.google.gson.internal.Primitives;
30 import com.google.gson.internal.reflect.ReflectionAccessor;
30 import com.google.gson.internal.reflect.ReflectionHelper;
3131 import com.google.gson.reflect.TypeToken;
3232 import com.google.gson.stream.JsonReader;
3333 import com.google.gson.stream.JsonToken;
4949 private final FieldNamingStrategy fieldNamingPolicy;
5050 private final Excluder excluder;
5151 private final JsonAdapterAnnotationTypeAdapterFactory jsonAdapterFactory;
52 private final ReflectionAccessor accessor = ReflectionAccessor.getInstance();
5352
5453 public ReflectiveTypeAdapterFactory(ConstructorConstructor constructorConstructor,
5554 FieldNamingStrategy fieldNamingPolicy, Excluder excluder,
155154 if (!serialize && !deserialize) {
156155 continue;
157156 }
158 accessor.makeAccessible(field);
157 ReflectionHelper.makeAccessible(field);
159158 Type fieldType = $Gson$Types.resolve(type.getType(), raw, field.getGenericType());
160159 List<String> fieldNames = getFieldNames(field);
161160 BoundField previous = null;
+0
-67
gson/src/main/java/com/google/gson/internal/bind/SqlDateTypeAdapter.java less more
0 /*
1 * Copyright (C) 2011 Google Inc.
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 package com.google.gson.internal.bind;
17
18 import com.google.gson.Gson;
19 import com.google.gson.JsonSyntaxException;
20 import com.google.gson.TypeAdapter;
21 import com.google.gson.TypeAdapterFactory;
22 import com.google.gson.reflect.TypeToken;
23 import com.google.gson.stream.JsonReader;
24 import com.google.gson.stream.JsonToken;
25 import com.google.gson.stream.JsonWriter;
26 import java.io.IOException;
27 import java.text.DateFormat;
28 import java.text.ParseException;
29 import java.text.SimpleDateFormat;
30
31 /**
32 * Adapter for java.sql.Date. Although this class appears stateless, it is not.
33 * DateFormat captures its time zone and locale when it is created, which gives
34 * this class state. DateFormat isn't thread safe either, so this class has
35 * to synchronize its read and write methods.
36 */
37 public final class SqlDateTypeAdapter extends TypeAdapter<java.sql.Date> {
38 public static final TypeAdapterFactory FACTORY = new TypeAdapterFactory() {
39 @SuppressWarnings("unchecked") // we use a runtime check to make sure the 'T's equal
40 @Override public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) {
41 return typeToken.getRawType() == java.sql.Date.class
42 ? (TypeAdapter<T>) new SqlDateTypeAdapter() : null;
43 }
44 };
45
46 private final DateFormat format = new SimpleDateFormat("MMM d, yyyy");
47
48 @Override
49 public synchronized java.sql.Date read(JsonReader in) throws IOException {
50 if (in.peek() == JsonToken.NULL) {
51 in.nextNull();
52 return null;
53 }
54 try {
55 final long utilDate = format.parse(in.nextString()).getTime();
56 return new java.sql.Date(utilDate);
57 } catch (ParseException e) {
58 throw new JsonSyntaxException(e);
59 }
60 }
61
62 @Override
63 public synchronized void write(JsonWriter out, java.sql.Date value) throws IOException {
64 out.value(value == null ? null : format.format(value));
65 }
66 }
+0
-66
gson/src/main/java/com/google/gson/internal/bind/TimeTypeAdapter.java less more
0 /*
1 * Copyright (C) 2011 Google Inc.
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 package com.google.gson.internal.bind;
17
18 import com.google.gson.Gson;
19 import com.google.gson.JsonSyntaxException;
20 import com.google.gson.TypeAdapter;
21 import com.google.gson.TypeAdapterFactory;
22 import com.google.gson.reflect.TypeToken;
23 import com.google.gson.stream.JsonReader;
24 import com.google.gson.stream.JsonToken;
25 import com.google.gson.stream.JsonWriter;
26 import java.io.IOException;
27 import java.sql.Time;
28 import java.text.DateFormat;
29 import java.text.ParseException;
30 import java.text.SimpleDateFormat;
31 import java.util.Date;
32
33 /**
34 * Adapter for Time. Although this class appears stateless, it is not.
35 * DateFormat captures its time zone and locale when it is created, which gives
36 * this class state. DateFormat isn't thread safe either, so this class has
37 * to synchronize its read and write methods.
38 */
39 public final class TimeTypeAdapter extends TypeAdapter<Time> {
40 public static final TypeAdapterFactory FACTORY = new TypeAdapterFactory() {
41 @SuppressWarnings("unchecked") // we use a runtime check to make sure the 'T's equal
42 @Override public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) {
43 return typeToken.getRawType() == Time.class ? (TypeAdapter<T>) new TimeTypeAdapter() : null;
44 }
45 };
46
47 private final DateFormat format = new SimpleDateFormat("hh:mm:ss a");
48
49 @Override public synchronized Time read(JsonReader in) throws IOException {
50 if (in.peek() == JsonToken.NULL) {
51 in.nextNull();
52 return null;
53 }
54 try {
55 Date date = format.parse(in.nextString());
56 return new Time(date.getTime());
57 } catch (ParseException e) {
58 throw new JsonSyntaxException(e);
59 }
60 }
61
62 @Override public synchronized void write(JsonWriter out, Time value) throws IOException {
63 out.value(value == null ? null : format.format(value));
64 }
65 }
4646 private final GsonContextImpl context = new GsonContextImpl();
4747
4848 /** The delegate is lazily created because it may not be needed, and creating it may fail. */
49 private TypeAdapter<T> delegate;
49 private volatile TypeAdapter<T> delegate;
5050
5151 public TreeTypeAdapter(JsonSerializer<T> serializer, JsonDeserializer<T> deserializer,
5252 Gson gson, TypeToken<T> typeToken, TypeAdapterFactory skipPast) {
8282 }
8383
8484 private TypeAdapter<T> delegate() {
85 // A race might lead to `delegate` being assigned by multiple threads but the last assignment will stick
8586 TypeAdapter<T> d = delegate;
8687 return d != null
8788 ? d
1616 package com.google.gson.internal.bind;
1717
1818 import java.io.IOException;
19 import java.lang.reflect.AccessibleObject;
1920 import java.lang.reflect.Field;
2021 import java.math.BigDecimal;
2122 import java.math.BigInteger;
2526 import java.net.URL;
2627 import java.security.AccessController;
2728 import java.security.PrivilegedAction;
28 import java.sql.Timestamp;
2929 import java.util.ArrayList;
3030 import java.util.BitSet;
3131 import java.util.Calendar;
3232 import java.util.Currency;
33 import java.util.Date;
3433 import java.util.GregorianCalendar;
3534 import java.util.HashMap;
3635 import java.util.List;
9392 boolean set;
9493 switch (tokenType) {
9594 case NUMBER:
96 set = in.nextInt() != 0;
95 case STRING:
96 int intValue = in.nextInt();
97 if (intValue == 0) {
98 set = false;
99 } else if (intValue == 1) {
100 set = true;
101 } else {
102 throw new JsonSyntaxException("Invalid bitset value " + intValue + ", expected 0 or 1; at path " + in.getPreviousPath());
103 }
97104 break;
98105 case BOOLEAN:
99106 set = in.nextBoolean();
100107 break;
101 case STRING:
102 String stringValue = in.nextString();
103 try {
104 set = Integer.parseInt(stringValue) != 0;
105 } catch (NumberFormatException e) {
106 throw new JsonSyntaxException(
107 "Error: Expecting: bitset number value (1, 0), Found: " + stringValue);
108 }
109 break;
110108 default:
111 throw new JsonSyntaxException("Invalid bitset value type: " + tokenType);
109 throw new JsonSyntaxException("Invalid bitset value type: " + tokenType + "; at path " + in.getPath());
112110 }
113111 if (set) {
114112 bitset.set(i);
179177 in.nextNull();
180178 return null;
181179 }
182 try {
183 int intValue = in.nextInt();
184 return (byte) intValue;
180
181 int intValue;
182 try {
183 intValue = in.nextInt();
185184 } catch (NumberFormatException e) {
186185 throw new JsonSyntaxException(e);
187186 }
187 // Allow up to 255 to support unsigned values
188 if (intValue > 255 || intValue < Byte.MIN_VALUE) {
189 throw new JsonSyntaxException("Lossy conversion from " + intValue + " to byte; at path " + in.getPreviousPath());
190 }
191 return (byte) intValue;
188192 }
189193 @Override
190194 public void write(JsonWriter out, Number value) throws IOException {
202206 in.nextNull();
203207 return null;
204208 }
205 try {
206 return (short) in.nextInt();
209
210 int intValue;
211 try {
212 intValue = in.nextInt();
207213 } catch (NumberFormatException e) {
208214 throw new JsonSyntaxException(e);
209215 }
216 // Allow up to 65535 to support unsigned values
217 if (intValue > 65535 || intValue < Short.MIN_VALUE) {
218 throw new JsonSyntaxException("Lossy conversion from " + intValue + " to short; at path " + in.getPreviousPath());
219 }
220 return (short) intValue;
210221 }
211222 @Override
212223 public void write(JsonWriter out, Number value) throws IOException {
344355 }
345356 };
346357
347 public static final TypeAdapter<Number> NUMBER = new TypeAdapter<Number>() {
348 @Override
349 public Number read(JsonReader in) throws IOException {
350 JsonToken jsonToken = in.peek();
351 switch (jsonToken) {
352 case NULL:
353 in.nextNull();
354 return null;
355 case NUMBER:
356 case STRING:
357 return new LazilyParsedNumber(in.nextString());
358 default:
359 throw new JsonSyntaxException("Expecting number, got: " + jsonToken);
360 }
361 }
362 @Override
363 public void write(JsonWriter out, Number value) throws IOException {
364 out.value(value);
365 }
366 };
367
368 public static final TypeAdapterFactory NUMBER_FACTORY = newFactory(Number.class, NUMBER);
369
370358 public static final TypeAdapter<Character> CHARACTER = new TypeAdapter<Character>() {
371359 @Override
372360 public Character read(JsonReader in) throws IOException {
376364 }
377365 String str = in.nextString();
378366 if (str.length() != 1) {
379 throw new JsonSyntaxException("Expecting character, got: " + str);
367 throw new JsonSyntaxException("Expecting character, got: " + str + "; at " + in.getPreviousPath());
380368 }
381369 return str.charAt(0);
382370 }
408396 out.value(value);
409397 }
410398 };
411
399
412400 public static final TypeAdapter<BigDecimal> BIG_DECIMAL = new TypeAdapter<BigDecimal>() {
413401 @Override public BigDecimal read(JsonReader in) throws IOException {
414402 if (in.peek() == JsonToken.NULL) {
415403 in.nextNull();
416404 return null;
417405 }
418 try {
419 return new BigDecimal(in.nextString());
406 String s = in.nextString();
407 try {
408 return new BigDecimal(s);
420409 } catch (NumberFormatException e) {
421 throw new JsonSyntaxException(e);
410 throw new JsonSyntaxException("Failed parsing '" + s + "' as BigDecimal; at path " + in.getPreviousPath(), e);
422411 }
423412 }
424413
426415 out.value(value);
427416 }
428417 };
429
418
430419 public static final TypeAdapter<BigInteger> BIG_INTEGER = new TypeAdapter<BigInteger>() {
431420 @Override public BigInteger read(JsonReader in) throws IOException {
432421 if (in.peek() == JsonToken.NULL) {
433422 in.nextNull();
434423 return null;
435424 }
436 try {
437 return new BigInteger(in.nextString());
425 String s = in.nextString();
426 try {
427 return new BigInteger(s);
438428 } catch (NumberFormatException e) {
439 throw new JsonSyntaxException(e);
429 throw new JsonSyntaxException("Failed parsing '" + s + "' as BigInteger; at path " + in.getPreviousPath(), e);
440430 }
441431 }
442432
443433 @Override public void write(JsonWriter out, BigInteger value) throws IOException {
434 out.value(value);
435 }
436 };
437
438 public static final TypeAdapter<LazilyParsedNumber> LAZILY_PARSED_NUMBER = new TypeAdapter<LazilyParsedNumber>() {
439 // Normally users should not be able to access and deserialize LazilyParsedNumber because
440 // it is an internal type, but implement this nonetheless in case there are legit corner
441 // cases where this is possible
442 @Override public LazilyParsedNumber read(JsonReader in) throws IOException {
443 if (in.peek() == JsonToken.NULL) {
444 in.nextNull();
445 return null;
446 }
447 return new LazilyParsedNumber(in.nextString());
448 }
449
450 @Override public void write(JsonWriter out, LazilyParsedNumber value) throws IOException {
444451 out.value(value);
445452 }
446453 };
549556 in.nextNull();
550557 return null;
551558 }
552 return java.util.UUID.fromString(in.nextString());
559 String s = in.nextString();
560 try {
561 return java.util.UUID.fromString(s);
562 } catch (IllegalArgumentException e) {
563 throw new JsonSyntaxException("Failed parsing '" + s + "' as UUID; at path " + in.getPreviousPath(), e);
564 }
553565 }
554566 @Override
555567 public void write(JsonWriter out, UUID value) throws IOException {
562574 public static final TypeAdapter<Currency> CURRENCY = new TypeAdapter<Currency>() {
563575 @Override
564576 public Currency read(JsonReader in) throws IOException {
565 return Currency.getInstance(in.nextString());
577 String s = in.nextString();
578 try {
579 return Currency.getInstance(s);
580 } catch (IllegalArgumentException e) {
581 throw new JsonSyntaxException("Failed parsing '" + s + "' as Currency; at path " + in.getPreviousPath(), e);
582 }
566583 }
567584 @Override
568585 public void write(JsonWriter out, Currency value) throws IOException {
570587 }
571588 }.nullSafe();
572589 public static final TypeAdapterFactory CURRENCY_FACTORY = newFactory(Currency.class, CURRENCY);
573
574 public static final TypeAdapterFactory TIMESTAMP_FACTORY = new TypeAdapterFactory() {
575 @SuppressWarnings("unchecked") // we use a runtime check to make sure the 'T's equal
576 @Override public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) {
577 if (typeToken.getRawType() != Timestamp.class) {
578 return null;
579 }
580
581 final TypeAdapter<Date> dateTypeAdapter = gson.getAdapter(Date.class);
582 return (TypeAdapter<T>) new TypeAdapter<Timestamp>() {
583 @Override public Timestamp read(JsonReader in) throws IOException {
584 Date date = dateTypeAdapter.read(in);
585 return date != null ? new Timestamp(date.getTime()) : null;
586 }
587
588 @Override public void write(JsonWriter out, Timestamp value) throws IOException {
589 dateTypeAdapter.write(out, value);
590 }
591 };
592 }
593 };
594590
595591 public static final TypeAdapter<Calendar> CALENDAR = new TypeAdapter<Calendar>() {
596592 private static final String YEAR = "year";
699695
700696 public static final TypeAdapter<JsonElement> JSON_ELEMENT = new TypeAdapter<JsonElement>() {
701697 @Override public JsonElement read(JsonReader in) throws IOException {
698 if (in instanceof JsonTreeReader) {
699 return ((JsonTreeReader) in).nextJsonElement();
700 }
701
702702 switch (in.peek()) {
703703 case STRING:
704704 return new JsonPrimitive(in.nextString());
776776 private final Map<String, T> nameToConstant = new HashMap<String, T>();
777777 private final Map<T, String> constantToName = new HashMap<T, String>();
778778
779 public EnumTypeAdapter(Class<T> classOfT) {
780 try {
781 for (final Field field : classOfT.getDeclaredFields()) {
782 if (!field.isEnumConstant()) {
783 continue;
779 public EnumTypeAdapter(final Class<T> classOfT) {
780 try {
781 // Uses reflection to find enum constants to work around name mismatches for obfuscated classes
782 // Reflection access might throw SecurityException, therefore run this in privileged context;
783 // should be acceptable because this only retrieves enum constants, but does not expose anything else
784 Field[] constantFields = AccessController.doPrivileged(new PrivilegedAction<Field[]>() {
785 @Override public Field[] run() {
786 Field[] fields = classOfT.getDeclaredFields();
787 ArrayList<Field> constantFieldsList = new ArrayList<Field>(fields.length);
788 for (Field f : fields) {
789 if (f.isEnumConstant()) {
790 constantFieldsList.add(f);
791 }
792 }
793
794 Field[] constantFields = constantFieldsList.toArray(new Field[0]);
795 AccessibleObject.setAccessible(constantFields, true);
796 return constantFields;
784797 }
785 AccessController.doPrivileged(new PrivilegedAction<Void>() {
786 @Override public Void run() {
787 field.setAccessible(true);
788 return null;
789 }
790 });
798 });
799 for (Field constantField : constantFields) {
791800 @SuppressWarnings("unchecked")
792 T constant = (T)(field.get(null));
801 T constant = (T)(constantField.get(null));
793802 String name = constant.name();
794 SerializedName annotation = field.getAnnotation(SerializedName.class);
803 SerializedName annotation = constantField.getAnnotation(SerializedName.class);
795804 if (annotation != null) {
796805 name = annotation.value();
797806 for (String alternate : annotation.alternate()) {
907916 T1 result = typeAdapter.read(in);
908917 if (result != null && !requestedType.isInstance(result)) {
909918 throw new JsonSyntaxException("Expected a " + requestedType.getName()
910 + " but was " + result.getClass().getName());
919 + " but was " + result.getClass().getName() + "; at path " + in.getPreviousPath());
911920 }
912921 return result;
913922 }
+0
-33
gson/src/main/java/com/google/gson/internal/reflect/PreJava9ReflectionAccessor.java less more
0 /*
1 * Copyright (C) 2017 The Gson authors
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 package com.google.gson.internal.reflect;
16
17 import java.lang.reflect.AccessibleObject;
18
19 /**
20 * A basic implementation of {@link ReflectionAccessor} which is suitable for Java 8 and below.
21 * <p>
22 * This implementation just calls {@link AccessibleObject#setAccessible(boolean) setAccessible(true)}, which worked
23 * fine before Java 9.
24 */
25 final class PreJava9ReflectionAccessor extends ReflectionAccessor {
26
27 /** {@inheritDoc} */
28 @Override
29 public void makeAccessible(AccessibleObject ao) {
30 ao.setAccessible(true);
31 }
32 }
+0
-54
gson/src/main/java/com/google/gson/internal/reflect/ReflectionAccessor.java less more
0 /*
1 * Copyright (C) 2017 The Gson authors
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 package com.google.gson.internal.reflect;
16
17 import java.lang.reflect.AccessibleObject;
18
19 import com.google.gson.internal.JavaVersion;
20
21 /**
22 * Provides a replacement for {@link AccessibleObject#setAccessible(boolean)}, which may be used to
23 * avoid reflective access issues appeared in Java 9, like {@link java.lang.reflect.InaccessibleObjectException}
24 * thrown or warnings like
25 * <pre>
26 * WARNING: An illegal reflective access operation has occurred
27 * WARNING: Illegal reflective access by ...
28 * </pre>
29 * <p/>
30 * Works both for Java 9 and earlier Java versions.
31 */
32 public abstract class ReflectionAccessor {
33
34 // the singleton instance, use getInstance() to obtain
35 private static final ReflectionAccessor instance = JavaVersion.getMajorJavaVersion() < 9 ? new PreJava9ReflectionAccessor() : new UnsafeReflectionAccessor();
36
37 /**
38 * Does the same as {@code ao.setAccessible(true)}, but never throws
39 * {@link java.lang.reflect.InaccessibleObjectException}
40 */
41 public abstract void makeAccessible(AccessibleObject ao);
42
43 /**
44 * Obtains a {@link ReflectionAccessor} instance suitable for the current Java version.
45 * <p>
46 * You may need one a reflective operation in your code throws {@link java.lang.reflect.InaccessibleObjectException}.
47 * In such a case, use {@link ReflectionAccessor#makeAccessible(AccessibleObject)} on a field, method or constructor
48 * (instead of basic {@link AccessibleObject#setAccessible(boolean)}).
49 */
50 public static ReflectionAccessor getInstance() {
51 return instance;
52 }
53 }
0 package com.google.gson.internal.reflect;
1
2 import com.google.gson.JsonIOException;
3 import java.lang.reflect.Constructor;
4 import java.lang.reflect.Field;
5
6 public class ReflectionHelper {
7 private ReflectionHelper() { }
8
9 /**
10 * Tries making the field accessible, wrapping any thrown exception in a
11 * {@link JsonIOException} with descriptive message.
12 *
13 * @param field field to make accessible
14 * @throws JsonIOException if making the field accessible fails
15 */
16 public static void makeAccessible(Field field) throws JsonIOException {
17 try {
18 field.setAccessible(true);
19 } catch (Exception exception) {
20 throw new JsonIOException("Failed making field '" + field.getDeclaringClass().getName() + "#"
21 + field.getName() + "' accessible; either change its visibility or write a custom "
22 + "TypeAdapter for its declaring type", exception);
23 }
24 }
25
26 /**
27 * Creates a string representation for a constructor.
28 * E.g.: {@code java.lang.String#String(char[], int, int)}
29 */
30 private static String constructorToString(Constructor<?> constructor) {
31 StringBuilder stringBuilder = new StringBuilder(constructor.getDeclaringClass().getName())
32 .append('#')
33 .append(constructor.getDeclaringClass().getSimpleName())
34 .append('(');
35 Class<?>[] parameters = constructor.getParameterTypes();
36 for (int i = 0; i < parameters.length; i++) {
37 if (i > 0) {
38 stringBuilder.append(", ");
39 }
40 stringBuilder.append(parameters[i].getSimpleName());
41 }
42
43 return stringBuilder.append(')').toString();
44 }
45
46 /**
47 * Tries making the constructor accessible, returning an exception message
48 * if this fails.
49 *
50 * @param constructor constructor to make accessible
51 * @return exception message; {@code null} if successful, non-{@code null} if
52 * unsuccessful
53 */
54 public static String tryMakeAccessible(Constructor<?> constructor) {
55 try {
56 constructor.setAccessible(true);
57 return null;
58 } catch (Exception exception) {
59 return "Failed making constructor '" + constructorToString(constructor) + "' accessible; "
60 + "either change its visibility or write a custom InstanceCreator or TypeAdapter for its declaring type: "
61 // Include the message since it might contain more detailed information
62 + exception.getMessage();
63 }
64 }
65 }
+0
-86
gson/src/main/java/com/google/gson/internal/reflect/UnsafeReflectionAccessor.java less more
0 /*
1 * Copyright (C) 2017 The Gson authors
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 package com.google.gson.internal.reflect;
16
17 import java.lang.reflect.AccessibleObject;
18 import java.lang.reflect.Field;
19 import java.lang.reflect.Method;
20
21 import com.google.gson.JsonIOException;
22
23 /**
24 * An implementation of {@link ReflectionAccessor} based on {@link Unsafe}.
25 * <p>
26 * NOTE: This implementation is designed for Java 9. Although it should work with earlier Java releases, it is better to
27 * use {@link PreJava9ReflectionAccessor} for them.
28 */
29 @SuppressWarnings({"unchecked", "rawtypes"})
30 final class UnsafeReflectionAccessor extends ReflectionAccessor {
31
32 private static Class unsafeClass;
33 private final Object theUnsafe = getUnsafeInstance();
34 private final Field overrideField = getOverrideField();
35
36 /** {@inheritDoc} */
37 @Override
38 public void makeAccessible(AccessibleObject ao) {
39 boolean success = makeAccessibleWithUnsafe(ao);
40 if (!success) {
41 try {
42 // unsafe couldn't be found, so try using accessible anyway
43 ao.setAccessible(true);
44 } catch (SecurityException e) {
45 throw new JsonIOException("Gson couldn't modify fields for " + ao
46 + "\nand sun.misc.Unsafe not found.\nEither write a custom type adapter,"
47 + " or make fields accessible, or include sun.misc.Unsafe.", e);
48 }
49 }
50 }
51
52 // Visible for testing only
53 boolean makeAccessibleWithUnsafe(AccessibleObject ao) {
54 if (theUnsafe != null && overrideField != null) {
55 try {
56 Method method = unsafeClass.getMethod("objectFieldOffset", Field.class);
57 long overrideOffset = (Long) method.invoke(theUnsafe, overrideField); // long overrideOffset = theUnsafe.objectFieldOffset(overrideField);
58 Method putBooleanMethod = unsafeClass.getMethod("putBoolean", Object.class, long.class, boolean.class);
59 putBooleanMethod.invoke(theUnsafe, ao, overrideOffset, true); // theUnsafe.putBoolean(ao, overrideOffset, true);
60 return true;
61 } catch (Exception ignored) { // do nothing
62 }
63 }
64 return false;
65 }
66
67 private static Object getUnsafeInstance() {
68 try {
69 unsafeClass = Class.forName("sun.misc.Unsafe");
70 Field unsafeField = unsafeClass.getDeclaredField("theUnsafe");
71 unsafeField.setAccessible(true);
72 return unsafeField.get(null);
73 } catch (Exception e) {
74 return null;
75 }
76 }
77
78 private static Field getOverrideField() {
79 try {
80 return AccessibleObject.class.getDeclaredField("override");
81 } catch (Exception e) {
82 return null;
83 }
84 }
85 }
0 /*
1 * Copyright (C) 2011 Google Inc.
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 package com.google.gson.internal.sql;
17
18 import com.google.gson.Gson;
19 import com.google.gson.JsonSyntaxException;
20 import com.google.gson.TypeAdapter;
21 import com.google.gson.TypeAdapterFactory;
22 import com.google.gson.reflect.TypeToken;
23 import com.google.gson.stream.JsonReader;
24 import com.google.gson.stream.JsonToken;
25 import com.google.gson.stream.JsonWriter;
26 import java.io.IOException;
27 import java.text.DateFormat;
28 import java.text.ParseException;
29 import java.text.SimpleDateFormat;
30 import java.util.Date;
31
32 /**
33 * Adapter for java.sql.Date. Although this class appears stateless, it is not.
34 * DateFormat captures its time zone and locale when it is created, which gives
35 * this class state. DateFormat isn't thread safe either, so this class has
36 * to synchronize its read and write methods.
37 */
38 final class SqlDateTypeAdapter extends TypeAdapter<java.sql.Date> {
39 static final TypeAdapterFactory FACTORY = new TypeAdapterFactory() {
40 @SuppressWarnings("unchecked") // we use a runtime check to make sure the 'T's equal
41 @Override public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) {
42 return typeToken.getRawType() == java.sql.Date.class
43 ? (TypeAdapter<T>) new SqlDateTypeAdapter() : null;
44 }
45 };
46
47 private final DateFormat format = new SimpleDateFormat("MMM d, yyyy");
48
49 private SqlDateTypeAdapter() {
50 }
51
52 @Override
53 public java.sql.Date read(JsonReader in) throws IOException {
54 if (in.peek() == JsonToken.NULL) {
55 in.nextNull();
56 return null;
57 }
58 String s = in.nextString();
59 try {
60 Date utilDate;
61 synchronized (this) {
62 utilDate = format.parse(s);
63 }
64 return new java.sql.Date(utilDate.getTime());
65 } catch (ParseException e) {
66 throw new JsonSyntaxException("Failed parsing '" + s + "' as SQL Date; at path " + in.getPreviousPath(), e);
67 }
68 }
69
70 @Override
71 public void write(JsonWriter out, java.sql.Date value) throws IOException {
72 if (value == null) {
73 out.nullValue();
74 return;
75 }
76 String dateString;
77 synchronized (this) {
78 dateString = format.format(value);
79 }
80 out.value(dateString);
81 }
82 }
0 /*
1 * Copyright (C) 2011 Google Inc.
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 package com.google.gson.internal.sql;
17
18 import com.google.gson.Gson;
19 import com.google.gson.JsonSyntaxException;
20 import com.google.gson.TypeAdapter;
21 import com.google.gson.TypeAdapterFactory;
22 import com.google.gson.reflect.TypeToken;
23 import com.google.gson.stream.JsonReader;
24 import com.google.gson.stream.JsonToken;
25 import com.google.gson.stream.JsonWriter;
26 import java.io.IOException;
27 import java.sql.Time;
28 import java.text.DateFormat;
29 import java.text.ParseException;
30 import java.text.SimpleDateFormat;
31 import java.util.Date;
32
33 /**
34 * Adapter for java.sql.Time. Although this class appears stateless, it is not.
35 * DateFormat captures its time zone and locale when it is created, which gives
36 * this class state. DateFormat isn't thread safe either, so this class has
37 * to synchronize its read and write methods.
38 */
39 final class SqlTimeTypeAdapter extends TypeAdapter<Time> {
40 static final TypeAdapterFactory FACTORY = new TypeAdapterFactory() {
41 @SuppressWarnings("unchecked") // we use a runtime check to make sure the 'T's equal
42 @Override public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) {
43 return typeToken.getRawType() == Time.class ? (TypeAdapter<T>) new SqlTimeTypeAdapter() : null;
44 }
45 };
46
47 private final DateFormat format = new SimpleDateFormat("hh:mm:ss a");
48
49 private SqlTimeTypeAdapter() {
50 }
51
52 @Override public Time read(JsonReader in) throws IOException {
53 if (in.peek() == JsonToken.NULL) {
54 in.nextNull();
55 return null;
56 }
57 String s = in.nextString();
58 try {
59 synchronized (this) {
60 Date date = format.parse(s);
61 return new Time(date.getTime());
62 }
63 } catch (ParseException e) {
64 throw new JsonSyntaxException("Failed parsing '" + s + "' as SQL Time; at path " + in.getPreviousPath(), e);
65 }
66 }
67
68 @Override public void write(JsonWriter out, Time value) throws IOException {
69 if (value == null) {
70 out.nullValue();
71 return;
72 }
73 String timeString;
74 synchronized (this) {
75 timeString = format.format(value);
76 }
77 out.value(timeString);
78 }
79 }
0 package com.google.gson.internal.sql;
1
2 import com.google.gson.Gson;
3 import com.google.gson.TypeAdapter;
4 import com.google.gson.TypeAdapterFactory;
5 import com.google.gson.reflect.TypeToken;
6 import com.google.gson.stream.JsonReader;
7 import com.google.gson.stream.JsonWriter;
8
9 import java.io.IOException;
10 import java.sql.Timestamp;
11 import java.util.Date;
12
13 class SqlTimestampTypeAdapter extends TypeAdapter<Timestamp> {
14 static final TypeAdapterFactory FACTORY = new TypeAdapterFactory() {
15 @SuppressWarnings("unchecked") // we use a runtime check to make sure the 'T's equal
16 @Override public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) {
17 if (typeToken.getRawType() == Timestamp.class) {
18 final TypeAdapter<Date> dateTypeAdapter = gson.getAdapter(Date.class);
19 return (TypeAdapter<T>) new SqlTimestampTypeAdapter(dateTypeAdapter);
20 } else {
21 return null;
22 }
23 }
24 };
25
26 private final TypeAdapter<Date> dateTypeAdapter;
27
28 private SqlTimestampTypeAdapter(TypeAdapter<Date> dateTypeAdapter) {
29 this.dateTypeAdapter = dateTypeAdapter;
30 }
31
32 @Override
33 public Timestamp read(JsonReader in) throws IOException {
34 Date date = dateTypeAdapter.read(in);
35 return date != null ? new Timestamp(date.getTime()) : null;
36 }
37
38 @Override
39 public void write(JsonWriter out, Timestamp value) throws IOException {
40 dateTypeAdapter.write(out, value);
41 }
42 }
0 package com.google.gson.internal.sql;
1
2 import java.sql.Timestamp;
3 import java.util.Date;
4
5 import com.google.gson.TypeAdapterFactory;
6 import com.google.gson.internal.bind.DefaultDateTypeAdapter.DateType;
7
8 /**
9 * Encapsulates access to {@code java.sql} types, to allow Gson to
10 * work without the {@code java.sql} module being present.
11 * No {@link ClassNotFoundException}s will be thrown in case
12 * the {@code java.sql} module is not present.
13 *
14 * <p>If {@link #SUPPORTS_SQL_TYPES} is {@code true}, all other
15 * constants of this class will be non-{@code null}. However, if
16 * it is {@code false} all other constants will be {@code null} and
17 * there will be no support for {@code java.sql} types.
18 */
19 public final class SqlTypesSupport {
20 /**
21 * {@code true} if {@code java.sql} types are supported,
22 * {@code false} otherwise
23 */
24 public static final boolean SUPPORTS_SQL_TYPES;
25
26 public static final DateType<? extends Date> DATE_DATE_TYPE;
27 public static final DateType<? extends Date> TIMESTAMP_DATE_TYPE;
28
29 public static final TypeAdapterFactory DATE_FACTORY;
30 public static final TypeAdapterFactory TIME_FACTORY;
31 public static final TypeAdapterFactory TIMESTAMP_FACTORY;
32
33 static {
34 boolean sqlTypesSupport;
35 try {
36 Class.forName("java.sql.Date");
37 sqlTypesSupport = true;
38 } catch (ClassNotFoundException classNotFoundException) {
39 sqlTypesSupport = false;
40 }
41 SUPPORTS_SQL_TYPES = sqlTypesSupport;
42
43 if (SUPPORTS_SQL_TYPES) {
44 DATE_DATE_TYPE = new DateType<java.sql.Date>(java.sql.Date.class) {
45 @Override protected java.sql.Date deserialize(Date date) {
46 return new java.sql.Date(date.getTime());
47 }
48 };
49 TIMESTAMP_DATE_TYPE = new DateType<Timestamp>(Timestamp.class) {
50 @Override protected Timestamp deserialize(Date date) {
51 return new Timestamp(date.getTime());
52 }
53 };
54
55 DATE_FACTORY = SqlDateTypeAdapter.FACTORY;
56 TIME_FACTORY = SqlTimeTypeAdapter.FACTORY;
57 TIMESTAMP_FACTORY = SqlTimestampTypeAdapter.FACTORY;
58 } else {
59 DATE_DATE_TYPE = null;
60 TIMESTAMP_DATE_TYPE = null;
61
62 DATE_FACTORY = null;
63 TIME_FACTORY = null;
64 TIMESTAMP_FACTORY = null;
65 }
66 }
67
68 private SqlTypesSupport() {
69 }
70 }
169169 * precision loss, extremely large values should be written and read as strings
170170 * in JSON.
171171 *
172 * <a id="nonexecuteprefix"/><h3>Non-Execute Prefix</h3>
172 * <h3 id="nonexecuteprefix">Non-Execute Prefix</h3>
173173 * Web servers that serve private data using JSON may be vulnerable to <a
174174 * href="http://en.wikipedia.org/wiki/JSON#Cross-site_request_forgery">Cross-site
175175 * request forgery</a> attacks. In such an attack, a malicious site gains access
227227 /** True to accept non-spec compliant JSON */
228228 private boolean lenient = false;
229229
230 static final int BUFFER_SIZE = 1024;
230231 /**
231232 * Use a manual buffer to easily read and unread upcoming characters, and
232233 * also so we can create strings without an intermediate StringBuilder.
233234 * We decode literals directly out of this buffer, so it must be at least as
234235 * long as the longest token that can be reported as a number.
235236 */
236 private final char[] buffer = new char[1024];
237 private final char[] buffer = new char[BUFFER_SIZE];
237238 private int pos = 0;
238239 private int limit = 0;
239240
411412 if (p == PEEKED_NONE) {
412413 p = doPeek();
413414 }
414 return p != PEEKED_END_OBJECT && p != PEEKED_END_ARRAY;
415 return p != PEEKED_END_OBJECT && p != PEEKED_END_ARRAY && p != PEEKED_EOF;
415416 }
416417
417418 /**
10841085 break;
10851086 }
10861087 }
1087
1088
10881089 String result = (null == builder) ? new String(buffer, pos, i) : builder.append(buffer, pos, i).toString();
10891090 pos += i;
10901091 return result;
14531454 return " at line " + line + " column " + column + " path " + getPath();
14541455 }
14551456
1456 /**
1457 * Returns a <a href="http://goessner.net/articles/JsonPath/">JsonPath</a> to
1458 * the current location in the JSON value.
1459 */
1460 public String getPath() {
1457 private String getPath(boolean usePreviousPath) {
14611458 StringBuilder result = new StringBuilder().append('$');
1462 for (int i = 0, size = stackSize; i < size; i++) {
1459 for (int i = 0; i < stackSize; i++) {
14631460 switch (stack[i]) {
14641461 case JsonScope.EMPTY_ARRAY:
14651462 case JsonScope.NONEMPTY_ARRAY:
1466 result.append('[').append(pathIndices[i]).append(']');
1463 int pathIndex = pathIndices[i];
1464 // If index is last path element it points to next array element; have to decrement
1465 if (usePreviousPath && pathIndex > 0 && i == stackSize - 1) {
1466 pathIndex--;
1467 }
1468 result.append('[').append(pathIndex).append(']');
14671469 break;
1468
14691470 case JsonScope.EMPTY_OBJECT:
14701471 case JsonScope.DANGLING_NAME:
14711472 case JsonScope.NONEMPTY_OBJECT:
14741475 result.append(pathNames[i]);
14751476 }
14761477 break;
1477
14781478 case JsonScope.NONEMPTY_DOCUMENT:
14791479 case JsonScope.EMPTY_DOCUMENT:
14801480 case JsonScope.CLOSED:
14821482 }
14831483 }
14841484 return result.toString();
1485 }
1486
1487 /**
1488 * Returns a <a href="https://goessner.net/articles/JsonPath/">JsonPath</a>
1489 * in <i>dot-notation</i> to the previous (or current) location in the JSON document:
1490 * <ul>
1491 * <li>For JSON arrays the path points to the index of the previous element.<br>
1492 * If no element has been consumed yet it uses the index 0 (even if there are no elements).</li>
1493 * <li>For JSON objects the path points to the last property, or to the current
1494 * property if its value has not been consumed yet.</li>
1495 * </ul>
1496 *
1497 * <p>This method can be useful to add additional context to exception messages
1498 * <i>after</i> a value has been consumed.
1499 */
1500 public String getPreviousPath() {
1501 return getPath(true);
1502 }
1503
1504 /**
1505 * Returns a <a href="https://goessner.net/articles/JsonPath/">JsonPath</a>
1506 * in <i>dot-notation</i> to the next (or current) location in the JSON document:
1507 * <ul>
1508 * <li>For JSON arrays the path points to the index of the next element (even
1509 * if there are no further elements).</li>
1510 * <li>For JSON objects the path points to the last property, or to the current
1511 * property if its value has not been consumed yet.</li>
1512 * </ul>
1513 *
1514 * <p>This method can be useful to add additional context to exception messages
1515 * <i>before</i> a value is consumed, for example when the {@linkplain #peek() peeked}
1516 * token is unexpected.
1517 */
1518 public String getPath() {
1519 return getPath(false);
14851520 }
14861521
14871522 /**
15451580 case '\'':
15461581 case '"':
15471582 case '\\':
1548 case '/':
1549 return escaped;
1583 case '/':
1584 return escaped;
15501585 default:
1551 // throw error when none of the above cases are matched
1552 throw syntaxError("Invalid escape sequence");
1586 // throw error when none of the above cases are matched
1587 throw syntaxError("Invalid escape sequence");
15531588 }
15541589 }
15551590
15691604 nextNonWhitespace(true);
15701605 pos--;
15711606
1607 if (pos + 5 > limit && !fillBuffer(5)) {
1608 return;
1609 }
1610
15721611 int p = pos;
1573 if (p + 5 > limit && !fillBuffer(5)) {
1574 return;
1575 }
1576
15771612 char[] buf = buffer;
15781613 if(buf[p] != ')' || buf[p + 1] != ']' || buf[p + 2] != '}' || buf[p + 3] != '\'' || buf[p + 4] != '\n') {
15791614 return; // not a security token!
1919 import java.io.Flushable;
2020 import java.io.IOException;
2121 import java.io.Writer;
22 import java.math.BigDecimal;
23 import java.math.BigInteger;
2224 import java.util.Arrays;
25 import java.util.concurrent.atomic.AtomicInteger;
26 import java.util.concurrent.atomic.AtomicLong;
27 import java.util.regex.Pattern;
2328
2429 import static com.google.gson.stream.JsonScope.DANGLING_NAME;
2530 import static com.google.gson.stream.JsonScope.EMPTY_ARRAY;
129134 */
130135 public class JsonWriter implements Closeable, Flushable {
131136
137 // Syntax as defined by https://datatracker.ietf.org/doc/html/rfc8259#section-6
138 private static final Pattern VALID_JSON_NUMBER_PATTERN = Pattern.compile("-?(?:0|[1-9][0-9]*)(?:\\.[0-9]+)?(?:[eE][-+]?[0-9]+)?");
139
132140 /*
133141 * From RFC 7159, "All Unicode characters may be placed within the
134142 * quotation marks except for the characters that must be escaped:
487495 * @param value a finite value. May not be {@link Double#isNaN() NaNs} or
488496 * {@link Double#isInfinite() infinities}.
489497 * @return this writer.
498 * @throws IllegalArgumentException if the value is NaN or Infinity and this writer is
499 * not {@link #setLenient(boolean) lenient}.
490500 */
491501 public JsonWriter value(double value) throws IOException {
492502 writeDeferredName();
511521 }
512522
513523 /**
514 * Encodes {@code value}.
524 * Returns whether the {@code toString()} of {@code c} can be trusted to return
525 * a valid JSON number.
526 */
527 private static boolean isTrustedNumberType(Class<? extends Number> c) {
528 // Note: Don't consider LazilyParsedNumber trusted because it could contain
529 // an arbitrary malformed string
530 return c == Integer.class || c == Long.class || c == Double.class || c == Float.class || c == Byte.class || c == Short.class
531 || c == BigDecimal.class || c == BigInteger.class || c == AtomicInteger.class || c == AtomicLong.class;
532 }
533
534 /**
535 * Encodes {@code value}. The value is written by directly writing the {@link Number#toString()}
536 * result to JSON. Implementations must make sure that the result represents a valid JSON number.
515537 *
516538 * @param value a finite value. May not be {@link Double#isNaN() NaNs} or
517539 * {@link Double#isInfinite() infinities}.
518540 * @return this writer.
541 * @throws IllegalArgumentException if the value is NaN or Infinity and this writer is
542 * not {@link #setLenient(boolean) lenient}; or if the {@code toString()} result is not a
543 * valid JSON number.
519544 */
520545 public JsonWriter value(Number value) throws IOException {
521546 if (value == null) {
524549
525550 writeDeferredName();
526551 String string = value.toString();
527 if (!lenient
528 && (string.equals("-Infinity") || string.equals("Infinity") || string.equals("NaN"))) {
529 throw new IllegalArgumentException("Numeric values must be finite, but was " + value);
530 }
552 if (string.equals("-Infinity") || string.equals("Infinity") || string.equals("NaN")) {
553 if (!lenient) {
554 throw new IllegalArgumentException("Numeric values must be finite, but was " + string);
555 }
556 } else {
557 Class<? extends Number> numberClass = value.getClass();
558 // Validate that string is valid before writing it directly to JSON output
559 if (!isTrustedNumberType(numberClass) && !VALID_JSON_NUMBER_PATTERN.matcher(string).matches()) {
560 throw new IllegalArgumentException("String created by " + numberClass + " is not a valid JSON number: " + string);
561 }
562 }
563
531564 beforeValue();
532565 out.append(string);
533566 return this;
2929 }
3030
3131 public MalformedJsonException(String msg, Throwable throwable) {
32 super(msg);
33 // Using initCause() instead of calling super() because Java 1.5 didn't retrofit IOException
34 // with a constructor with Throwable. This was done in Java 1.6
35 initCause(throwable);
32 super(msg, throwable);
3633 }
3734
3835 public MalformedJsonException(Throwable throwable) {
39 // Using initCause() instead of calling super() because Java 1.5 didn't retrofit IOException
40 // with a constructor with Throwable. This was done in Java 1.6
41 initCause(throwable);
36 super(throwable);
4237 }
4338 }
0 /**
1 * This package provides classes for processing JSON in an efficient streaming way.
2 */
3 package com.google.gson.stream;
77 exports com.google.gson.reflect;
88 exports com.google.gson.stream;
99
10 requires transitive java.sql;
10 // Optional dependency on java.sql
11 requires static java.sql;
12
13 // Optional dependency on jdk.unsupported for JDK's sun.misc.Unsafe
14 requires static jdk.unsupported;
1115 }
+0
-205
gson/src/test/java/com/google/gson/DefaultDateTypeAdapterTest.java less more
0 /*
1 * Copyright (C) 2008 Google Inc.
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 package com.google.gson;
17
18 import java.io.IOException;
19 import java.text.DateFormat;
20 import java.text.SimpleDateFormat;
21 import java.util.Date;
22 import java.util.Locale;
23 import java.util.TimeZone;
24
25 import com.google.gson.internal.JavaVersion;
26
27 import junit.framework.TestCase;
28
29 /**
30 * A simple unit test for the {@link DefaultDateTypeAdapter} class.
31 *
32 * @author Joel Leitch
33 */
34 public class DefaultDateTypeAdapterTest extends TestCase {
35
36 public void testFormattingInEnUs() {
37 assertFormattingAlwaysEmitsUsLocale(Locale.US);
38 }
39
40 public void testFormattingInFr() {
41 assertFormattingAlwaysEmitsUsLocale(Locale.FRANCE);
42 }
43
44 private void assertFormattingAlwaysEmitsUsLocale(Locale locale) {
45 TimeZone defaultTimeZone = TimeZone.getDefault();
46 TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
47 Locale defaultLocale = Locale.getDefault();
48 Locale.setDefault(locale);
49 try {
50 String afterYearSep = JavaVersion.isJava9OrLater() ? ", " : " ";
51 String afterYearLongSep = JavaVersion.isJava9OrLater() ? " at " : " ";
52 String utcFull = JavaVersion.isJava9OrLater() ? "Coordinated Universal Time" : "UTC";
53 assertFormatted(String.format("Jan 1, 1970%s12:00:00 AM", afterYearSep),
54 new DefaultDateTypeAdapter(Date.class));
55 assertFormatted("1/1/70", new DefaultDateTypeAdapter(Date.class, DateFormat.SHORT));
56 assertFormatted("Jan 1, 1970", new DefaultDateTypeAdapter(Date.class, DateFormat.MEDIUM));
57 assertFormatted("January 1, 1970", new DefaultDateTypeAdapter(Date.class, DateFormat.LONG));
58 assertFormatted(String.format("1/1/70%s12:00 AM", afterYearSep),
59 new DefaultDateTypeAdapter(DateFormat.SHORT, DateFormat.SHORT));
60 assertFormatted(String.format("Jan 1, 1970%s12:00:00 AM", afterYearSep),
61 new DefaultDateTypeAdapter(DateFormat.MEDIUM, DateFormat.MEDIUM));
62 assertFormatted(String.format("January 1, 1970%s12:00:00 AM UTC", afterYearLongSep),
63 new DefaultDateTypeAdapter(DateFormat.LONG, DateFormat.LONG));
64 assertFormatted(String.format("Thursday, January 1, 1970%s12:00:00 AM %s", afterYearLongSep, utcFull),
65 new DefaultDateTypeAdapter(DateFormat.FULL, DateFormat.FULL));
66 } finally {
67 TimeZone.setDefault(defaultTimeZone);
68 Locale.setDefault(defaultLocale);
69 }
70 }
71
72 public void testParsingDatesFormattedWithSystemLocale() throws Exception {
73 TimeZone defaultTimeZone = TimeZone.getDefault();
74 TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
75 Locale defaultLocale = Locale.getDefault();
76 Locale.setDefault(Locale.FRANCE);
77 try {
78 String afterYearSep = JavaVersion.isJava9OrLater() ? " à " : " ";
79 assertParsed(String.format("1 janv. 1970%s00:00:00", afterYearSep),
80 new DefaultDateTypeAdapter(Date.class));
81 assertParsed("01/01/70", new DefaultDateTypeAdapter(Date.class, DateFormat.SHORT));
82 assertParsed("1 janv. 1970", new DefaultDateTypeAdapter(Date.class, DateFormat.MEDIUM));
83 assertParsed("1 janvier 1970", new DefaultDateTypeAdapter(Date.class, DateFormat.LONG));
84 assertParsed("01/01/70 00:00",
85 new DefaultDateTypeAdapter(DateFormat.SHORT, DateFormat.SHORT));
86 assertParsed(String.format("1 janv. 1970%s00:00:00", afterYearSep),
87 new DefaultDateTypeAdapter(DateFormat.MEDIUM, DateFormat.MEDIUM));
88 assertParsed(String.format("1 janvier 1970%s00:00:00 UTC", afterYearSep),
89 new DefaultDateTypeAdapter(DateFormat.LONG, DateFormat.LONG));
90 assertParsed(JavaVersion.isJava9OrLater() ? (JavaVersion.getMajorJavaVersion() <11 ?
91 "jeudi 1 janvier 1970 à 00:00:00 Coordinated Universal Time" :
92 "jeudi 1 janvier 1970 à 00:00:00 Temps universel coordonné") :
93 "jeudi 1 janvier 1970 00 h 00 UTC",
94 new DefaultDateTypeAdapter(DateFormat.FULL, DateFormat.FULL));
95 } finally {
96 TimeZone.setDefault(defaultTimeZone);
97 Locale.setDefault(defaultLocale);
98 }
99 }
100
101 public void testParsingDatesFormattedWithUsLocale() throws Exception {
102 TimeZone defaultTimeZone = TimeZone.getDefault();
103 TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
104 Locale defaultLocale = Locale.getDefault();
105 Locale.setDefault(Locale.US);
106 try {
107 assertParsed("Jan 1, 1970 0:00:00 AM", new DefaultDateTypeAdapter(Date.class));
108 assertParsed("1/1/70", new DefaultDateTypeAdapter(Date.class, DateFormat.SHORT));
109 assertParsed("Jan 1, 1970", new DefaultDateTypeAdapter(Date.class, DateFormat.MEDIUM));
110 assertParsed("January 1, 1970", new DefaultDateTypeAdapter(Date.class, DateFormat.LONG));
111 assertParsed("1/1/70 0:00 AM",
112 new DefaultDateTypeAdapter(DateFormat.SHORT, DateFormat.SHORT));
113 assertParsed("Jan 1, 1970 0:00:00 AM",
114 new DefaultDateTypeAdapter(DateFormat.MEDIUM, DateFormat.MEDIUM));
115 assertParsed("January 1, 1970 0:00:00 AM UTC",
116 new DefaultDateTypeAdapter(DateFormat.LONG, DateFormat.LONG));
117 assertParsed("Thursday, January 1, 1970 0:00:00 AM UTC",
118 new DefaultDateTypeAdapter(DateFormat.FULL, DateFormat.FULL));
119 } finally {
120 TimeZone.setDefault(defaultTimeZone);
121 Locale.setDefault(defaultLocale);
122 }
123 }
124
125 public void testFormatUsesDefaultTimezone() throws Exception {
126 TimeZone defaultTimeZone = TimeZone.getDefault();
127 TimeZone.setDefault(TimeZone.getTimeZone("America/Los_Angeles"));
128 Locale defaultLocale = Locale.getDefault();
129 Locale.setDefault(Locale.US);
130 try {
131 String afterYearSep = JavaVersion.isJava9OrLater() ? ", " : " ";
132 assertFormatted(String.format("Dec 31, 1969%s4:00:00 PM", afterYearSep),
133 new DefaultDateTypeAdapter(Date.class));
134 assertParsed("Dec 31, 1969 4:00:00 PM", new DefaultDateTypeAdapter(Date.class));
135 } finally {
136 TimeZone.setDefault(defaultTimeZone);
137 Locale.setDefault(defaultLocale);
138 }
139 }
140
141 public void testDateDeserializationISO8601() throws Exception {
142 DefaultDateTypeAdapter adapter = new DefaultDateTypeAdapter(Date.class);
143 assertParsed("1970-01-01T00:00:00.000Z", adapter);
144 assertParsed("1970-01-01T00:00Z", adapter);
145 assertParsed("1970-01-01T00:00:00+00:00", adapter);
146 assertParsed("1970-01-01T01:00:00+01:00", adapter);
147 assertParsed("1970-01-01T01:00:00+01", adapter);
148 }
149
150 public void testDateSerialization() throws Exception {
151 int dateStyle = DateFormat.LONG;
152 DefaultDateTypeAdapter dateTypeAdapter = new DefaultDateTypeAdapter(Date.class, dateStyle);
153 DateFormat formatter = DateFormat.getDateInstance(dateStyle, Locale.US);
154 Date currentDate = new Date();
155
156 String dateString = dateTypeAdapter.toJson(currentDate);
157 assertEquals(toLiteral(formatter.format(currentDate)), dateString);
158 }
159
160 public void testDatePattern() throws Exception {
161 String pattern = "yyyy-MM-dd";
162 DefaultDateTypeAdapter dateTypeAdapter = new DefaultDateTypeAdapter(Date.class, pattern);
163 DateFormat formatter = new SimpleDateFormat(pattern);
164 Date currentDate = new Date();
165
166 String dateString = dateTypeAdapter.toJson(currentDate);
167 assertEquals(toLiteral(formatter.format(currentDate)), dateString);
168 }
169
170 @SuppressWarnings("unused")
171 public void testInvalidDatePattern() throws Exception {
172 try {
173 new DefaultDateTypeAdapter(Date.class, "I am a bad Date pattern....");
174 fail("Invalid date pattern should fail.");
175 } catch (IllegalArgumentException expected) { }
176 }
177
178 public void testNullValue() throws Exception {
179 DefaultDateTypeAdapter adapter = new DefaultDateTypeAdapter(Date.class);
180 assertNull(adapter.fromJson("null"));
181 assertEquals("null", adapter.toJson(null));
182 }
183
184 public void testUnexpectedToken() throws Exception {
185 try {
186 DefaultDateTypeAdapter adapter = new DefaultDateTypeAdapter(Date.class);
187 adapter.fromJson("{}");
188 fail("Unexpected token should fail.");
189 } catch (IllegalStateException expected) { }
190 }
191
192 private void assertFormatted(String formatted, DefaultDateTypeAdapter adapter) {
193 assertEquals(toLiteral(formatted), adapter.toJson(new Date(0)));
194 }
195
196 private void assertParsed(String date, DefaultDateTypeAdapter adapter) throws IOException {
197 assertEquals(date, new Date(0), adapter.fromJson(toLiteral(date)));
198 assertEquals("ISO 8601", new Date(0), adapter.fromJson(toLiteral("1970-01-01T00:00:00Z")));
199 }
200
201 private static String toLiteral(String s) {
202 return '"' + s + '"';
203 }
204 }
0 package com.google.gson;
1
2 import static org.junit.Assert.assertEquals;
3 import static org.junit.Assert.assertNotEquals;
4 import java.lang.reflect.Field;
5 import java.util.Locale;
6 import org.junit.Test;
7 import com.google.gson.functional.FieldNamingTest;
8
9 /**
10 * Performs tests directly against {@link FieldNamingPolicy}; for integration tests
11 * see {@link FieldNamingTest}.
12 */
13 public class FieldNamingPolicyTest {
14 @Test
15 public void testSeparateCamelCase() {
16 // Map from original -> expected
17 String[][] argumentPairs = {
18 { "a", "a" },
19 { "ab", "ab" },
20 { "Ab", "Ab" },
21 { "aB", "a_B" },
22 { "AB", "A_B" },
23 { "A_B", "A__B" },
24 { "firstSecondThird", "first_Second_Third" },
25 { "__", "__" },
26 { "_123", "_123" }
27 };
28
29 for (String[] pair : argumentPairs) {
30 assertEquals(pair[1], FieldNamingPolicy.separateCamelCase(pair[0], '_'));
31 }
32 }
33
34 @Test
35 public void testUpperCaseFirstLetter() {
36 // Map from original -> expected
37 String[][] argumentPairs = {
38 { "a", "A" },
39 { "ab", "Ab" },
40 { "AB", "AB" },
41 { "_a", "_A" },
42 { "_ab", "_Ab" },
43 { "__", "__" },
44 { "_1", "_1" },
45 // Not a letter, but has uppercase variant (should not be uppercased)
46 // See https://github.com/google/gson/issues/1965
47 { "\u2170", "\u2170" },
48 { "_\u2170", "_\u2170" },
49 { "\u2170a", "\u2170A" },
50 };
51
52 for (String[] pair : argumentPairs) {
53 assertEquals(pair[1], FieldNamingPolicy.upperCaseFirstLetter(pair[0]));
54 }
55 }
56
57 /**
58 * Upper casing policies should be unaffected by default Locale.
59 */
60 @Test
61 public void testUpperCasingLocaleIndependent() throws Exception {
62 class Dummy {
63 @SuppressWarnings("unused")
64 int i;
65 }
66
67 FieldNamingPolicy[] policies = {
68 FieldNamingPolicy.UPPER_CAMEL_CASE,
69 FieldNamingPolicy.UPPER_CAMEL_CASE_WITH_SPACES,
70 FieldNamingPolicy.UPPER_CASE_WITH_UNDERSCORES,
71 };
72
73 Field field = Dummy.class.getDeclaredField("i");
74 String name = field.getName();
75 String expected = name.toUpperCase(Locale.ROOT);
76
77 Locale oldLocale = Locale.getDefault();
78 // Set Turkish as Locale which has special case conversion rules
79 Locale.setDefault(new Locale("tr"));
80
81 try {
82 // Verify that default Locale has different case conversion rules
83 assertNotEquals("Test setup is broken", expected, name.toUpperCase());
84
85 for (FieldNamingPolicy policy : policies) {
86 // Should ignore default Locale
87 assertEquals("Unexpected conversion for " + policy, expected, policy.translateName(field));
88 }
89 } finally {
90 Locale.setDefault(oldLocale);
91 }
92 }
93
94 /**
95 * Lower casing policies should be unaffected by default Locale.
96 */
97 @Test
98 public void testLowerCasingLocaleIndependent() throws Exception {
99 class Dummy {
100 @SuppressWarnings("unused")
101 int I;
102 }
103
104 FieldNamingPolicy[] policies = {
105 FieldNamingPolicy.LOWER_CASE_WITH_DASHES,
106 FieldNamingPolicy.LOWER_CASE_WITH_DOTS,
107 FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES,
108 };
109
110 Field field = Dummy.class.getDeclaredField("I");
111 String name = field.getName();
112 String expected = name.toLowerCase(Locale.ROOT);
113
114 Locale oldLocale = Locale.getDefault();
115 // Set Turkish as Locale which has special case conversion rules
116 Locale.setDefault(new Locale("tr"));
117
118 try {
119 // Verify that default Locale has different case conversion rules
120 assertNotEquals("Test setup is broken", expected, name.toLowerCase());
121
122 for (FieldNamingPolicy policy : policies) {
123 // Should ignore default Locale
124 assertEquals("Unexpected conversion for " + policy, expected, policy.translateName(field));
125 }
126 } finally {
127 Locale.setDefault(oldLocale);
128 }
129 }
130 }
8383 static class HasTransients {
8484 transient String a = "a";
8585 }
86
87 public void testDisableJdkUnsafe() {
88 Gson gson = new GsonBuilder()
89 .disableJdkUnsafe()
90 .create();
91 try {
92 gson.fromJson("{}", ClassWithoutNoArgsConstructor.class);
93 fail("Expected exception");
94 } catch (JsonIOException expected) {
95 assertEquals(
96 "Unable to create instance of class com.google.gson.GsonBuilderTest$ClassWithoutNoArgsConstructor; "
97 + "usage of JDK Unsafe is disabled. Registering an InstanceCreator or a TypeAdapter for this type, "
98 + "adding a no-args constructor, or enabling usage of JDK Unsafe may fix this problem.",
99 expected.getMessage()
100 );
101 }
102 }
103
104 private static class ClassWithoutNoArgsConstructor {
105 @SuppressWarnings("unused")
106 public ClassWithoutNoArgsConstructor(String s) {
107 }
108 }
86109 }
1818 import com.google.gson.internal.Excluder;
1919 import com.google.gson.stream.JsonReader;
2020 import com.google.gson.stream.JsonWriter;
21 import com.google.gson.stream.MalformedJsonException;
2122 import java.io.IOException;
23 import java.io.StringReader;
24 import java.io.StringWriter;
2225 import java.lang.reflect.Field;
2326 import java.lang.reflect.Type;
2427 import java.text.DateFormat;
4346 }
4447 };
4548
49 private static final ToNumberStrategy CUSTOM_OBJECT_TO_NUMBER_STRATEGY = ToNumberPolicy.DOUBLE;
50 private static final ToNumberStrategy CUSTOM_NUMBER_TO_NUMBER_STRATEGY = ToNumberPolicy.LAZILY_PARSED_NUMBER;
51
4652 public void testOverridesDefaultExcluder() {
4753 Gson gson = new Gson(CUSTOM_EXCLUDER, CUSTOM_FIELD_NAMING_STRATEGY,
4854 new HashMap<Type, InstanceCreator<?>>(), true, false, true, false,
49 true, true, false, LongSerializationPolicy.DEFAULT, null, DateFormat.DEFAULT,
55 true, true, false, true, LongSerializationPolicy.DEFAULT, null, DateFormat.DEFAULT,
5056 DateFormat.DEFAULT, new ArrayList<TypeAdapterFactory>(),
51 new ArrayList<TypeAdapterFactory>(), new ArrayList<TypeAdapterFactory>());
57 new ArrayList<TypeAdapterFactory>(), new ArrayList<TypeAdapterFactory>(),
58 CUSTOM_OBJECT_TO_NUMBER_STRATEGY, CUSTOM_NUMBER_TO_NUMBER_STRATEGY);
5259
53 assertEquals(CUSTOM_EXCLUDER, gson.excluder());
60 assertEquals(CUSTOM_EXCLUDER, gson.excluder);
5461 assertEquals(CUSTOM_FIELD_NAMING_STRATEGY, gson.fieldNamingStrategy());
5562 assertEquals(true, gson.serializeNulls());
5663 assertEquals(false, gson.htmlSafe());
5966 public void testClonedTypeAdapterFactoryListsAreIndependent() {
6067 Gson original = new Gson(CUSTOM_EXCLUDER, CUSTOM_FIELD_NAMING_STRATEGY,
6168 new HashMap<Type, InstanceCreator<?>>(), true, false, true, false,
62 true, true, false, LongSerializationPolicy.DEFAULT, null, DateFormat.DEFAULT,
69 true, true, false, true, LongSerializationPolicy.DEFAULT, null, DateFormat.DEFAULT,
6370 DateFormat.DEFAULT, new ArrayList<TypeAdapterFactory>(),
64 new ArrayList<TypeAdapterFactory>(), new ArrayList<TypeAdapterFactory>());
71 new ArrayList<TypeAdapterFactory>(), new ArrayList<TypeAdapterFactory>(),
72 CUSTOM_OBJECT_TO_NUMBER_STRATEGY, CUSTOM_NUMBER_TO_NUMBER_STRATEGY);
6573
6674 Gson clone = original.newBuilder()
6775 .registerTypeAdapter(Object.class, new TestTypeAdapter())
7684 }
7785 @Override public Object read(JsonReader in) throws IOException { return null; }
7886 }
87
88 public void testNewJsonWriter_Default() throws IOException {
89 StringWriter writer = new StringWriter();
90 JsonWriter jsonWriter = new Gson().newJsonWriter(writer);
91 jsonWriter.beginObject();
92 jsonWriter.name("test");
93 jsonWriter.nullValue();
94 jsonWriter.name("<test2");
95 jsonWriter.value(true);
96 jsonWriter.endObject();
97
98 try {
99 // Additional top-level value
100 jsonWriter.value(1);
101 fail();
102 } catch (IllegalStateException expected) {
103 assertEquals("JSON must have only one top-level value.", expected.getMessage());
104 }
105
106 jsonWriter.close();
107 assertEquals("{\"\\u003ctest2\":true}", writer.toString());
108 }
109
110 public void testNewJsonWriter_Custom() throws IOException {
111 StringWriter writer = new StringWriter();
112 JsonWriter jsonWriter = new GsonBuilder()
113 .disableHtmlEscaping()
114 .generateNonExecutableJson()
115 .setPrettyPrinting()
116 .serializeNulls()
117 .setLenient()
118 .create()
119 .newJsonWriter(writer);
120 jsonWriter.beginObject();
121 jsonWriter.name("test");
122 jsonWriter.nullValue();
123 jsonWriter.name("<test2");
124 jsonWriter.value(true);
125 jsonWriter.endObject();
126
127 // Additional top-level value
128 jsonWriter.value(1);
129
130 jsonWriter.close();
131 assertEquals(")]}'\n{\n \"test\": null,\n \"<test2\": true\n}1", writer.toString());
132 }
133
134 public void testNewJsonReader_Default() throws IOException {
135 String json = "test"; // String without quotes
136 JsonReader jsonReader = new Gson().newJsonReader(new StringReader(json));
137 try {
138 jsonReader.nextString();
139 fail();
140 } catch (MalformedJsonException expected) {
141 }
142 jsonReader.close();
143 }
144
145 public void testNewJsonReader_Custom() throws IOException {
146 String json = "test"; // String without quotes
147 JsonReader jsonReader = new GsonBuilder()
148 .setLenient()
149 .create()
150 .newJsonReader(new StringReader(json));
151 assertEquals("test", jsonReader.nextString());
152 jsonReader.close();
153 }
79154 }
103103 JsonElement jsonElement = jsonObj.get(propertyName);
104104 assertNotNull(jsonElement);
105105 assertEquals(String.valueOf(value), jsonElement.getAsString());
106 assertEquals(value, jsonElement.getAsCharacter());
106
107 @SuppressWarnings("deprecation")
108 char character = jsonElement.getAsCharacter();
109 assertEquals(value, character);
107110 }
108111
109112 /**
2828 public void testDefaultLongSerialization() throws Exception {
2929 JsonElement element = LongSerializationPolicy.DEFAULT.serialize(1556L);
3030 assertTrue(element.isJsonPrimitive());
31
31
3232 JsonPrimitive jsonPrimitive = element.getAsJsonPrimitive();
3333 assertFalse(jsonPrimitive.isString());
3434 assertTrue(jsonPrimitive.isNumber());
3535 assertEquals(1556L, element.getAsLong());
3636 }
37
37
3838 public void testDefaultLongSerializationIntegration() {
3939 Gson gson = new GsonBuilder()
40 .setLongSerializationPolicy(LongSerializationPolicy.DEFAULT)
41 .create();
40 .setLongSerializationPolicy(LongSerializationPolicy.DEFAULT)
41 .create();
4242 assertEquals("[1]", gson.toJson(new long[] { 1L }, long[].class));
4343 assertEquals("[1]", gson.toJson(new Long[] { 1L }, Long[].class));
44 }
45
46 public void testDefaultLongSerializationNull() {
47 LongSerializationPolicy policy = LongSerializationPolicy.DEFAULT;
48 assertTrue(policy.serialize(null).isJsonNull());
49
50 Gson gson = new GsonBuilder()
51 .setLongSerializationPolicy(policy)
52 .create();
53 assertEquals("null", gson.toJson(null, Long.class));
4454 }
4555
4656 public void testStringLongSerialization() throws Exception {
5565
5666 public void testStringLongSerializationIntegration() {
5767 Gson gson = new GsonBuilder()
58 .setLongSerializationPolicy(LongSerializationPolicy.STRING)
59 .create();
68 .setLongSerializationPolicy(LongSerializationPolicy.STRING)
69 .create();
6070 assertEquals("[\"1\"]", gson.toJson(new long[] { 1L }, long[].class));
6171 assertEquals("[\"1\"]", gson.toJson(new Long[] { 1L }, Long[].class));
6272 }
73
74 public void testStringLongSerializationNull() {
75 LongSerializationPolicy policy = LongSerializationPolicy.STRING;
76 assertTrue(policy.serialize(null).isJsonNull());
77
78 Gson gson = new GsonBuilder()
79 .setLongSerializationPolicy(policy)
80 .create();
81 assertEquals("null", gson.toJson(null, Long.class));
82 }
6383 }
0 /*
1 * Copyright (C) 2021 Google Inc.
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 package com.google.gson;
17
18 import java.io.IOException;
19 import java.io.StringReader;
20 import java.math.BigDecimal;
21 import com.google.gson.internal.LazilyParsedNumber;
22 import com.google.gson.stream.JsonReader;
23 import com.google.gson.stream.MalformedJsonException;
24 import junit.framework.TestCase;
25
26 public class ToNumberPolicyTest extends TestCase {
27 public void testDouble() throws IOException {
28 ToNumberStrategy strategy = ToNumberPolicy.DOUBLE;
29 assertEquals(10.1, strategy.readNumber(fromString("10.1")));
30 assertEquals(3.141592653589793D, strategy.readNumber(fromString("3.141592653589793238462643383279")));
31 try {
32 strategy.readNumber(fromString("1e400"));
33 fail();
34 } catch (MalformedJsonException expected) {
35 assertEquals("JSON forbids NaN and infinities: Infinity at line 1 column 6 path $", expected.getMessage());
36 }
37 try {
38 strategy.readNumber(fromString("\"not-a-number\""));
39 fail();
40 } catch (NumberFormatException expected) {
41 }
42 }
43
44 public void testLazilyParsedNumber() throws IOException {
45 ToNumberStrategy strategy = ToNumberPolicy.LAZILY_PARSED_NUMBER;
46 assertEquals(new LazilyParsedNumber("10.1"), strategy.readNumber(fromString("10.1")));
47 assertEquals(new LazilyParsedNumber("3.141592653589793238462643383279"), strategy.readNumber(fromString("3.141592653589793238462643383279")));
48 assertEquals(new LazilyParsedNumber("1e400"), strategy.readNumber(fromString("1e400")));
49 }
50
51 public void testLongOrDouble() throws IOException {
52 ToNumberStrategy strategy = ToNumberPolicy.LONG_OR_DOUBLE;
53 assertEquals(10L, strategy.readNumber(fromString("10")));
54 assertEquals(10.1, strategy.readNumber(fromString("10.1")));
55 assertEquals(3.141592653589793D, strategy.readNumber(fromString("3.141592653589793238462643383279")));
56 try {
57 strategy.readNumber(fromString("1e400"));
58 fail();
59 } catch (MalformedJsonException expected) {
60 assertEquals("JSON forbids NaN and infinities: Infinity; at path $", expected.getMessage());
61 }
62 try {
63 strategy.readNumber(fromString("\"not-a-number\""));
64 fail();
65 } catch (JsonParseException expected) {
66 assertEquals("Cannot parse not-a-number; at path $", expected.getMessage());
67 }
68
69 assertEquals(Double.NaN, strategy.readNumber(fromStringLenient("NaN")));
70 assertEquals(Double.POSITIVE_INFINITY, strategy.readNumber(fromStringLenient("Infinity")));
71 assertEquals(Double.NEGATIVE_INFINITY, strategy.readNumber(fromStringLenient("-Infinity")));
72 try {
73 strategy.readNumber(fromString("NaN"));
74 fail();
75 } catch (MalformedJsonException expected) {
76 assertEquals("Use JsonReader.setLenient(true) to accept malformed JSON at line 1 column 1 path $", expected.getMessage());
77 }
78 try {
79 strategy.readNumber(fromString("Infinity"));
80 fail();
81 } catch (MalformedJsonException expected) {
82 assertEquals("Use JsonReader.setLenient(true) to accept malformed JSON at line 1 column 1 path $", expected.getMessage());
83 }
84 try {
85 strategy.readNumber(fromString("-Infinity"));
86 fail();
87 } catch (MalformedJsonException expected) {
88 assertEquals("Use JsonReader.setLenient(true) to accept malformed JSON at line 1 column 1 path $", expected.getMessage());
89 }
90 }
91
92 public void testBigDecimal() throws IOException {
93 ToNumberStrategy strategy = ToNumberPolicy.BIG_DECIMAL;
94 assertEquals(new BigDecimal("10.1"), strategy.readNumber(fromString("10.1")));
95 assertEquals(new BigDecimal("3.141592653589793238462643383279"), strategy.readNumber(fromString("3.141592653589793238462643383279")));
96 assertEquals(new BigDecimal("1e400"), strategy.readNumber(fromString("1e400")));
97
98 try {
99 strategy.readNumber(fromString("\"not-a-number\""));
100 fail();
101 } catch (JsonParseException expected) {
102 assertEquals("Cannot parse not-a-number; at path $", expected.getMessage());
103 }
104 }
105
106 public void testNullsAreNeverExpected() throws IOException {
107 try {
108 ToNumberPolicy.DOUBLE.readNumber(fromString("null"));
109 fail();
110 } catch (IllegalStateException expected) {
111 }
112 try {
113 ToNumberPolicy.LAZILY_PARSED_NUMBER.readNumber(fromString("null"));
114 fail();
115 } catch (IllegalStateException expected) {
116 }
117 try {
118 ToNumberPolicy.LONG_OR_DOUBLE.readNumber(fromString("null"));
119 fail();
120 } catch (IllegalStateException expected) {
121 }
122 try {
123 ToNumberPolicy.BIG_DECIMAL.readNumber(fromString("null"));
124 fail();
125 } catch (IllegalStateException expected) {
126 }
127 }
128
129 private static JsonReader fromString(String json) {
130 return new JsonReader(new StringReader(json));
131 }
132
133 private static JsonReader fromStringLenient(String json) {
134 JsonReader jsonReader = fromString(json);
135 jsonReader.setLenient(true);
136 return jsonReader;
137 }
138 }
3636 import com.google.gson.JsonPrimitive;
3737 import com.google.gson.JsonSerializationContext;
3838 import com.google.gson.JsonSerializer;
39 import com.google.gson.common.MoreAsserts;
4039 import com.google.gson.common.TestTypes.BagOfPrimitives;
4140 import com.google.gson.reflect.TypeToken;
4241
3838 import java.net.InetAddress;
3939 import java.net.URI;
4040 import java.net.URL;
41 import java.sql.Time;
42 import java.sql.Timestamp;
4341 import java.text.DateFormat;
4442 import java.util.ArrayList;
4543 import java.util.Arrays;
6866 public class DefaultTypeAdaptersTest extends TestCase {
6967 private Gson gson;
7068 private TimeZone oldTimeZone;
69 private Locale oldLocale;
7170
7271 @Override
7372 protected void setUp() throws Exception {
7473 super.setUp();
7574 this.oldTimeZone = TimeZone.getDefault();
7675 TimeZone.setDefault(TimeZone.getTimeZone("America/Los_Angeles"));
76 this.oldLocale = Locale.getDefault();
7777 Locale.setDefault(Locale.US);
7878 gson = new Gson();
7979 }
8181 @Override
8282 protected void tearDown() throws Exception {
8383 TimeZone.setDefault(oldTimeZone);
84 Locale.setDefault(oldLocale);
8485 super.tearDown();
8586 }
8687
8788 public void testClassSerialization() {
8889 try {
8990 gson.toJson(String.class);
90 } catch (UnsupportedOperationException expected) {}
91 fail();
92 } catch (UnsupportedOperationException expected) {
93 }
9194 // Override with a custom type adapter for class.
9295 gson = new GsonBuilder().registerTypeAdapter(Class.class, new MyClassTypeAdapter()).create();
9396 assertEquals("\"java.lang.String\"", gson.toJson(String.class));
9699 public void testClassDeserialization() {
97100 try {
98101 gson.fromJson("String.class", String.class.getClass());
99 } catch (UnsupportedOperationException expected) {}
102 fail();
103 } catch (UnsupportedOperationException expected) {
104 }
100105 // Override with a custom type adapter for class.
101106 gson = new GsonBuilder().registerTypeAdapter(Class.class, new MyClassTypeAdapter()).create();
102107 assertEquals(String.class, gson.fromJson("java.lang.String", Class.class));
145150 URI target = gson.fromJson(json, URI.class);
146151 assertEquals(uriValue, target.toASCIIString());
147152 }
148
153
149154 public void testNullSerialization() throws Exception {
150155 testNullSerializationAndDeserialization(Boolean.class);
151156 testNullSerializationAndDeserialization(Byte.class);
174179 testNullSerializationAndDeserialization(Date.class);
175180 testNullSerializationAndDeserialization(GregorianCalendar.class);
176181 testNullSerializationAndDeserialization(Calendar.class);
177 testNullSerializationAndDeserialization(Time.class);
178 testNullSerializationAndDeserialization(Timestamp.class);
179 testNullSerializationAndDeserialization(java.sql.Date.class);
180 testNullSerializationAndDeserialization(Enum.class);
181182 testNullSerializationAndDeserialization(Class.class);
182183 }
183184
184185 private void testNullSerializationAndDeserialization(Class<?> c) {
186 testNullSerializationAndDeserialization(gson, c);
187 }
188
189 public static void testNullSerializationAndDeserialization(Gson gson, Class<?> c) {
185190 assertEquals("null", gson.toJson(null, c));
186191 assertEquals(null, gson.fromJson("null", c));
187192 }
268273 ClassWithBigInteger actual = gson.fromJson(json, ClassWithBigInteger.class);
269274 assertEquals(expected.value, actual.value);
270275 }
271
276
272277 public void testOverrideBigIntegerTypeAdapter() throws Exception {
273278 gson = new GsonBuilder()
274279 .registerTypeAdapter(BigInteger.class, new NumberAsStringAdapter(BigInteger.class))
324329
325330 json = "[true,false,true,true,true,true,false,false,true,false,false]";
326331 assertEquals(expected, gson.fromJson(json, BitSet.class));
332
333 try {
334 gson.fromJson("[1, []]", BitSet.class);
335 fail();
336 } catch (JsonSyntaxException e) {
337 assertEquals("Invalid bitset value type: BEGIN_ARRAY; at path $[1]", e.getMessage());
338 }
339
340 try {
341 gson.fromJson("[1, 2]", BitSet.class);
342 fail();
343 } catch (JsonSyntaxException e) {
344 assertEquals("Invalid bitset value 2, expected 0 or 1; at path $[1]", e.getMessage());
345 }
327346 }
328347
329348 public void testDefaultDateSerialization() {
346365 // Date can not directly be compared with another instance since the deserialization loses the
347366 // millisecond portion.
348367 @SuppressWarnings("deprecation")
349 private void assertEqualsDate(Date date, int year, int month, int day) {
368 public static void assertEqualsDate(Date date, int year, int month, int day) {
350369 assertEquals(year-1900, date.getYear());
351370 assertEquals(month, date.getMonth());
352371 assertEquals(day, date.getDate());
353372 }
354373
355374 @SuppressWarnings("deprecation")
356 private void assertEqualsTime(Date date, int hours, int minutes, int seconds) {
375 public static void assertEqualsTime(Date date, int hours, int minutes, int seconds) {
357376 assertEquals(hours, date.getHours());
358377 assertEquals(minutes, date.getMinutes());
359378 assertEquals(seconds, date.getSeconds());
360 }
361
362 public void testDefaultJavaSqlDateSerialization() {
363 java.sql.Date instant = new java.sql.Date(1259875082000L);
364 String json = gson.toJson(instant);
365 assertEquals("\"Dec 3, 2009\"", json);
366 }
367
368 public void testDefaultJavaSqlDateDeserialization() {
369 String json = "'Dec 3, 2009'";
370 java.sql.Date extracted = gson.fromJson(json, java.sql.Date.class);
371 assertEqualsDate(extracted, 2009, 11, 3);
372 }
373
374 public void testDefaultJavaSqlTimestampSerialization() {
375 Timestamp now = new java.sql.Timestamp(1259875082000L);
376 String json = gson.toJson(now);
377 if (JavaVersion.isJava9OrLater()) {
378 assertEquals("\"Dec 3, 2009, 1:18:02 PM\"", json);
379 } else {
380 assertEquals("\"Dec 3, 2009 1:18:02 PM\"", json);
381 }
382 }
383
384 public void testDefaultJavaSqlTimestampDeserialization() {
385 String json = "'Dec 3, 2009 1:18:02 PM'";
386 Timestamp extracted = gson.fromJson(json, Timestamp.class);
387 assertEqualsDate(extracted, 2009, 11, 3);
388 assertEqualsTime(extracted, 13, 18, 2);
389 }
390
391 public void testDefaultJavaSqlTimeSerialization() {
392 Time now = new Time(1259875082000L);
393 String json = gson.toJson(now);
394 assertEquals("\"01:18:02 PM\"", json);
395 }
396
397 public void testDefaultJavaSqlTimeDeserialization() {
398 String json = "'1:18:02 PM'";
399 Time extracted = gson.fromJson(json, Time.class);
400 assertEqualsTime(extracted, 13, 18, 2);
401379 }
402380
403381 public void testDefaultDateSerializationUsingBuilder() throws Exception {
523501 }
524502 }
525503
526 // http://code.google.com/p/google-gson/issues/detail?id=230
527 public void testTimestampSerialization() throws Exception {
528 TimeZone defaultTimeZone = TimeZone.getDefault();
529 TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
530 Locale defaultLocale = Locale.getDefault();
531 Locale.setDefault(Locale.US);
532 try {
533 Timestamp timestamp = new Timestamp(0L);
534 Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd").create();
535 String json = gson.toJson(timestamp, Timestamp.class);
536 assertEquals("\"1970-01-01\"", json);
537 assertEquals(0, gson.fromJson("\"1970-01-01\"", Timestamp.class).getTime());
538 } finally {
539 TimeZone.setDefault(defaultTimeZone);
540 Locale.setDefault(defaultLocale);
541 }
542 }
543
544 // http://code.google.com/p/google-gson/issues/detail?id=230
545 public void testSqlDateSerialization() throws Exception {
546 TimeZone defaultTimeZone = TimeZone.getDefault();
547 TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
548 Locale defaultLocale = Locale.getDefault();
549 Locale.setDefault(Locale.US);
550 try {
551 java.sql.Date sqlDate = new java.sql.Date(0L);
552 Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd").create();
553 String json = gson.toJson(sqlDate, Timestamp.class);
554 assertEquals("\"1970-01-01\"", json);
555 assertEquals(0, gson.fromJson("\"1970-01-01\"", java.sql.Date.class).getTime());
556 } finally {
557 TimeZone.setDefault(defaultTimeZone);
558 Locale.setDefault(defaultLocale);
559 }
560 }
561
562504 public void testJsonPrimitiveSerialization() {
563505 assertEquals("5", gson.toJson(new JsonPrimitive(5), JsonElement.class));
564506 assertEquals("true", gson.toJson(new JsonPrimitive(true), JsonElement.class));
636578 gson.fromJson("\"abc\"", JsonObject.class);
637579 fail();
638580 } catch (JsonSyntaxException expected) {
639 assertEquals("Expected a com.google.gson.JsonObject but was com.google.gson.JsonPrimitive",
581 assertEquals("Expected a com.google.gson.JsonObject but was com.google.gson.JsonPrimitive; at path $",
640582 expected.getMessage());
641583 }
642584 }
1414 */
1515
1616 package com.google.gson.functional;
17
18 import java.lang.reflect.Type;
19 import java.util.ArrayList;
20 import java.util.Collection;
21 import java.util.EnumSet;
22 import java.util.Set;
2317
2418 import com.google.gson.Gson;
2519 import com.google.gson.GsonBuilder;
3327 import com.google.gson.annotations.SerializedName;
3428 import com.google.gson.common.MoreAsserts;
3529 import com.google.gson.reflect.TypeToken;
36
30 import java.lang.reflect.Type;
31 import java.util.ArrayList;
32 import java.util.Collection;
33 import java.util.Collections;
34 import java.util.EnumMap;
35 import java.util.EnumSet;
36 import java.util.Map;
37 import java.util.Set;
3738 import junit.framework.TestCase;
3839 /**
3940 * Functional tests for Java 5.0 enums.
151152 public void testEnumSet() {
152153 EnumSet<Roshambo> foo = EnumSet.of(Roshambo.ROCK, Roshambo.PAPER);
153154 String json = gson.toJson(foo);
155 assertEquals("[\"ROCK\",\"PAPER\"]", json);
156
154157 Type type = new TypeToken<EnumSet<Roshambo>>() {}.getType();
155158 EnumSet<Roshambo> bar = gson.fromJson(json, type);
156159 assertTrue(bar.contains(Roshambo.ROCK));
157160 assertTrue(bar.contains(Roshambo.PAPER));
158161 assertFalse(bar.contains(Roshambo.SCISSORS));
162 }
163
164 public void testEnumMap() throws Exception {
165 EnumMap<MyEnum, String> map = new EnumMap<MyEnum, String>(MyEnum.class);
166 map.put(MyEnum.VALUE1, "test");
167 String json = gson.toJson(map);
168 assertEquals("{\"VALUE1\":\"test\"}", json);
169
170 Type type = new TypeToken<EnumMap<MyEnum, String>>() {}.getType();
171 EnumMap<?, ?> actualMap = gson.fromJson("{\"VALUE1\":\"test\"}", type);
172 Map<?, ?> expectedMap = Collections.singletonMap(MyEnum.VALUE1, "test");
173 assertEquals(expectedMap, actualMap);
159174 }
160175
161176 public enum Roshambo {
199214 }
200215
201216 public void testEnumClassWithFields() {
202 assertEquals("\"RED\"", gson.toJson(Color.RED));
203 assertEquals("red", gson.fromJson("RED", Color.class).value);
217 assertEquals("\"RED\"", gson.toJson(Color.RED));
218 assertEquals("red", gson.fromJson("RED", Color.class).value);
204219 }
205220
206221 public enum Color {
207 RED("red", 1), BLUE("blue", 2), GREEN("green", 3);
208 String value;
209 int index;
210 private Color(String value, int index) {
211 this.value = value;
212 this.index = index;
213 }
222 RED("red", 1), BLUE("blue", 2), GREEN("green", 3);
223 String value;
224 int index;
225 private Color(String value, int index) {
226 this.value = value;
227 this.index = index;
228 }
214229 }
215230 }
2020 import static com.google.gson.FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES;
2121 import static com.google.gson.FieldNamingPolicy.UPPER_CAMEL_CASE;
2222 import static com.google.gson.FieldNamingPolicy.UPPER_CAMEL_CASE_WITH_SPACES;
23 import static com.google.gson.FieldNamingPolicy.UPPER_CASE_WITH_UNDERSCORES;
2324
2425 import com.google.gson.FieldNamingPolicy;
2526 import com.google.gson.Gson;
4950 assertEquals("{'Lower Camel':1,'Upper Camel':2,'_Lower Camel Leading Underscore':3," +
5051 "'_ Upper Camel Leading Underscore':4,'Lower_words':5,'U P P E R_ W O R D S':6," +
5152 "'annotatedName':7,'Lower Id':8,'_9':9}",
53 gson.toJson(new TestNames()).replace('\"', '\''));
54 }
55
56 public void testUpperCaseWithUnderscores() {
57 Gson gson = getGsonWithNamingPolicy(UPPER_CASE_WITH_UNDERSCORES);
58 assertEquals("{'LOWER_CAMEL':1,'UPPER_CAMEL':2,'_LOWER_CAMEL_LEADING_UNDERSCORE':3," +
59 "'__UPPER_CAMEL_LEADING_UNDERSCORE':4,'LOWER_WORDS':5,'U_P_P_E_R__W_O_R_D_S':6," +
60 "'annotatedName':7,'LOWER_ID':8,'_9':9}",
5261 gson.toJson(new TestNames()).replace('\"', '\''));
5362 }
5463
140140 assertEquals("someValue", deserializedObject.someConstantStringInstanceField);
141141 }
142142
143 public void testGsonWithUpperCaseUnderscorePolicySerialization() {
144 Gson gson = builder.setFieldNamingPolicy(FieldNamingPolicy.UPPER_CASE_WITH_UNDERSCORES)
145 .create();
146 StringWrapper target = new StringWrapper("blah");
147 assertEquals("{\"SOME_CONSTANT_STRING_INSTANCE_FIELD\":\""
148 + target.someConstantStringInstanceField + "\"}", gson.toJson(target));
149 }
150
151 public void testGsonWithUpperCaseUnderscorePolicyDeserialiation() {
152 Gson gson = builder.setFieldNamingPolicy(FieldNamingPolicy.UPPER_CASE_WITH_UNDERSCORES)
153 .create();
154 String target = "{\"SOME_CONSTANT_STRING_INSTANCE_FIELD\":\"someValue\"}";
155 StringWrapper deserializedObject = gson.fromJson(target, StringWrapper.class);
156 assertEquals("someValue", deserializedObject.someConstantStringInstanceField);
157 }
158
143159 public void testDeprecatedNamingStrategy() throws Exception {
144160 Gson gson = builder.setFieldNamingStrategy(new UpperCaseNamingStrategy()).create();
145161 ClassWithDuplicateFields target = new ClassWithDuplicateFields(10);
5454 */
5555 public class ObjectTest extends TestCase {
5656 private Gson gson;
57 private TimeZone oldTimeZone = TimeZone.getDefault();
57 private TimeZone oldTimeZone;
58 private Locale oldLocale;
5859
5960 @Override
6061 protected void setUp() throws Exception {
6162 super.setUp();
6263 gson = new Gson();
6364
65 oldTimeZone = TimeZone.getDefault();
6466 TimeZone.setDefault(TimeZone.getTimeZone("America/Los_Angeles"));
67 oldLocale = Locale.getDefault();
6568 Locale.setDefault(Locale.US);
6669 }
6770
6871 @Override
6972 protected void tearDown() throws Exception {
7073 TimeZone.setDefault(oldTimeZone);
74 Locale.setDefault(oldLocale);
7175 super.tearDown();
7276 }
77
7378 public void testJsonInSingleQuotesDeserialization() {
7479 String json = "{'stringValue':'no message','intValue':10,'longValue':20}";
7580 BagOfPrimitives target = gson.fromJson(json, BagOfPrimitives.class);
1515
1616 package com.google.gson.functional;
1717
18 import static org.junit.Assert.assertArrayEquals;
19
1820 import com.google.gson.Gson;
1921 import com.google.gson.GsonBuilder;
2022 import com.google.gson.JsonPrimitive;
2123 import com.google.gson.JsonSyntaxException;
2224 import com.google.gson.LongSerializationPolicy;
25 import com.google.gson.internal.LazilyParsedNumber;
2326 import com.google.gson.reflect.TypeToken;
2427 import java.io.Serializable;
2528 import java.io.StringReader;
6265 assertEquals("1", gson.toJson(1, Byte.class));
6366 }
6467
68 public void testByteDeserialization() {
69 Byte boxed = gson.fromJson("1", Byte.class);
70 assertEquals(1, (byte)boxed);
71 byte primitive = gson.fromJson("1", byte.class);
72 assertEquals(1, primitive);
73
74 byte[] bytes = gson.fromJson("[-128, 0, 127, 255]", byte[].class);
75 assertArrayEquals(new byte[] {-128, 0, 127, -1}, bytes);
76 }
77
78 public void testByteDeserializationLossy() {
79 try {
80 gson.fromJson("-129", byte.class);
81 fail();
82 } catch (JsonSyntaxException e) {
83 assertEquals("Lossy conversion from -129 to byte; at path $", e.getMessage());
84 }
85
86 try {
87 gson.fromJson("256", byte.class);
88 fail();
89 } catch (JsonSyntaxException e) {
90 assertEquals("Lossy conversion from 256 to byte; at path $", e.getMessage());
91 }
92
93 try {
94 gson.fromJson("2147483648", byte.class);
95 fail();
96 } catch (JsonSyntaxException e) {
97 assertEquals("java.lang.NumberFormatException: Expected an int but was 2147483648 at line 1 column 11 path $", e.getMessage());
98 }
99 }
100
65101 public void testShortSerialization() {
66102 assertEquals("1", gson.toJson(1, short.class));
67103 assertEquals("1", gson.toJson(1, Short.class));
68104 }
69105
70 public void testByteDeserialization() {
71 Byte target = gson.fromJson("1", Byte.class);
72 assertEquals(1, (byte)target);
73 byte primitive = gson.fromJson("1", byte.class);
106 public void testShortDeserialization() {
107 Short boxed = gson.fromJson("1", Short.class);
108 assertEquals(1, (short)boxed);
109 short primitive = gson.fromJson("1", short.class);
74110 assertEquals(1, primitive);
111
112 short[] shorts = gson.fromJson("[-32768, 0, 32767, 65535]", short[].class);
113 assertArrayEquals(new short[] {-32768, 0, 32767, -1}, shorts);
114 }
115
116 public void testShortDeserializationLossy() {
117 try {
118 gson.fromJson("-32769", short.class);
119 fail();
120 } catch (JsonSyntaxException e) {
121 assertEquals("Lossy conversion from -32769 to short; at path $", e.getMessage());
122 }
123
124 try {
125 gson.fromJson("65536", short.class);
126 fail();
127 } catch (JsonSyntaxException e) {
128 assertEquals("Lossy conversion from 65536 to short; at path $", e.getMessage());
129 }
130
131 try {
132 gson.fromJson("2147483648", short.class);
133 fail();
134 } catch (JsonSyntaxException e) {
135 assertEquals("java.lang.NumberFormatException: Expected an int but was 2147483648 at line 1 column 11 path $", e.getMessage());
136 }
75137 }
76138
77139 public void testPrimitiveIntegerAutoboxedInASingleElementArraySerialization() {
331393 } catch (JsonSyntaxException expected) { }
332394 }
333395
396 public void testLazilyParsedNumberSerialization() {
397 LazilyParsedNumber target = new LazilyParsedNumber("1.5");
398 String actual = gson.toJson(target);
399 assertEquals("1.5", actual);
400 }
401
402 public void testLazilyParsedNumberDeserialization() {
403 LazilyParsedNumber expected = new LazilyParsedNumber("1.5");
404 LazilyParsedNumber actual = gson.fromJson("1.5", LazilyParsedNumber.class);
405 assertEquals(expected, actual);
406 }
407
334408 public void testMoreSpecificSerialization() {
335409 Gson gson = new Gson();
336410 String expected = "This is a string";
0 package com.google.gson.functional;
1
2 import static org.junit.Assert.assertEquals;
3 import static org.junit.Assert.assertNull;
4 import static org.junit.Assert.assertTrue;
5 import static org.junit.Assert.fail;
6
7 import com.google.gson.Gson;
8 import com.google.gson.GsonBuilder;
9 import com.google.gson.JsonIOException;
10 import com.google.gson.TypeAdapter;
11 import com.google.gson.stream.JsonReader;
12 import com.google.gson.stream.JsonWriter;
13 import java.io.IOException;
14 import java.lang.reflect.ReflectPermission;
15 import java.net.URL;
16 import java.net.URLClassLoader;
17 import java.security.Permission;
18 import java.util.Collections;
19 import java.util.concurrent.atomic.AtomicBoolean;
20 import org.junit.Test;
21
22 public class ReflectionAccessTest {
23 @SuppressWarnings("unused")
24 private static class ClassWithPrivateMembers {
25 private String s;
26
27 private ClassWithPrivateMembers() {
28 }
29 }
30
31 private static Class<?> loadClassWithDifferentClassLoader(Class<?> c) throws Exception {
32 URL url = c.getProtectionDomain().getCodeSource().getLocation();
33 URLClassLoader classLoader = new URLClassLoader(new URL[] { url }, null);
34 return classLoader.loadClass(c.getName());
35 }
36
37 @Test
38 public void testRestrictiveSecurityManager() throws Exception {
39 // Must use separate class loader, otherwise permission is not checked, see Class.getDeclaredFields()
40 Class<?> clazz = loadClassWithDifferentClassLoader(ClassWithPrivateMembers.class);
41
42 final Permission accessDeclaredMembers = new RuntimePermission("accessDeclaredMembers");
43 final Permission suppressAccessChecks = new ReflectPermission("suppressAccessChecks");
44 SecurityManager original = System.getSecurityManager();
45 SecurityManager restrictiveManager = new SecurityManager() {
46 @Override
47 public void checkPermission(Permission perm) {
48 if (accessDeclaredMembers.equals(perm)) {
49 throw new SecurityException("Gson: no-member-access");
50 }
51 if (suppressAccessChecks.equals(perm)) {
52 throw new SecurityException("Gson: no-suppress-access-check");
53 }
54 }
55 };
56 System.setSecurityManager(restrictiveManager);
57
58 try {
59 Gson gson = new Gson();
60 try {
61 // Getting reflection based adapter should fail
62 gson.getAdapter(clazz);
63 fail();
64 } catch (SecurityException e) {
65 assertEquals("Gson: no-member-access", e.getMessage());
66 }
67
68 final AtomicBoolean wasReadCalled = new AtomicBoolean(false);
69 gson = new GsonBuilder()
70 .registerTypeAdapter(clazz, new TypeAdapter<Object>() {
71 @Override
72 public void write(JsonWriter out, Object value) throws IOException {
73 out.value("custom-write");
74 }
75
76 @Override
77 public Object read(JsonReader in) throws IOException {
78 in.skipValue();
79 wasReadCalled.set(true);
80 return null;
81 }}
82 )
83 .create();
84
85 assertEquals("\"custom-write\"", gson.toJson(null, clazz));
86 assertNull(gson.fromJson("{}", clazz));
87 assertTrue(wasReadCalled.get());
88 } finally {
89 System.setSecurityManager(original);
90 }
91 }
92
93 /**
94 * Test serializing an instance of a non-accessible internal class, but where
95 * Gson supports serializing one of its superinterfaces.
96 *
97 * <p>Here {@link Collections#emptyList()} is used which returns an instance
98 * of the internal class {@code java.util.Collections.EmptyList}. Gson should
99 * serialize the object as {@code List} despite the internal class not being
100 * accessible.
101 *
102 * <p>See https://github.com/google/gson/issues/1875
103 */
104 @Test
105 public void testSerializeInternalImplementationObject() {
106 Gson gson = new Gson();
107 String json = gson.toJson(Collections.emptyList());
108 assertEquals("[]", json);
109
110 // But deserialization should fail
111 Class<?> internalClass = Collections.emptyList().getClass();
112 try {
113 gson.fromJson("{}", internalClass);
114 fail("Missing exception; test has to be run with `--illegal-access=deny`");
115 } catch (JsonIOException expected) {
116 assertTrue(expected.getMessage().startsWith(
117 "Failed making constructor 'java.util.Collections$EmptyList#EmptyList()' accessible; "
118 + "either change its visibility or write a custom InstanceCreator or TypeAdapter for its declaring type"
119 ));
120 }
121 }
122 }
+0
-65
gson/src/test/java/com/google/gson/functional/ThrowableFunctionalTest.java less more
0 // Copyright (C) 2014 Trymph Inc.
1 package com.google.gson.functional;
2
3 import java.io.IOException;
4
5 import junit.framework.TestCase;
6
7 import com.google.gson.Gson;
8 import com.google.gson.annotations.SerializedName;
9
10 @SuppressWarnings("serial")
11 public final class ThrowableFunctionalTest extends TestCase {
12 private final Gson gson = new Gson();
13
14 public void testExceptionWithoutCause() {
15 RuntimeException e = new RuntimeException("hello");
16 String json = gson.toJson(e);
17 assertTrue(json.contains("hello"));
18
19 e = gson.fromJson("{'detailMessage':'hello'}", RuntimeException.class);
20 assertEquals("hello", e.getMessage());
21 }
22
23 public void testExceptionWithCause() {
24 Exception e = new Exception("top level", new IOException("io error"));
25 String json = gson.toJson(e);
26 assertTrue(json.contains("{\"detailMessage\":\"top level\",\"cause\":{\"detailMessage\":\"io error\""));
27
28 e = gson.fromJson("{'detailMessage':'top level','cause':{'detailMessage':'io error'}}", Exception.class);
29 assertEquals("top level", e.getMessage());
30 assertTrue(e.getCause() instanceof Throwable); // cause is not parameterized so type info is lost
31 assertEquals("io error", e.getCause().getMessage());
32 }
33
34 public void testSerializedNameOnExceptionFields() {
35 MyException e = new MyException();
36 String json = gson.toJson(e);
37 assertTrue(json.contains("{\"my_custom_name\":\"myCustomMessageValue\""));
38 }
39
40 public void testErrorWithoutCause() {
41 OutOfMemoryError e = new OutOfMemoryError("hello");
42 String json = gson.toJson(e);
43 assertTrue(json.contains("hello"));
44
45 e = gson.fromJson("{'detailMessage':'hello'}", OutOfMemoryError.class);
46 assertEquals("hello", e.getMessage());
47 }
48
49 public void testErrornWithCause() {
50 Error e = new Error("top level", new IOException("io error"));
51 String json = gson.toJson(e);
52 assertTrue(json.contains("top level"));
53 assertTrue(json.contains("io error"));
54
55 e = gson.fromJson("{'detailMessage':'top level','cause':{'detailMessage':'io error'}}", Error.class);
56 assertEquals("top level", e.getMessage());
57 assertTrue(e.getCause() instanceof Throwable); // cause is not parameterized so type info is lost
58 assertEquals("io error", e.getCause().getMessage());
59 }
60
61 private static final class MyException extends Throwable {
62 @SerializedName("my_custom_name") String myCustomMessage = "myCustomMessageValue";
63 }
64 }
0 /*
1 * Copyright (C) 2021 Google Inc.
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 package com.google.gson.functional;
17
18 import java.lang.reflect.Type;
19 import java.math.BigDecimal;
20 import java.util.Arrays;
21 import java.util.Collection;
22 import java.util.LinkedList;
23 import java.util.List;
24 import com.google.gson.Gson;
25 import com.google.gson.GsonBuilder;
26 import com.google.gson.ToNumberPolicy;
27 import com.google.gson.ToNumberStrategy;
28 import com.google.gson.internal.LazilyParsedNumber;
29 import com.google.gson.reflect.TypeToken;
30 import com.google.gson.stream.JsonReader;
31 import junit.framework.TestCase;
32
33 public class ToNumberPolicyFunctionalTest extends TestCase {
34 public void testDefault() {
35 Gson gson = new Gson();
36 assertEquals(null, gson.fromJson("null", Object.class));
37 assertEquals(10D, gson.fromJson("10", Object.class));
38 assertEquals(null, gson.fromJson("null", Number.class));
39 assertEquals(new LazilyParsedNumber("10"), gson.fromJson("10", Number.class));
40 }
41
42 public void testAsDoubles() {
43 Gson gson = new GsonBuilder()
44 .setObjectToNumberStrategy(ToNumberPolicy.DOUBLE)
45 .setNumberToNumberStrategy(ToNumberPolicy.DOUBLE)
46 .create();
47 assertEquals(null, gson.fromJson("null", Object.class));
48 assertEquals(10.0, gson.fromJson("10", Object.class));
49 assertEquals(null, gson.fromJson("null", Number.class));
50 assertEquals(10.0, gson.fromJson("10", Number.class));
51 }
52
53 public void testAsLazilyParsedNumbers() {
54 Gson gson = new GsonBuilder()
55 .setObjectToNumberStrategy(ToNumberPolicy.LAZILY_PARSED_NUMBER)
56 .setNumberToNumberStrategy(ToNumberPolicy.LAZILY_PARSED_NUMBER)
57 .create();
58 assertEquals(null, gson.fromJson("null", Object.class));
59 assertEquals(new LazilyParsedNumber("10"), gson.fromJson("10", Object.class));
60 assertEquals(null, gson.fromJson("null", Number.class));
61 assertEquals(new LazilyParsedNumber("10"), gson.fromJson("10", Number.class));
62 }
63
64 public void testAsLongsOrDoubles() {
65 Gson gson = new GsonBuilder()
66 .setObjectToNumberStrategy(ToNumberPolicy.LONG_OR_DOUBLE)
67 .setNumberToNumberStrategy(ToNumberPolicy.LONG_OR_DOUBLE)
68 .create();
69 assertEquals(null, gson.fromJson("null", Object.class));
70 assertEquals(10L, gson.fromJson("10", Object.class));
71 assertEquals(10.0, gson.fromJson("10.0", Object.class));
72 assertEquals(null, gson.fromJson("null", Number.class));
73 assertEquals(10L, gson.fromJson("10", Number.class));
74 assertEquals(10.0, gson.fromJson("10.0", Number.class));
75 }
76
77 public void testAsBigDecimals() {
78 Gson gson = new GsonBuilder()
79 .setObjectToNumberStrategy(ToNumberPolicy.BIG_DECIMAL)
80 .setNumberToNumberStrategy(ToNumberPolicy.BIG_DECIMAL)
81 .create();
82 assertEquals(null, gson.fromJson("null", Object.class));
83 assertEquals(new BigDecimal("10"), gson.fromJson("10", Object.class));
84 assertEquals(new BigDecimal("10.0"), gson.fromJson("10.0", Object.class));
85 assertEquals(null, gson.fromJson("null", Number.class));
86 assertEquals(new BigDecimal("10"), gson.fromJson("10", Number.class));
87 assertEquals(new BigDecimal("10.0"), gson.fromJson("10.0", Number.class));
88 assertEquals(new BigDecimal("3.141592653589793238462643383279"), gson.fromJson("3.141592653589793238462643383279", BigDecimal.class));
89 assertEquals(new BigDecimal("1e400"), gson.fromJson("1e400", BigDecimal.class));
90 }
91
92 public void testAsListOfLongsOrDoubles() {
93 Gson gson = new GsonBuilder()
94 .setObjectToNumberStrategy(ToNumberPolicy.LONG_OR_DOUBLE)
95 .setNumberToNumberStrategy(ToNumberPolicy.LONG_OR_DOUBLE)
96 .create();
97 List<Object> expected = new LinkedList<Object>();
98 expected.add(null);
99 expected.add(10L);
100 expected.add(10.0);
101 Type objectCollectionType = new TypeToken<Collection<Object>>() { }.getType();
102 Collection<Object> objects = gson.fromJson("[null,10,10.0]", objectCollectionType);
103 assertEquals(expected, objects);
104 Type numberCollectionType = new TypeToken<Collection<Number>>() { }.getType();
105 Collection<Object> numbers = gson.fromJson("[null,10,10.0]", numberCollectionType);
106 assertEquals(expected, numbers);
107 }
108
109 public void testCustomStrategiesCannotAffectConcreteDeclaredNumbers() {
110 ToNumberStrategy fail = new ToNumberStrategy() {
111 @Override
112 public Byte readNumber(JsonReader in) {
113 throw new UnsupportedOperationException();
114 }
115 };
116 Gson gson = new GsonBuilder()
117 .setObjectToNumberStrategy(fail)
118 .setNumberToNumberStrategy(fail)
119 .create();
120 List<Object> numbers = gson.fromJson("[null, 10, 20, 30]", new TypeToken<List<Byte>>() {}.getType());
121 assertEquals(Arrays.asList(null, (byte) 10, (byte) 20, (byte) 30), numbers);
122 try {
123 gson.fromJson("[null, 10, 20, 30]", new TypeToken<List<Object>>() {}.getType());
124 fail();
125 } catch (UnsupportedOperationException ex) {
126 }
127 try {
128 gson.fromJson("[null, 10, 20, 30]", new TypeToken<List<Number>>() {}.getType());
129 fail();
130 } catch (UnsupportedOperationException ex) {
131 }
132 }
133 }
5656 .registerTypeAdapter(Id.class, new IdTreeTypeAdapter())
5757 .create();
5858 course = new Course<HistoryCourse>(COURSE_ID, 4,
59 new Assignment<HistoryCourse>(null, null), createList(STUDENT1, STUDENT2));
59 new Assignment<HistoryCourse>(null, null), Arrays.asList(STUDENT1, STUDENT2));
6060 }
6161
6262 public void testSerializeId() {
170170 private static class HistoryCourse {
171171 int numClasses;
172172 }
173
174 private static <T> List<T> createList(T ...items) {
175 return Arrays.asList(items);
176 }
177173 }
0 package com.google.gson.internal;
1
2 import static org.junit.Assert.assertEquals;
3 import static org.junit.Assert.fail;
4
5 import java.lang.reflect.Type;
6 import java.util.Collections;
7 import java.util.Map;
8
9 import org.junit.Test;
10
11 import com.google.gson.InstanceCreator;
12 import com.google.gson.reflect.TypeToken;
13
14 public class ConstructorConstructorTest {
15 private static final Map<Type, InstanceCreator<?>> NO_INSTANCE_CREATORS = Collections.emptyMap();
16
17 private abstract static class AbstractClass {
18 @SuppressWarnings("unused")
19 public AbstractClass() { }
20 }
21 private interface Interface { }
22
23 /**
24 * Verify that ConstructorConstructor does not try to invoke no-arg constructor
25 * of abstract class.
26 */
27 @Test
28 public void testGet_AbstractClassNoArgConstructor() {
29 ConstructorConstructor constructorFactory = new ConstructorConstructor(NO_INSTANCE_CREATORS, true);
30 ObjectConstructor<AbstractClass> constructor = constructorFactory.get(TypeToken.get(AbstractClass.class));
31 try {
32 constructor.construct();
33 fail("Expected exception");
34 } catch (RuntimeException exception) {
35 assertEquals(
36 "Unable to create instance of class com.google.gson.internal.ConstructorConstructorTest$AbstractClass. "
37 + "Registering an InstanceCreator or a TypeAdapter for this type, or adding a no-args constructor may fix this problem.",
38 exception.getMessage()
39 );
40 }
41 }
42
43 @Test
44 public void testGet_Interface() {
45 ConstructorConstructor constructorFactory = new ConstructorConstructor(NO_INSTANCE_CREATORS, true);
46 ObjectConstructor<Interface> constructor = constructorFactory.get(TypeToken.get(Interface.class));
47 try {
48 constructor.construct();
49 fail("Expected exception");
50 } catch (RuntimeException exception) {
51 assertEquals(
52 "Unable to create instance of interface com.google.gson.internal.ConstructorConstructorTest$Interface. "
53 + "Registering an InstanceCreator or a TypeAdapter for this type, or adding a no-args constructor may fix this problem.",
54 exception.getMessage()
55 );
56 }
57 }
58 }
1717 import static org.junit.Assert.*;
1818
1919 import org.junit.Test;
20
21 import com.google.gson.internal.JavaVersion;
2220
2321 /**
2422 * Unit and functional tests for {@link JavaVersion}
1414 */
1515 package com.google.gson.internal;
1616
17 import java.io.ByteArrayInputStream;
18 import java.io.ByteArrayOutputStream;
19 import java.io.IOException;
20 import java.io.ObjectInputStream;
21 import java.io.ObjectOutputStream;
22 import java.math.BigDecimal;
23
1724 import junit.framework.TestCase;
1825
1926 public class LazilyParsedNumberTest extends TestCase {
2835 LazilyParsedNumber n1Another = new LazilyParsedNumber("1");
2936 assertTrue(n1.equals(n1Another));
3037 }
38
39 public void testJavaSerialization() throws IOException, ClassNotFoundException {
40 ByteArrayOutputStream out = new ByteArrayOutputStream();
41 ObjectOutputStream objOut = new ObjectOutputStream(out);
42 objOut.writeObject(new LazilyParsedNumber("123"));
43 objOut.close();
44
45 ObjectInputStream objIn = new ObjectInputStream(new ByteArrayInputStream(out.toByteArray()));
46 Number deserialized = (Number) objIn.readObject();
47 assertEquals(new BigDecimal("123"), deserialized);
48 }
3149 }
+0
-290
gson/src/test/java/com/google/gson/internal/LinkedHashTreeMapTest.java less more
0 /*
1 * Copyright (C) 2012 Google Inc.
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 package com.google.gson.internal;
17
18 import com.google.gson.common.MoreAsserts;
19 import com.google.gson.internal.LinkedHashTreeMap.AvlBuilder;
20 import com.google.gson.internal.LinkedHashTreeMap.AvlIterator;
21 import com.google.gson.internal.LinkedHashTreeMap.Node;
22 import java.util.ArrayList;
23 import java.util.Arrays;
24 import java.util.Iterator;
25 import java.util.Map;
26 import java.util.Random;
27 import junit.framework.TestCase;
28
29 public final class LinkedHashTreeMapTest extends TestCase {
30 public void testIterationOrder() {
31 LinkedHashTreeMap<String, String> map = new LinkedHashTreeMap<String, String>();
32 map.put("a", "android");
33 map.put("c", "cola");
34 map.put("b", "bbq");
35 assertIterationOrder(map.keySet(), "a", "c", "b");
36 assertIterationOrder(map.values(), "android", "cola", "bbq");
37 }
38
39 public void testRemoveRootDoesNotDoubleUnlink() {
40 LinkedHashTreeMap<String, String> map = new LinkedHashTreeMap<String, String>();
41 map.put("a", "android");
42 map.put("c", "cola");
43 map.put("b", "bbq");
44 Iterator<Map.Entry<String,String>> it = map.entrySet().iterator();
45 it.next();
46 it.next();
47 it.next();
48 it.remove();
49 assertIterationOrder(map.keySet(), "a", "c");
50 }
51
52 public void testPutNullKeyFails() {
53 LinkedHashTreeMap<String, String> map = new LinkedHashTreeMap<String, String>();
54 try {
55 map.put(null, "android");
56 fail();
57 } catch (NullPointerException expected) {
58 }
59 }
60
61 public void testPutNonComparableKeyFails() {
62 LinkedHashTreeMap<Object, String> map = new LinkedHashTreeMap<Object, String>();
63 try {
64 map.put(new Object(), "android");
65 fail();
66 } catch (ClassCastException expected) {}
67 }
68
69 public void testContainsNonComparableKeyReturnsFalse() {
70 LinkedHashTreeMap<String, String> map = new LinkedHashTreeMap<String, String>();
71 map.put("a", "android");
72 assertFalse(map.containsKey(new Object()));
73 }
74
75 public void testContainsNullKeyIsAlwaysFalse() {
76 LinkedHashTreeMap<String, String> map = new LinkedHashTreeMap<String, String>();
77 map.put("a", "android");
78 assertFalse(map.containsKey(null));
79 }
80
81 public void testPutOverrides() throws Exception {
82 LinkedHashTreeMap<String, String> map = new LinkedHashTreeMap<String, String>();
83 assertNull(map.put("d", "donut"));
84 assertNull(map.put("e", "eclair"));
85 assertNull(map.put("f", "froyo"));
86 assertEquals(3, map.size());
87
88 assertEquals("donut", map.get("d"));
89 assertEquals("donut", map.put("d", "done"));
90 assertEquals(3, map.size());
91 }
92
93 public void testEmptyStringValues() {
94 LinkedHashTreeMap<String, String> map = new LinkedHashTreeMap<String, String>();
95 map.put("a", "");
96 assertTrue(map.containsKey("a"));
97 assertEquals("", map.get("a"));
98 }
99
100 // NOTE that this does not happen every time, but given the below predictable random,
101 // this test will consistently fail (assuming the initial size is 16 and rehashing
102 // size remains at 3/4)
103 public void testForceDoublingAndRehash() throws Exception {
104 Random random = new Random(1367593214724L);
105 LinkedHashTreeMap<String, String> map = new LinkedHashTreeMap<String, String>();
106 String[] keys = new String[1000];
107 for (int i = 0; i < keys.length; i++) {
108 keys[i] = Integer.toString(Math.abs(random.nextInt()), 36) + "-" + i;
109 map.put(keys[i], "" + i);
110 }
111
112 for (int i = 0; i < keys.length; i++) {
113 String key = keys[i];
114 assertTrue(map.containsKey(key));
115 assertEquals("" + i, map.get(key));
116 }
117 }
118
119 public void testClear() {
120 LinkedHashTreeMap<String, String> map = new LinkedHashTreeMap<String, String>();
121 map.put("a", "android");
122 map.put("c", "cola");
123 map.put("b", "bbq");
124 map.clear();
125 assertIterationOrder(map.keySet());
126 assertEquals(0, map.size());
127 }
128
129 public void testEqualsAndHashCode() throws Exception {
130 LinkedHashTreeMap<String, Integer> map1 = new LinkedHashTreeMap<String, Integer>();
131 map1.put("A", 1);
132 map1.put("B", 2);
133 map1.put("C", 3);
134 map1.put("D", 4);
135
136 LinkedHashTreeMap<String, Integer> map2 = new LinkedHashTreeMap<String, Integer>();
137 map2.put("C", 3);
138 map2.put("B", 2);
139 map2.put("D", 4);
140 map2.put("A", 1);
141
142 MoreAsserts.assertEqualsAndHashCode(map1, map2);
143 }
144
145 public void testAvlWalker() {
146 assertAvlWalker(node(node("a"), "b", node("c")),
147 "a", "b", "c");
148 assertAvlWalker(node(node(node("a"), "b", node("c")), "d", node(node("e"), "f", node("g"))),
149 "a", "b", "c", "d", "e", "f", "g");
150 assertAvlWalker(node(node(null, "a", node("b")), "c", node(node("d"), "e", null)),
151 "a", "b", "c", "d", "e");
152 assertAvlWalker(node(null, "a", node(null, "b", node(null, "c", node("d")))),
153 "a", "b", "c", "d");
154 assertAvlWalker(node(node(node(node("a"), "b", null), "c", null), "d", null),
155 "a", "b", "c", "d");
156 }
157
158 private void assertAvlWalker(Node<String, String> root, String... values) {
159 AvlIterator<String, String> iterator = new AvlIterator<String, String>();
160 iterator.reset(root);
161 for (String value : values) {
162 assertEquals(value, iterator.next().getKey());
163 }
164 assertNull(iterator.next());
165 }
166
167 public void testAvlBuilder() {
168 assertAvlBuilder(1, "a");
169 assertAvlBuilder(2, "(. a b)");
170 assertAvlBuilder(3, "(a b c)");
171 assertAvlBuilder(4, "(a b (. c d))");
172 assertAvlBuilder(5, "(a b (c d e))");
173 assertAvlBuilder(6, "((. a b) c (d e f))");
174 assertAvlBuilder(7, "((a b c) d (e f g))");
175 assertAvlBuilder(8, "((a b c) d (e f (. g h)))");
176 assertAvlBuilder(9, "((a b c) d (e f (g h i)))");
177 assertAvlBuilder(10, "((a b c) d ((. e f) g (h i j)))");
178 assertAvlBuilder(11, "((a b c) d ((e f g) h (i j k)))");
179 assertAvlBuilder(12, "((a b (. c d)) e ((f g h) i (j k l)))");
180 assertAvlBuilder(13, "((a b (c d e)) f ((g h i) j (k l m)))");
181 assertAvlBuilder(14, "(((. a b) c (d e f)) g ((h i j) k (l m n)))");
182 assertAvlBuilder(15, "(((a b c) d (e f g)) h ((i j k) l (m n o)))");
183 assertAvlBuilder(16, "(((a b c) d (e f g)) h ((i j k) l (m n (. o p))))");
184 assertAvlBuilder(30, "((((. a b) c (d e f)) g ((h i j) k (l m n))) o "
185 + "(((p q r) s (t u v)) w ((x y z) A (B C D))))");
186 assertAvlBuilder(31, "((((a b c) d (e f g)) h ((i j k) l (m n o))) p "
187 + "(((q r s) t (u v w)) x ((y z A) B (C D E))))");
188 }
189
190 private void assertAvlBuilder(int size, String expected) {
191 char[] values = "abcdefghijklmnopqrstuvwxyzABCDE".toCharArray();
192 AvlBuilder<String, String> avlBuilder = new AvlBuilder<String, String>();
193 avlBuilder.reset(size);
194 for (int i = 0; i < size; i++) {
195 avlBuilder.add(node(Character.toString(values[i])));
196 }
197 assertTree(expected, avlBuilder.root());
198 }
199
200 public void testDoubleCapacity() {
201 @SuppressWarnings("unchecked") // Arrays and generics don't get along.
202 Node<String, String>[] oldTable = new Node[1];
203 oldTable[0] = node(node(node("a"), "b", node("c")), "d", node(node("e"), "f", node("g")));
204
205 Node<String, String>[] newTable = LinkedHashTreeMap.doubleCapacity(oldTable);
206 assertTree("(b d f)", newTable[0]); // Even hash codes!
207 assertTree("(a c (. e g))", newTable[1]); // Odd hash codes!
208 }
209
210 public void testDoubleCapacityAllNodesOnLeft() {
211 @SuppressWarnings("unchecked") // Arrays and generics don't get along.
212 Node<String, String>[] oldTable = new Node[1];
213 oldTable[0] = node(node("b"), "d", node("f"));
214
215 Node<String, String>[] newTable = LinkedHashTreeMap.doubleCapacity(oldTable);
216 assertTree("(b d f)", newTable[0]); // Even hash codes!
217 assertNull(newTable[1]); // Odd hash codes!
218
219 for (Node<?, ?> node : newTable) {
220 if (node != null) {
221 assertConsistent(node);
222 }
223 }
224 }
225
226 private static final Node<String, String> head = new Node<String, String>();
227
228 private Node<String, String> node(String value) {
229 return new Node<String, String>(null, value, value.hashCode(), head, head);
230 }
231
232 private Node<String, String> node(Node<String, String> left, String value,
233 Node<String, String> right) {
234 Node<String, String> result = node(value);
235 if (left != null) {
236 result.left = left;
237 left.parent = result;
238 }
239 if (right != null) {
240 result.right = right;
241 right.parent = result;
242 }
243 return result;
244 }
245
246 private void assertTree(String expected, Node<?, ?> root) {
247 assertEquals(expected, toString(root));
248 assertConsistent(root);
249 }
250
251 private void assertConsistent(Node<?, ?> node) {
252 int leftHeight = 0;
253 if (node.left != null) {
254 assertConsistent(node.left);
255 assertSame(node, node.left.parent);
256 leftHeight = node.left.height;
257 }
258 int rightHeight = 0;
259 if (node.right != null) {
260 assertConsistent(node.right);
261 assertSame(node, node.right.parent);
262 rightHeight = node.right.height;
263 }
264 if (node.parent != null) {
265 assertTrue(node.parent.left == node || node.parent.right == node);
266 }
267 if (Math.max(leftHeight, rightHeight) + 1 != node.height) {
268 fail();
269 }
270 }
271
272 private String toString(Node<?, ?> root) {
273 if (root == null) {
274 return ".";
275 } else if (root.left == null && root.right == null) {
276 return String.valueOf(root.key);
277 } else {
278 return String.format("(%s %s %s)", toString(root.left), root.key, toString(root.right));
279 }
280 }
281
282 private <T> void assertIterationOrder(Iterable<T> actual, T... expected) {
283 ArrayList<T> actualList = new ArrayList<T>();
284 for (T t : actual) {
285 actualList.add(t);
286 }
287 assertEquals(Arrays.asList(expected), actualList);
288 }
289 }
1515
1616 package com.google.gson.internal;
1717
18 import java.io.ByteArrayInputStream;
19 import java.io.ByteArrayOutputStream;
20 import java.io.IOException;
21 import java.io.ObjectInputStream;
22 import java.io.ObjectOutputStream;
1823 import java.util.ArrayList;
1924 import java.util.Arrays;
25 import java.util.Collections;
2026 import java.util.Iterator;
2127 import java.util.Map;
2228 import java.util.Random;
139145 MoreAsserts.assertEqualsAndHashCode(map1, map2);
140146 }
141147
142 private <T> void assertIterationOrder(Iterable<T> actual, T... expected) {
148 public void testJavaSerialization() throws IOException, ClassNotFoundException {
149 ByteArrayOutputStream out = new ByteArrayOutputStream();
150 ObjectOutputStream objOut = new ObjectOutputStream(out);
151 Map<String, Integer> map = new LinkedTreeMap<String, Integer>();
152 map.put("a", 1);
153 objOut.writeObject(map);
154 objOut.close();
155
156 ObjectInputStream objIn = new ObjectInputStream(new ByteArrayInputStream(out.toByteArray()));
157 @SuppressWarnings("unchecked")
158 Map<String, Integer> deserialized = (Map<String, Integer>) objIn.readObject();
159 assertEquals(Collections.singletonMap("a", 1), deserialized);
160 }
161
162 @SafeVarargs
163 private final <T> void assertIterationOrder(Iterable<T> actual, T... expected) {
143164 ArrayList<T> actualList = new ArrayList<T>();
144165 for (T t : actual) {
145166 actualList.add(t);
0 /*
1 * Copyright (C) 2008 Google Inc.
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 package com.google.gson.internal.bind;
17
18 import java.io.IOException;
19 import java.text.DateFormat;
20 import java.text.SimpleDateFormat;
21 import java.util.Date;
22 import java.util.Locale;
23 import java.util.TimeZone;
24
25 import com.google.gson.Gson;
26 import com.google.gson.TypeAdapter;
27 import com.google.gson.TypeAdapterFactory;
28 import com.google.gson.internal.JavaVersion;
29 import com.google.gson.internal.bind.DefaultDateTypeAdapter.DateType;
30 import com.google.gson.reflect.TypeToken;
31
32 import junit.framework.TestCase;
33
34 /**
35 * A simple unit test for the {@link DefaultDateTypeAdapter} class.
36 *
37 * @author Joel Leitch
38 */
39 public class DefaultDateTypeAdapterTest extends TestCase {
40
41 public void testFormattingInEnUs() {
42 assertFormattingAlwaysEmitsUsLocale(Locale.US);
43 }
44
45 public void testFormattingInFr() {
46 assertFormattingAlwaysEmitsUsLocale(Locale.FRANCE);
47 }
48
49 private void assertFormattingAlwaysEmitsUsLocale(Locale locale) {
50 TimeZone defaultTimeZone = TimeZone.getDefault();
51 TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
52 Locale defaultLocale = Locale.getDefault();
53 Locale.setDefault(locale);
54 try {
55 String afterYearSep = JavaVersion.isJava9OrLater() ? ", " : " ";
56 String afterYearLongSep = JavaVersion.isJava9OrLater() ? " at " : " ";
57 String utcFull = JavaVersion.isJava9OrLater() ? "Coordinated Universal Time" : "UTC";
58 assertFormatted(String.format("Jan 1, 1970%s12:00:00 AM", afterYearSep),
59 DateType.DATE.createDefaultsAdapterFactory());
60 assertFormatted("1/1/70", DateType.DATE.createAdapterFactory(DateFormat.SHORT));
61 assertFormatted("Jan 1, 1970", DateType.DATE.createAdapterFactory(DateFormat.MEDIUM));
62 assertFormatted("January 1, 1970", DateType.DATE.createAdapterFactory(DateFormat.LONG));
63 assertFormatted(String.format("1/1/70%s12:00 AM", afterYearSep),
64 DateType.DATE.createAdapterFactory(DateFormat.SHORT, DateFormat.SHORT));
65 assertFormatted(String.format("Jan 1, 1970%s12:00:00 AM", afterYearSep),
66 DateType.DATE.createAdapterFactory(DateFormat.MEDIUM, DateFormat.MEDIUM));
67 assertFormatted(String.format("January 1, 1970%s12:00:00 AM UTC", afterYearLongSep),
68 DateType.DATE.createAdapterFactory(DateFormat.LONG, DateFormat.LONG));
69 assertFormatted(String.format("Thursday, January 1, 1970%s12:00:00 AM %s", afterYearLongSep, utcFull),
70 DateType.DATE.createAdapterFactory(DateFormat.FULL, DateFormat.FULL));
71 } finally {
72 TimeZone.setDefault(defaultTimeZone);
73 Locale.setDefault(defaultLocale);
74 }
75 }
76
77 public void testParsingDatesFormattedWithSystemLocale() throws Exception {
78 TimeZone defaultTimeZone = TimeZone.getDefault();
79 TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
80 Locale defaultLocale = Locale.getDefault();
81 Locale.setDefault(Locale.FRANCE);
82 try {
83 String afterYearSep = JavaVersion.isJava9OrLater() ? " à " : " ";
84 assertParsed(String.format("1 janv. 1970%s00:00:00", afterYearSep),
85 DateType.DATE.createDefaultsAdapterFactory());
86 assertParsed("01/01/70", DateType.DATE.createAdapterFactory(DateFormat.SHORT));
87 assertParsed("1 janv. 1970", DateType.DATE.createAdapterFactory(DateFormat.MEDIUM));
88 assertParsed("1 janvier 1970", DateType.DATE.createAdapterFactory(DateFormat.LONG));
89 assertParsed("01/01/70 00:00",
90 DateType.DATE.createAdapterFactory(DateFormat.SHORT, DateFormat.SHORT));
91 assertParsed(String.format("1 janv. 1970%s00:00:00", afterYearSep),
92 DateType.DATE.createAdapterFactory(DateFormat.MEDIUM, DateFormat.MEDIUM));
93 assertParsed(String.format("1 janvier 1970%s00:00:00 UTC", afterYearSep),
94 DateType.DATE.createAdapterFactory(DateFormat.LONG, DateFormat.LONG));
95 assertParsed(JavaVersion.isJava9OrLater() ? (JavaVersion.getMajorJavaVersion() <11 ?
96 "jeudi 1 janvier 1970 à 00:00:00 Coordinated Universal Time" :
97 "jeudi 1 janvier 1970 à 00:00:00 Temps universel coordonné") :
98 "jeudi 1 janvier 1970 00 h 00 UTC",
99 DateType.DATE.createAdapterFactory(DateFormat.FULL, DateFormat.FULL));
100 } finally {
101 TimeZone.setDefault(defaultTimeZone);
102 Locale.setDefault(defaultLocale);
103 }
104 }
105
106 public void testParsingDatesFormattedWithUsLocale() throws Exception {
107 TimeZone defaultTimeZone = TimeZone.getDefault();
108 TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
109 Locale defaultLocale = Locale.getDefault();
110 Locale.setDefault(Locale.US);
111 try {
112 assertParsed("Jan 1, 1970 0:00:00 AM", DateType.DATE.createDefaultsAdapterFactory());
113 assertParsed("1/1/70", DateType.DATE.createAdapterFactory(DateFormat.SHORT));
114 assertParsed("Jan 1, 1970", DateType.DATE.createAdapterFactory(DateFormat.MEDIUM));
115 assertParsed("January 1, 1970", DateType.DATE.createAdapterFactory(DateFormat.LONG));
116 assertParsed("1/1/70 0:00 AM",
117 DateType.DATE.createAdapterFactory(DateFormat.SHORT, DateFormat.SHORT));
118 assertParsed("Jan 1, 1970 0:00:00 AM",
119 DateType.DATE.createAdapterFactory(DateFormat.MEDIUM, DateFormat.MEDIUM));
120 assertParsed("January 1, 1970 0:00:00 AM UTC",
121 DateType.DATE.createAdapterFactory(DateFormat.LONG, DateFormat.LONG));
122 assertParsed("Thursday, January 1, 1970 0:00:00 AM UTC",
123 DateType.DATE.createAdapterFactory(DateFormat.FULL, DateFormat.FULL));
124 } finally {
125 TimeZone.setDefault(defaultTimeZone);
126 Locale.setDefault(defaultLocale);
127 }
128 }
129
130 public void testFormatUsesDefaultTimezone() throws Exception {
131 TimeZone defaultTimeZone = TimeZone.getDefault();
132 TimeZone.setDefault(TimeZone.getTimeZone("America/Los_Angeles"));
133 Locale defaultLocale = Locale.getDefault();
134 Locale.setDefault(Locale.US);
135 try {
136 String afterYearSep = JavaVersion.isJava9OrLater() ? ", " : " ";
137 assertFormatted(String.format("Dec 31, 1969%s4:00:00 PM", afterYearSep),
138 DateType.DATE.createDefaultsAdapterFactory());
139 assertParsed("Dec 31, 1969 4:00:00 PM", DateType.DATE.createDefaultsAdapterFactory());
140 } finally {
141 TimeZone.setDefault(defaultTimeZone);
142 Locale.setDefault(defaultLocale);
143 }
144 }
145
146 public void testDateDeserializationISO8601() throws Exception {
147 TypeAdapterFactory adapterFactory = DateType.DATE.createDefaultsAdapterFactory();
148 assertParsed("1970-01-01T00:00:00.000Z", adapterFactory);
149 assertParsed("1970-01-01T00:00Z", adapterFactory);
150 assertParsed("1970-01-01T00:00:00+00:00", adapterFactory);
151 assertParsed("1970-01-01T01:00:00+01:00", adapterFactory);
152 assertParsed("1970-01-01T01:00:00+01", adapterFactory);
153 }
154
155 public void testDateSerialization() throws Exception {
156 int dateStyle = DateFormat.LONG;
157 TypeAdapter<Date> dateTypeAdapter = dateAdapter(DateType.DATE.createAdapterFactory(dateStyle));
158 DateFormat formatter = DateFormat.getDateInstance(dateStyle, Locale.US);
159 Date currentDate = new Date();
160
161 String dateString = dateTypeAdapter.toJson(currentDate);
162 assertEquals(toLiteral(formatter.format(currentDate)), dateString);
163 }
164
165 public void testDatePattern() throws Exception {
166 String pattern = "yyyy-MM-dd";
167 TypeAdapter<Date> dateTypeAdapter = dateAdapter(DateType.DATE.createAdapterFactory(pattern));
168 DateFormat formatter = new SimpleDateFormat(pattern);
169 Date currentDate = new Date();
170
171 String dateString = dateTypeAdapter.toJson(currentDate);
172 assertEquals(toLiteral(formatter.format(currentDate)), dateString);
173 }
174
175 public void testInvalidDatePattern() throws Exception {
176 try {
177 DateType.DATE.createAdapterFactory("I am a bad Date pattern....");
178 fail("Invalid date pattern should fail.");
179 } catch (IllegalArgumentException expected) { }
180 }
181
182 public void testNullValue() throws Exception {
183 TypeAdapter<Date> adapter = dateAdapter(DateType.DATE.createDefaultsAdapterFactory());
184 assertNull(adapter.fromJson("null"));
185 assertEquals("null", adapter.toJson(null));
186 }
187
188 public void testUnexpectedToken() throws Exception {
189 try {
190 TypeAdapter<Date> adapter = dateAdapter(DateType.DATE.createDefaultsAdapterFactory());
191 adapter.fromJson("{}");
192 fail("Unexpected token should fail.");
193 } catch (IllegalStateException expected) { }
194 }
195
196 private static TypeAdapter<Date> dateAdapter(TypeAdapterFactory adapterFactory) {
197 TypeAdapter<Date> adapter = adapterFactory.create(new Gson(), TypeToken.get(Date.class));
198 assertNotNull(adapter);
199 return adapter;
200 }
201
202 private static void assertFormatted(String formatted, TypeAdapterFactory adapterFactory) {
203 TypeAdapter<Date> adapter = dateAdapter(adapterFactory);
204 assertEquals(toLiteral(formatted), adapter.toJson(new Date(0)));
205 }
206
207 private static void assertParsed(String date, TypeAdapterFactory adapterFactory) throws IOException {
208 TypeAdapter<Date> adapter = dateAdapter(adapterFactory);
209 assertEquals(date, new Date(0), adapter.fromJson(toLiteral(date)));
210 assertEquals("ISO 8601", new Date(0), adapter.fromJson(toLiteral("1970-01-01T00:00:00Z")));
211 }
212
213 private static String toLiteral(String s) {
214 return '"' + s + '"';
215 }
216 }
1717
1818 import com.google.gson.JsonElement;
1919 import com.google.gson.JsonParser;
20 import com.google.gson.JsonPrimitive;
2021 import com.google.gson.stream.JsonToken;
2122 import java.io.IOException;
2223 import junit.framework.TestCase;
297298 reader.endArray();
298299 }
299300
301 public void testNextJsonElement() throws IOException {
302 final JsonElement element = JsonParser.parseString("{\"A\": 1, \"B\" : {}, \"C\" : []}");
303 JsonTreeReader reader = new JsonTreeReader(element);
304 reader.beginObject();
305 try {
306 reader.nextJsonElement();
307 fail();
308 } catch (IllegalStateException expected) {
309 }
310 reader.nextName();
311 assertEquals(reader.nextJsonElement(), new JsonPrimitive(1));
312 reader.nextName();
313 reader.beginObject();
314 try {
315 reader.nextJsonElement();
316 fail();
317 } catch (IllegalStateException expected) {
318 }
319 reader.endObject();
320 reader.nextName();
321 reader.beginArray();
322 try {
323 reader.nextJsonElement();
324 fail();
325 } catch (IllegalStateException expected) {
326 }
327 reader.endArray();
328 reader.endObject();
329 try {
330 reader.nextJsonElement();
331 fail();
332 } catch (IllegalStateException expected) {
333 }
334 }
335
300336 public void testEarlyClose() throws IOException {
301337 JsonElement element = JsonParser.parseString("[1, 2, 3]");
302338 JsonTreeReader reader = new JsonTreeReader(element);
4646 in.skipValue();
4747 assertEquals(JsonToken.END_DOCUMENT, in.peek());
4848 }
49
50 public void testHasNext_endOfDocument() throws IOException {
51 JsonTreeReader reader = new JsonTreeReader(new JsonObject());
52 reader.beginObject();
53 reader.endObject();
54 assertFalse(reader.hasNext());
55 }
4956 }
3535
3636 @SuppressWarnings("unused")
3737 private static class Foo1<A> {
38 public Foo2<? extends A> foo2;
38 public Foo2<? extends A> foo2;
3939 }
4040 @SuppressWarnings("unused")
4141 private static class Foo2<B> {
4747 */
4848
4949 public void testRecursiveResolveSimple() {
50 @SuppressWarnings("rawtypes")
5051 TypeAdapter<Foo1> adapter = new Gson().getAdapter(Foo1.class);
51 assertNotNull(adapter);
52 }
53
54 /**
55 * Real-world samples, found in Issues #603 and #440.
56 */
57
58 public void testIssue603PrintStream() {
59 TypeAdapter<PrintStream> adapter = new Gson().getAdapter(PrintStream.class);
60 assertNotNull(adapter);
61 }
62
63 public void testIssue440WeakReference() throws Exception {
64 TypeAdapter<WeakReference> adapter = new Gson().getAdapter(WeakReference.class);
6552 assertNotNull(adapter);
6653 }
6754
10491 }
10592
10693 public void testRecursiveTypeVariablesResolve1() throws Exception {
94 @SuppressWarnings("rawtypes")
10795 TypeAdapter<TestType> adapter = new Gson().getAdapter(TestType.class);
10896 assertNotNull(adapter);
10997 }
11098
11199 public void testRecursiveTypeVariablesResolve12() throws Exception {
100 @SuppressWarnings("rawtypes")
112101 TypeAdapter<TestType2> adapter = new Gson().getAdapter(TestType2.class);
113102 assertNotNull(adapter);
114103 }
00 package com.google.gson.internal.bind.util;
11
2 import org.junit.Rule;
32 import org.junit.Test;
4 import org.junit.rules.ExpectedException;
5
3 import org.junit.function.ThrowingRunnable;
64 import java.text.ParseException;
75 import java.text.ParsePosition;
86 import java.util.*;
97
108 import static org.junit.Assert.assertEquals;
9 import static org.junit.Assert.assertThrows;
1110
1211 public class ISO8601UtilsTest {
13
14 @Rule
15 public final ExpectedException exception = ExpectedException.none();
1612
1713 private static TimeZone utcTimeZone() {
1814 return TimeZone.getTimeZone("UTC");
8682
8783 @Test
8884 public void testDateParseInvalidTime() throws ParseException {
89 String dateStr = "2018-06-25T61:60:62-03:00";
90 exception.expect(ParseException.class);
91 ISO8601Utils.parse(dateStr, new ParsePosition(0));
85 final String dateStr = "2018-06-25T61:60:62-03:00";
86 assertThrows(ParseException.class, new ThrowingRunnable() {
87 @Override
88 public void run() throws Throwable {
89 ISO8601Utils.parse(dateStr, new ParsePosition(0));
90 }
91 });
9292 }
9393 }
+0
-77
gson/src/test/java/com/google/gson/internal/reflect/UnsafeReflectionAccessorTest.java less more
0 /*
1 * Copyright (C) 2018 The Gson authors
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 package com.google.gson.internal.reflect;
16
17 import static org.junit.Assert.assertFalse;
18 import static org.junit.Assert.assertTrue;
19 import static org.junit.Assert.fail;
20
21 import java.lang.reflect.Field;
22 import java.security.Permission;
23
24 import org.junit.Test;
25
26 /**
27 * Unit tests for {@link UnsafeReflectionAccessor}
28 *
29 * @author Inderjeet Singh
30 */
31 public class UnsafeReflectionAccessorTest {
32
33 @Test
34 public void testMakeAccessibleWithUnsafe() throws Exception {
35 UnsafeReflectionAccessor accessor = new UnsafeReflectionAccessor();
36 Field field = ClassWithPrivateFinalFields.class.getDeclaredField("a");
37 try {
38 boolean success = accessor.makeAccessibleWithUnsafe(field);
39 assertTrue(success);
40 } catch (Exception e) {
41 fail("Unsafe didn't work on the JDK");
42 }
43 }
44
45 @Test
46 public void testMakeAccessibleWithRestrictiveSecurityManager() throws Exception {
47 final Permission accessDeclaredMembers = new RuntimePermission("accessDeclaredMembers");
48 final SecurityManager original = System.getSecurityManager();
49 SecurityManager restrictiveManager = new SecurityManager() {
50 @Override
51 public void checkPermission(Permission perm) {
52 if (accessDeclaredMembers.equals(perm)) {
53 throw new SecurityException("nope");
54 }
55 }
56 };
57 System.setSecurityManager(restrictiveManager);
58
59 try {
60 UnsafeReflectionAccessor accessor = new UnsafeReflectionAccessor();
61 Field field = ClassWithPrivateFinalFields.class.getDeclaredField("a");
62 assertFalse("override field should have been inaccessible", accessor.makeAccessibleWithUnsafe(field));
63 accessor.makeAccessible(field);
64 } finally {
65 System.setSecurityManager(original);
66 }
67 }
68
69 @SuppressWarnings("unused")
70 private static final class ClassWithPrivateFinalFields {
71 private final String a;
72 public ClassWithPrivateFinalFields(String a) {
73 this.a = a;
74 }
75 }
76 }
0 package com.google.gson.internal.sql;
1
2 import java.sql.Date;
3 import java.sql.Time;
4 import java.sql.Timestamp;
5 import java.util.Locale;
6 import java.util.TimeZone;
7
8 import com.google.gson.Gson;
9 import com.google.gson.GsonBuilder;
10 import com.google.gson.functional.DefaultTypeAdaptersTest;
11 import com.google.gson.internal.JavaVersion;
12
13 import junit.framework.TestCase;
14
15 public class SqlTypesGsonTest extends TestCase {
16 private Gson gson;
17 private TimeZone oldTimeZone;
18 private Locale oldLocale;
19
20 @Override
21 protected void setUp() throws Exception {
22 super.setUp();
23 this.oldTimeZone = TimeZone.getDefault();
24 TimeZone.setDefault(TimeZone.getTimeZone("America/Los_Angeles"));
25 this.oldLocale = Locale.getDefault();
26 Locale.setDefault(Locale.US);
27 gson = new Gson();
28 }
29
30 @Override
31 protected void tearDown() throws Exception {
32 super.tearDown();
33 TimeZone.setDefault(oldTimeZone);
34 Locale.setDefault(oldLocale);
35 }
36
37 public void testNullSerializationAndDeserialization() {
38 testNullSerializationAndDeserialization(Date.class);
39 testNullSerializationAndDeserialization(Time.class);
40 testNullSerializationAndDeserialization(Timestamp.class);
41 }
42
43 private void testNullSerializationAndDeserialization(Class<?> c) {
44 DefaultTypeAdaptersTest.testNullSerializationAndDeserialization(gson, c);
45 }
46
47 public void testDefaultSqlDateSerialization() {
48 java.sql.Date instant = new java.sql.Date(1259875082000L);
49 String json = gson.toJson(instant);
50 assertEquals("\"Dec 3, 2009\"", json);
51 }
52
53 public void testDefaultSqlDateDeserialization() {
54 String json = "'Dec 3, 2009'";
55 java.sql.Date extracted = gson.fromJson(json, java.sql.Date.class);
56 DefaultTypeAdaptersTest.assertEqualsDate(extracted, 2009, 11, 3);
57 }
58
59 // http://code.google.com/p/google-gson/issues/detail?id=230
60 public void testSqlDateSerialization() throws Exception {
61 TimeZone defaultTimeZone = TimeZone.getDefault();
62 TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
63 Locale defaultLocale = Locale.getDefault();
64 Locale.setDefault(Locale.US);
65 try {
66 java.sql.Date sqlDate = new java.sql.Date(0L);
67 Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd").create();
68 String json = gson.toJson(sqlDate, Timestamp.class);
69 assertEquals("\"1970-01-01\"", json);
70 assertEquals(0, gson.fromJson("\"1970-01-01\"", java.sql.Date.class).getTime());
71 } finally {
72 TimeZone.setDefault(defaultTimeZone);
73 Locale.setDefault(defaultLocale);
74 }
75 }
76
77 public void testDefaultSqlTimeSerialization() {
78 Time now = new Time(1259875082000L);
79 String json = gson.toJson(now);
80 assertEquals("\"01:18:02 PM\"", json);
81 }
82
83 public void testDefaultSqlTimeDeserialization() {
84 String json = "'1:18:02 PM'";
85 Time extracted = gson.fromJson(json, Time.class);
86 DefaultTypeAdaptersTest.assertEqualsTime(extracted, 13, 18, 2);
87 }
88
89 public void testDefaultSqlTimestampSerialization() {
90 Timestamp now = new java.sql.Timestamp(1259875082000L);
91 String json = gson.toJson(now);
92 if (JavaVersion.isJava9OrLater()) {
93 assertEquals("\"Dec 3, 2009, 1:18:02 PM\"", json);
94 } else {
95 assertEquals("\"Dec 3, 2009 1:18:02 PM\"", json);
96 }
97 }
98
99 public void testDefaultSqlTimestampDeserialization() {
100 String json = "'Dec 3, 2009 1:18:02 PM'";
101 Timestamp extracted = gson.fromJson(json, Timestamp.class);
102 DefaultTypeAdaptersTest.assertEqualsDate(extracted, 2009, 11, 3);
103 DefaultTypeAdaptersTest.assertEqualsTime(extracted, 13, 18, 2);
104 }
105
106 // http://code.google.com/p/google-gson/issues/detail?id=230
107 public void testTimestampSerialization() throws Exception {
108 TimeZone defaultTimeZone = TimeZone.getDefault();
109 TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
110 Locale defaultLocale = Locale.getDefault();
111 Locale.setDefault(Locale.US);
112 try {
113 Timestamp timestamp = new Timestamp(0L);
114 Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd").create();
115 String json = gson.toJson(timestamp, Timestamp.class);
116 assertEquals("\"1970-01-01\"", json);
117 assertEquals(0, gson.fromJson("\"1970-01-01\"", Timestamp.class).getTime());
118 } finally {
119 TimeZone.setDefault(defaultTimeZone);
120 Locale.setDefault(defaultLocale);
121 }
122 }
123 }
0 package com.google.gson.internal.sql;
1
2 import junit.framework.TestCase;
3
4 public class SqlTypesSupportTest extends TestCase {
5 public void testSupported() {
6 assertTrue(SqlTypesSupport.SUPPORTS_SQL_TYPES);
7
8 assertNotNull(SqlTypesSupport.DATE_DATE_TYPE);
9 assertNotNull(SqlTypesSupport.TIMESTAMP_DATE_TYPE);
10
11 assertNotNull(SqlTypesSupport.DATE_FACTORY);
12 assertNotNull(SqlTypesSupport.TIME_FACTORY);
13 assertNotNull(SqlTypesSupport.TIMESTAMP_FACTORY);
14 }
15 }
0 /*
1 * Copyright (C) 2016 Google Inc.
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 package com.google.gson.regression;
16
17 import java.io.InputStream;
18 import java.io.IOException;
19 import java.net.URL;
20 import java.util.ArrayList;
21 import java.util.Collections;
22 import java.util.List;
23 import java.util.jar.Manifest;
24
25 import junit.framework.TestCase;
26
27 public class OSGiTest extends TestCase {
28 public void testComGoogleGsonAnnotationsPackage() throws Exception {
29 Manifest mf = findManifest("com.google.gson");
30 String importPkg = mf.getMainAttributes().getValue("Import-Package");
31 assertNotNull("Import-Package statement is there", importPkg);
32 assertSubstring("There should be com.google.gson.annotations dependency", importPkg, "com.google.gson.annotations");
33 }
34
35 public void testSunMiscImportPackage() throws Exception {
36 Manifest mf = findManifest("com.google.gson");
37 String importPkg = mf.getMainAttributes().getValue("Import-Package");
38 assertNotNull("Import-Package statement is there", importPkg);
39 for (String dep : importPkg.split(",")) {
40 if (dep.contains("sun.misc")) {
41 assertSubstring("sun.misc import is optional", dep, "resolution:=optional");
42 return;
43 }
44 }
45 fail("There should be sun.misc dependency, but was: " + importPkg);
46 }
47
48 private Manifest findManifest(String pkg) throws IOException {
49 List<URL> urls = new ArrayList<URL>();
50 for (URL u : Collections.list(getClass().getClassLoader().getResources("META-INF/MANIFEST.MF"))) {
51 InputStream is = u.openStream();
52 Manifest mf = new Manifest(is);
53 is.close();
54 if (pkg.equals(mf.getMainAttributes().getValue("Bundle-SymbolicName"))) {
55 return mf;
56 }
57 urls.add(u);
58 }
59 fail("Cannot find " + pkg + " OSGi bundle manifest among: " + urls);
60 return null;
61 }
62
63 private static void assertSubstring(String msg, String wholeText, String subString) {
64 if (wholeText.contains(subString)) {
65 return;
66 }
67 fail(msg + ". Expecting " + subString + " but was: " + wholeText);
68 }
69 }
4545
4646 @Test public void path() throws IOException {
4747 JsonReader reader = factory.create("{\"a\":[2,true,false,null,\"b\",{\"c\":\"d\"},[3]]}");
48 assertEquals("$", reader.getPath());
49 reader.beginObject();
48 assertEquals("$", reader.getPreviousPath());
49 assertEquals("$", reader.getPath());
50 reader.beginObject();
51 assertEquals("$.", reader.getPreviousPath());
5052 assertEquals("$.", reader.getPath());
5153 reader.nextName();
52 assertEquals("$.a", reader.getPath());
53 reader.beginArray();
54 assertEquals("$.a", reader.getPreviousPath());
55 assertEquals("$.a", reader.getPath());
56 reader.beginArray();
57 assertEquals("$.a[0]", reader.getPreviousPath());
5458 assertEquals("$.a[0]", reader.getPath());
5559 reader.nextInt();
60 assertEquals("$.a[0]", reader.getPreviousPath());
5661 assertEquals("$.a[1]", reader.getPath());
5762 reader.nextBoolean();
63 assertEquals("$.a[1]", reader.getPreviousPath());
5864 assertEquals("$.a[2]", reader.getPath());
5965 reader.nextBoolean();
66 assertEquals("$.a[2]", reader.getPreviousPath());
6067 assertEquals("$.a[3]", reader.getPath());
6168 reader.nextNull();
69 assertEquals("$.a[3]", reader.getPreviousPath());
6270 assertEquals("$.a[4]", reader.getPath());
6371 reader.nextString();
72 assertEquals("$.a[4]", reader.getPreviousPath());
6473 assertEquals("$.a[5]", reader.getPath());
6574 reader.beginObject();
75 assertEquals("$.a[5].", reader.getPreviousPath());
6676 assertEquals("$.a[5].", reader.getPath());
6777 reader.nextName();
78 assertEquals("$.a[5].c", reader.getPreviousPath());
6879 assertEquals("$.a[5].c", reader.getPath());
6980 reader.nextString();
81 assertEquals("$.a[5].c", reader.getPreviousPath());
7082 assertEquals("$.a[5].c", reader.getPath());
7183 reader.endObject();
84 assertEquals("$.a[5]", reader.getPreviousPath());
7285 assertEquals("$.a[6]", reader.getPath());
7386 reader.beginArray();
87 assertEquals("$.a[6][0]", reader.getPreviousPath());
7488 assertEquals("$.a[6][0]", reader.getPath());
7589 reader.nextInt();
90 assertEquals("$.a[6][0]", reader.getPreviousPath());
7691 assertEquals("$.a[6][1]", reader.getPath());
7792 reader.endArray();
93 assertEquals("$.a[6]", reader.getPreviousPath());
7894 assertEquals("$.a[7]", reader.getPath());
7995 reader.endArray();
80 assertEquals("$.a", reader.getPath());
81 reader.endObject();
96 assertEquals("$.a", reader.getPreviousPath());
97 assertEquals("$.a", reader.getPath());
98 reader.endObject();
99 assertEquals("$", reader.getPreviousPath());
82100 assertEquals("$", reader.getPath());
83101 }
84102
85103 @Test public void objectPath() throws IOException {
86104 JsonReader reader = factory.create("{\"a\":1,\"b\":2}");
87 assertEquals("$", reader.getPath());
88
89 reader.peek();
90 assertEquals("$", reader.getPath());
91 reader.beginObject();
105 assertEquals("$", reader.getPreviousPath());
106 assertEquals("$", reader.getPath());
107
108 reader.peek();
109 assertEquals("$", reader.getPreviousPath());
110 assertEquals("$", reader.getPath());
111 reader.beginObject();
112 assertEquals("$.", reader.getPreviousPath());
92113 assertEquals("$.", reader.getPath());
93114
94115 reader.peek();
116 assertEquals("$.", reader.getPreviousPath());
95117 assertEquals("$.", reader.getPath());
96118 reader.nextName();
97 assertEquals("$.a", reader.getPath());
98
99 reader.peek();
100 assertEquals("$.a", reader.getPath());
101 reader.nextInt();
102 assertEquals("$.a", reader.getPath());
103
104 reader.peek();
105 assertEquals("$.a", reader.getPath());
106 reader.nextName();
107 assertEquals("$.b", reader.getPath());
108
109 reader.peek();
110 assertEquals("$.b", reader.getPath());
111 reader.nextInt();
112 assertEquals("$.b", reader.getPath());
113
114 reader.peek();
115 assertEquals("$.b", reader.getPath());
116 reader.endObject();
117 assertEquals("$", reader.getPath());
118
119 reader.peek();
119 assertEquals("$.a", reader.getPreviousPath());
120 assertEquals("$.a", reader.getPath());
121
122 reader.peek();
123 assertEquals("$.a", reader.getPreviousPath());
124 assertEquals("$.a", reader.getPath());
125 reader.nextInt();
126 assertEquals("$.a", reader.getPreviousPath());
127 assertEquals("$.a", reader.getPath());
128
129 reader.peek();
130 assertEquals("$.a", reader.getPreviousPath());
131 assertEquals("$.a", reader.getPath());
132 reader.nextName();
133 assertEquals("$.b", reader.getPreviousPath());
134 assertEquals("$.b", reader.getPath());
135
136 reader.peek();
137 assertEquals("$.b", reader.getPreviousPath());
138 assertEquals("$.b", reader.getPath());
139 reader.nextInt();
140 assertEquals("$.b", reader.getPreviousPath());
141 assertEquals("$.b", reader.getPath());
142
143 reader.peek();
144 assertEquals("$.b", reader.getPreviousPath());
145 assertEquals("$.b", reader.getPath());
146 reader.endObject();
147 assertEquals("$", reader.getPreviousPath());
148 assertEquals("$", reader.getPath());
149
150 reader.peek();
151 assertEquals("$", reader.getPreviousPath());
120152 assertEquals("$", reader.getPath());
121153 reader.close();
154 assertEquals("$", reader.getPreviousPath());
122155 assertEquals("$", reader.getPath());
123156 }
124157
125158 @Test public void arrayPath() throws IOException {
126159 JsonReader reader = factory.create("[1,2]");
127 assertEquals("$", reader.getPath());
128
129 reader.peek();
130 assertEquals("$", reader.getPath());
131 reader.beginArray();
160 assertEquals("$", reader.getPreviousPath());
161 assertEquals("$", reader.getPath());
162
163 reader.peek();
164 assertEquals("$", reader.getPreviousPath());
165 assertEquals("$", reader.getPath());
166 reader.beginArray();
167 assertEquals("$[0]", reader.getPreviousPath());
132168 assertEquals("$[0]", reader.getPath());
133169
134170 reader.peek();
171 assertEquals("$[0]", reader.getPreviousPath());
135172 assertEquals("$[0]", reader.getPath());
136173 reader.nextInt();
137 assertEquals("$[1]", reader.getPath());
138
139 reader.peek();
140 assertEquals("$[1]", reader.getPath());
141 reader.nextInt();
142 assertEquals("$[2]", reader.getPath());
143
144 reader.peek();
145 assertEquals("$[2]", reader.getPath());
146 reader.endArray();
147 assertEquals("$", reader.getPath());
148
149 reader.peek();
174 assertEquals("$[0]", reader.getPreviousPath());
175 assertEquals("$[1]", reader.getPath());
176
177 reader.peek();
178 assertEquals("$[0]", reader.getPreviousPath());
179 assertEquals("$[1]", reader.getPath());
180 reader.nextInt();
181 assertEquals("$[1]", reader.getPreviousPath());
182 assertEquals("$[2]", reader.getPath());
183
184 reader.peek();
185 assertEquals("$[1]", reader.getPreviousPath());
186 assertEquals("$[2]", reader.getPath());
187 reader.endArray();
188 assertEquals("$", reader.getPreviousPath());
189 assertEquals("$", reader.getPath());
190
191 reader.peek();
192 assertEquals("$", reader.getPreviousPath());
150193 assertEquals("$", reader.getPath());
151194 reader.close();
195 assertEquals("$", reader.getPreviousPath());
152196 assertEquals("$", reader.getPath());
153197 }
154198
159203 reader.setLenient(true);
160204 reader.beginArray();
161205 reader.endArray();
162 assertEquals("$", reader.getPath());
163 reader.beginArray();
164 reader.endArray();
206 assertEquals("$", reader.getPreviousPath());
207 assertEquals("$", reader.getPath());
208 reader.beginArray();
209 reader.endArray();
210 assertEquals("$", reader.getPreviousPath());
165211 assertEquals("$", reader.getPath());
166212 }
167213
170216 reader.beginArray();
171217 reader.skipValue();
172218 reader.skipValue();
219 assertEquals("$[1]", reader.getPreviousPath());
173220 assertEquals("$[2]", reader.getPath());
174221 }
175222
177224 JsonReader reader = factory.create("{\"a\":1}");
178225 reader.beginObject();
179226 reader.skipValue();
227 assertEquals("$.null", reader.getPreviousPath());
180228 assertEquals("$.null", reader.getPath());
181229 }
182230
183231 @Test public void skipObjectValues() throws IOException {
184232 JsonReader reader = factory.create("{\"a\":1,\"b\":2}");
185233 reader.beginObject();
234 assertEquals("$.", reader.getPreviousPath());
186235 assertEquals("$.", reader.getPath());
187236 reader.nextName();
188237 reader.skipValue();
238 assertEquals("$.null", reader.getPreviousPath());
189239 assertEquals("$.null", reader.getPath());
190240 reader.nextName();
241 assertEquals("$.b", reader.getPreviousPath());
191242 assertEquals("$.b", reader.getPath());
192243 }
193244
195246 JsonReader reader = factory.create("[[1,2,3],4]");
196247 reader.beginArray();
197248 reader.skipValue();
249 assertEquals("$[0]", reader.getPreviousPath());
198250 assertEquals("$[1]", reader.getPath());
199251 }
200252
201253 @Test public void arrayOfObjects() throws IOException {
202254 JsonReader reader = factory.create("[{},{},{}]");
203255 reader.beginArray();
256 assertEquals("$[0]", reader.getPreviousPath());
204257 assertEquals("$[0]", reader.getPath());
205258 reader.beginObject();
259 assertEquals("$[0].", reader.getPreviousPath());
206260 assertEquals("$[0].", reader.getPath());
207261 reader.endObject();
208 assertEquals("$[1]", reader.getPath());
209 reader.beginObject();
262 assertEquals("$[0]", reader.getPreviousPath());
263 assertEquals("$[1]", reader.getPath());
264 reader.beginObject();
265 assertEquals("$[1].", reader.getPreviousPath());
210266 assertEquals("$[1].", reader.getPath());
211267 reader.endObject();
212 assertEquals("$[2]", reader.getPath());
213 reader.beginObject();
268 assertEquals("$[1]", reader.getPreviousPath());
269 assertEquals("$[2]", reader.getPath());
270 reader.beginObject();
271 assertEquals("$[2].", reader.getPreviousPath());
214272 assertEquals("$[2].", reader.getPath());
215273 reader.endObject();
274 assertEquals("$[2]", reader.getPreviousPath());
216275 assertEquals("$[3]", reader.getPath());
217276 reader.endArray();
277 assertEquals("$", reader.getPreviousPath());
218278 assertEquals("$", reader.getPath());
219279 }
220280
221281 @Test public void arrayOfArrays() throws IOException {
222282 JsonReader reader = factory.create("[[],[],[]]");
223283 reader.beginArray();
284 assertEquals("$[0]", reader.getPreviousPath());
224285 assertEquals("$[0]", reader.getPath());
225286 reader.beginArray();
287 assertEquals("$[0][0]", reader.getPreviousPath());
226288 assertEquals("$[0][0]", reader.getPath());
227289 reader.endArray();
228 assertEquals("$[1]", reader.getPath());
229 reader.beginArray();
290 assertEquals("$[0]", reader.getPreviousPath());
291 assertEquals("$[1]", reader.getPath());
292 reader.beginArray();
293 assertEquals("$[1][0]", reader.getPreviousPath());
230294 assertEquals("$[1][0]", reader.getPath());
231295 reader.endArray();
232 assertEquals("$[2]", reader.getPath());
233 reader.beginArray();
296 assertEquals("$[1]", reader.getPreviousPath());
297 assertEquals("$[2]", reader.getPath());
298 reader.beginArray();
299 assertEquals("$[2][0]", reader.getPreviousPath());
234300 assertEquals("$[2][0]", reader.getPath());
235301 reader.endArray();
302 assertEquals("$[2]", reader.getPreviousPath());
236303 assertEquals("$[3]", reader.getPath());
237304 reader.endArray();
238 assertEquals("$", reader.getPath());
239 }
240
241 enum Factory {
305 assertEquals("$", reader.getPreviousPath());
306 assertEquals("$", reader.getPath());
307 }
308
309 public enum Factory {
242310 STRING_READER {
243311 @Override public JsonReader create(String data) {
244312 return new JsonReader(new StringReader(data));
7171 assertEquals(JsonToken.END_DOCUMENT, reader.peek());
7272 }
7373
74 public void testHasNextEndOfDocument() throws IOException {
75 JsonReader reader = new JsonReader(reader("{}"));
76 reader.beginObject();
77 reader.endObject();
78 assertFalse(reader.hasNext());
79 }
80
7481 public void testSkipArray() throws IOException {
7582 JsonReader reader = new JsonReader(reader(
7683 "{\"a\": [\"one\", \"two\", \"three\"], \"b\": 123}"));
187194 } catch (IOException expected) {
188195 }
189196 }
190
197
191198 @SuppressWarnings("unused")
192199 public void testNulls() {
193200 try {
303310 + "1.7976931348623157E308,"
304311 + "4.9E-324,"
305312 + "0.0,"
313 + "0.00,"
306314 + "-0.5,"
307315 + "2.2250738585072014E-308,"
308316 + "3.141592653589793,"
309 + "2.718281828459045]";
317 + "2.718281828459045,"
318 + "0,"
319 + "0.01,"
320 + "0e0,"
321 + "1e+0,"
322 + "1e-0,"
323 + "1e0000," // leading 0 is allowed for exponent
324 + "1e00001,"
325 + "1e+1]";
310326 JsonReader reader = new JsonReader(reader(json));
311327 reader.beginArray();
312328 assertEquals(-0.0, reader.nextDouble());
314330 assertEquals(1.7976931348623157E308, reader.nextDouble());
315331 assertEquals(4.9E-324, reader.nextDouble());
316332 assertEquals(0.0, reader.nextDouble());
333 assertEquals(0.0, reader.nextDouble());
317334 assertEquals(-0.5, reader.nextDouble());
318335 assertEquals(2.2250738585072014E-308, reader.nextDouble());
319336 assertEquals(3.141592653589793, reader.nextDouble());
320337 assertEquals(2.718281828459045, reader.nextDouble());
338 assertEquals(0.0, reader.nextDouble());
339 assertEquals(0.01, reader.nextDouble());
340 assertEquals(0.0, reader.nextDouble());
341 assertEquals(1.0, reader.nextDouble());
342 assertEquals(1.0, reader.nextDouble());
343 assertEquals(1.0, reader.nextDouble());
344 assertEquals(10.0, reader.nextDouble());
345 assertEquals(10.0, reader.nextDouble());
321346 reader.endArray();
322347 assertEquals(JsonToken.END_DOCUMENT, reader.peek());
323348 }
466491 assertNotANumber("-");
467492 assertNotANumber(".");
468493
494 // plus sign is not allowed for integer part
495 assertNotANumber("+1");
496
497 // leading 0 is not allowed for integer part
498 assertNotANumber("00");
499 assertNotANumber("01");
500
469501 // exponent lacks digit
470502 assertNotANumber("e");
471503 assertNotANumber("0e");
500532 }
501533
502534 private void assertNotANumber(String s) throws IOException {
503 JsonReader reader = new JsonReader(reader("[" + s + "]"));
504 reader.setLenient(true);
505 reader.beginArray();
535 JsonReader reader = new JsonReader(reader(s));
536 reader.setLenient(true);
506537 assertEquals(JsonToken.STRING, reader.peek());
507538 assertEquals(s, reader.nextString());
508 reader.endArray();
539
540 JsonReader strictReader = new JsonReader(reader(s));
541 try {
542 strictReader.nextDouble();
543 fail("Should have failed reading " + s + " as double");
544 } catch (MalformedJsonException e) {
545 }
509546 }
510547
511548 public void testPeekingUnquotedStringsPrefixedWithIntegers() throws IOException {
560597 } catch (NumberFormatException expected) {
561598 }
562599 }
563
600
564601 /**
565602 * Issue 1053, negative zero.
566603 * @throws Exception
567604 */
568605 public void testNegativeZero() throws Exception {
569 JsonReader reader = new JsonReader(reader("[-0]"));
570 reader.setLenient(false);
571 reader.beginArray();
572 assertEquals(NUMBER, reader.peek());
573 assertEquals("-0", reader.nextString());
606 JsonReader reader = new JsonReader(reader("[-0]"));
607 reader.setLenient(false);
608 reader.beginArray();
609 assertEquals(NUMBER, reader.peek());
610 assertEquals("-0", reader.nextString());
574611 }
575612
576613 /**
17291766 }
17301767 }
17311768
1769 /**
1770 * Regression test for an issue with buffer filling and consumeNonExecutePrefix.
1771 */
1772 public void testReadAcrossBuffers() throws IOException {
1773 StringBuilder sb = new StringBuilder("#");
1774 for (int i = 0; i < JsonReader.BUFFER_SIZE - 3; i++) {
1775 sb.append(' ');
1776 }
1777 sb.append("\n)]}'\n3");
1778 JsonReader reader = new JsonReader(reader(sb.toString()));
1779 reader.setLenient(true);
1780 JsonToken token = reader.peek();
1781 assertEquals(JsonToken.NUMBER, token);
1782 }
1783
17321784 private void assertDocument(String document, Object... expectations) throws IOException {
17331785 JsonReader reader = new JsonReader(reader(document));
17341786 reader.setLenient(true);
1515
1616 package com.google.gson.stream;
1717
18 import junit.framework.TestCase;
19
18 import com.google.gson.internal.LazilyParsedNumber;
2019 import java.io.IOException;
2120 import java.io.StringWriter;
2221 import java.math.BigDecimal;
2322 import java.math.BigInteger;
23 import junit.framework.TestCase;
2424
2525 @SuppressWarnings("resource")
2626 public final class JsonWriterTest extends TestCase {
179179 jsonWriter.value(Double.NaN);
180180 fail();
181181 } catch (IllegalArgumentException expected) {
182 assertEquals("Numeric values must be finite, but was NaN", expected.getMessage());
182183 }
183184 try {
184185 jsonWriter.value(Double.NEGATIVE_INFINITY);
185186 fail();
186187 } catch (IllegalArgumentException expected) {
188 assertEquals("Numeric values must be finite, but was -Infinity", expected.getMessage());
187189 }
188190 try {
189191 jsonWriter.value(Double.POSITIVE_INFINITY);
190192 fail();
191193 } catch (IllegalArgumentException expected) {
192 }
193 }
194
195 public void testNonFiniteBoxedDoubles() throws IOException {
194 assertEquals("Numeric values must be finite, but was Infinity", expected.getMessage());
195 }
196 }
197
198 public void testNonFiniteNumbers() throws IOException {
196199 StringWriter stringWriter = new StringWriter();
197200 JsonWriter jsonWriter = new JsonWriter(stringWriter);
198201 jsonWriter.beginArray();
200203 jsonWriter.value(Double.valueOf(Double.NaN));
201204 fail();
202205 } catch (IllegalArgumentException expected) {
206 assertEquals("Numeric values must be finite, but was NaN", expected.getMessage());
203207 }
204208 try {
205209 jsonWriter.value(Double.valueOf(Double.NEGATIVE_INFINITY));
206210 fail();
207211 } catch (IllegalArgumentException expected) {
212 assertEquals("Numeric values must be finite, but was -Infinity", expected.getMessage());
208213 }
209214 try {
210215 jsonWriter.value(Double.valueOf(Double.POSITIVE_INFINITY));
211216 fail();
212217 } catch (IllegalArgumentException expected) {
218 assertEquals("Numeric values must be finite, but was Infinity", expected.getMessage());
219 }
220 try {
221 jsonWriter.value(new LazilyParsedNumber("Infinity"));
222 fail();
223 } catch (IllegalArgumentException expected) {
224 assertEquals("Numeric values must be finite, but was Infinity", expected.getMessage());
213225 }
214226 }
215227
225237 assertEquals("[NaN,-Infinity,Infinity]", stringWriter.toString());
226238 }
227239
228 public void testNonFiniteBoxedDoublesWhenLenient() throws IOException {
240 public void testNonFiniteNumbersWhenLenient() throws IOException {
229241 StringWriter stringWriter = new StringWriter();
230242 JsonWriter jsonWriter = new JsonWriter(stringWriter);
231243 jsonWriter.setLenient(true);
233245 jsonWriter.value(Double.valueOf(Double.NaN));
234246 jsonWriter.value(Double.valueOf(Double.NEGATIVE_INFINITY));
235247 jsonWriter.value(Double.valueOf(Double.POSITIVE_INFINITY));
236 jsonWriter.endArray();
237 assertEquals("[NaN,-Infinity,Infinity]", stringWriter.toString());
248 jsonWriter.value(new LazilyParsedNumber("Infinity"));
249 jsonWriter.endArray();
250 assertEquals("[NaN,-Infinity,Infinity,Infinity]", stringWriter.toString());
238251 }
239252
240253 public void testDoubles() throws IOException {
295308 + "9223372036854775808,"
296309 + "-9223372036854775809,"
297310 + "3.141592653589793238462643383]", stringWriter.toString());
311 }
312
313 /**
314 * Tests writing {@code Number} instances which are not one of the standard JDK ones.
315 */
316 public void testNumbersCustomClass() throws IOException {
317 String[] validNumbers = {
318 "-0.0",
319 "1.0",
320 "1.7976931348623157E308",
321 "4.9E-324",
322 "0.0",
323 "0.00",
324 "-0.5",
325 "2.2250738585072014E-308",
326 "3.141592653589793",
327 "2.718281828459045",
328 "0",
329 "0.01",
330 "0e0",
331 "1e+0",
332 "1e-0",
333 "1e0000", // leading 0 is allowed for exponent
334 "1e00001",
335 "1e+1",
336 };
337
338 for (String validNumber : validNumbers) {
339 StringWriter stringWriter = new StringWriter();
340 JsonWriter jsonWriter = new JsonWriter(stringWriter);
341
342 jsonWriter.value(new LazilyParsedNumber(validNumber));
343 jsonWriter.close();
344
345 assertEquals(validNumber, stringWriter.toString());
346 }
347 }
348
349 public void testMalformedNumbers() throws IOException {
350 String[] malformedNumbers = {
351 "some text",
352 "",
353 ".",
354 "00",
355 "01",
356 "-00",
357 "-",
358 "--1",
359 "+1", // plus sign is not allowed for integer part
360 "+",
361 "1,0",
362 "1,000",
363 "0.", // decimal digit is required
364 ".1", // integer part is required
365 "e1",
366 ".e1",
367 ".1e1",
368 "1e-",
369 "1e+",
370 "1e--1",
371 "1e+-1",
372 "1e1e1",
373 "1+e1",
374 "1e1.0",
375 };
376
377 for (String malformedNumber : malformedNumbers) {
378 JsonWriter jsonWriter = new JsonWriter(new StringWriter());
379 try {
380 jsonWriter.value(new LazilyParsedNumber(malformedNumber));
381 fail("Should have failed writing malformed number: " + malformedNumber);
382 } catch (IllegalArgumentException e) {
383 assertEquals("String created by class com.google.gson.internal.LazilyParsedNumber is not a valid JSON number: " + malformedNumber, e.getMessage());
384 }
385 }
298386 }
299387
300388 public void testBooleans() throws IOException {
22 -optimizations !code/simplification/arithmetic,!code/simplification/cast,!field/*,!class/merging/*
33 -optimizationpasses 5
44 -allowaccessmodification
5 # On Windows mixed case class names might cause problems
6 -dontusemixedcaseclassnames
57 -keepattributes *Annotation*,Signature,InnerClasses,EnclosingMethod
68 -keepclassmembers enum * {
79 public static **[] values();
1618
1719 -dontwarn com.google.gson.functional.EnumWithObfuscatedTest
1820 -dontwarn junit.framework.TestCase
19
21 # Ignore notes about duplicate JDK classes
22 -dontnote module-info,jdk.internal.**
0 # metrics
1
2 This Maven module contains the source code for running internal benchmark tests against Gson.
0 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
1 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
0 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
21 <modelVersion>4.0.0</modelVersion>
3 <groupId>com.google.code.gson</groupId>
2 <parent>
3 <groupId>com.google.code.gson</groupId>
4 <artifactId>gson-parent</artifactId>
5 <version>2.9.0</version>
6 </parent>
7
48 <artifactId>gson-metrics</artifactId>
5 <packaging>jar</packaging>
6 <version>1.0-SNAPSHOT</version>
79 <inceptionYear>2011</inceptionYear>
810 <name>Gson Metrics</name>
9 <parent>
10 <groupId>org.sonatype.oss</groupId>
11 <artifactId>oss-parent</artifactId>
12 <version>5</version>
13 </parent>
14 <url>http://code.google.com/p/google-gson/</url>
1511 <description>Performance Metrics for Google Gson library</description>
16 <properties>
17 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
18 </properties>
12
1913 <licenses>
2014 <license>
21 <name>The Apache Software License, Version 2.0</name>
22 <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
23 <distribution>repo</distribution>
15 <name>Apache-2.0</name>
16 <url>https://www.apache.org/licenses/LICENSE-2.0.txt</url>
2417 </license>
2518 </licenses>
26 <scm>
27 <connection>scm:svn:http://google-gson.googlecode.com/svn/trunk/metrics</connection>
28 <developerConnection>scm:svn:https://google-gson.googlecode.com/svn/trunk/metrics</developerConnection>
29 <url>http://google-gson.codegoogle.com/svn/trunk/metrics</url>
30 </scm>
31 <issueManagement>
32 <system>Google Code Issue Tracking</system>
33 <url>http://code.google.com/p/google-gson/issues/list</url>
34 </issueManagement>
19
3520 <organization>
3621 <name>Google, Inc.</name>
37 <url>http://www.google.com</url>
22 <url>https://www.google.com</url>
3823 </organization>
24
3925 <dependencies>
4026 <dependency>
4127 <groupId>com.google.code.gson</groupId>
4228 <artifactId>gson</artifactId>
43 <version>1.7.2-SNAPSHOT</version>
29 <version>${project.parent.version}</version>
4430 </dependency>
4531 <dependency>
46 <groupId>com.google.code.caliper</groupId>
47 <artifactId>caliper</artifactId>
48 <version>1.0-SNAPSHOT</version>
32 <groupId>com.fasterxml.jackson.core</groupId>
33 <artifactId>jackson-databind</artifactId>
34 <version>2.13.1</version>
4935 </dependency>
5036 <dependency>
51 <groupId>junit</groupId>
52 <artifactId>junit</artifactId>
53 <version>4.13.1</version>
54 <scope>test</scope>
37 <groupId>com.google.caliper</groupId>
38 <artifactId>caliper</artifactId>
39 <version>1.0-beta-3</version>
5540 </dependency>
5641 </dependencies>
42
5743 <build>
58 <defaultGoal>package</defaultGoal>
59 <plugins>
60 <plugin>
61 <groupId>org.apache.maven.plugins</groupId>
62 <artifactId>maven-compiler-plugin</artifactId>
63 <version>2.3.2</version>
64 <configuration>
65 <source>1.6</source>
66 <target>1.6</target>
67 </configuration>
68 </plugin>
69 <plugin>
70 <groupId>org.apache.maven.plugins</groupId>
71 <artifactId>maven-eclipse-plugin</artifactId>
72 <version>2.8</version>
73 <configuration>
74 <downloadSources>true</downloadSources>
75 <downloadJavadocs>true</downloadJavadocs>
76 <workspace>../eclipse-ws/</workspace>
77 <workspaceCodeStylesURL>
78 file:///${basedir}/../lib/gson-formatting-styles.xml
79 </workspaceCodeStylesURL>
80 </configuration>
81 </plugin>
82 <plugin>
83 <groupId>org.apache.maven.plugins</groupId>
84 <artifactId>maven-release-plugin</artifactId>
85 <version>2.1</version>
86 <configuration>
87 <arguments>-DenableCiProfile=true</arguments>
88 <tagBase>https://google-gson.googlecode.com/svn/tags/</tagBase>
89 </configuration>
90 </plugin>
91 <plugin>
92 <groupId>org.apache.maven.plugins</groupId>
93 <artifactId>maven-source-plugin</artifactId>
94 <version>2.1.2</version>
95 <executions>
96 <execution>
97 <id>attach-sources</id>
98 <goals>
99 <goal>jar</goal>
100 </goals>
101 </execution>
102 </executions>
103 </plugin>
104 <plugin>
105 <groupId>org.apache.maven.plugins</groupId>
106 <artifactId>maven-javadoc-plugin</artifactId>
107 <version>2.7</version>
108 <executions>
109 <execution>
110 <id>attach-javadocs</id>
111 <goals>
112 <goal>jar</goal>
113 </goals>
114 </execution>
115 </executions>
116 <configuration>
117 <links>
118 <link>http://download.oracle.com/javase/1.5.0/docs/api/</link>
119 </links>
120 <version>true</version>
121 <show>public</show>
122 </configuration>
123 </plugin>
124 </plugins>
44 <pluginManagement>
45 <plugins>
46 <plugin>
47 <groupId>org.apache.maven.plugins</groupId>
48 <artifactId>maven-deploy-plugin</artifactId>
49 <version>3.0.0-M2</version>
50 <configuration>
51 <!-- Not deployed -->
52 <skip>true</skip>
53 </configuration>
54 </plugin>
55 </plugins>
56 </pluginManagement>
12557 </build>
58
12659 <developers>
12760 <developer>
12861 <name>Inderjeet Singh</name>
1414 */
1515 package com.google.gson.metrics;
1616
17 import com.google.caliper.BeforeExperiment;
18 import com.google.gson.Gson;
19 import com.google.gson.stream.JsonReader;
1720 import java.io.IOException;
1821 import java.io.StringReader;
1922 import java.lang.reflect.Field;
20
21 import com.google.caliper.Runner;
22 import com.google.caliper.SimpleBenchmark;
23 import com.google.gson.Gson;
24 import com.google.gson.stream.JsonReader;
2523
2624 /**
2725 * Caliper based micro benchmarks for Gson
3028 * @author Jesse Wilson
3129 * @author Joel Leitch
3230 */
33 public class BagOfPrimitivesDeserializationBenchmark extends SimpleBenchmark {
31 public class BagOfPrimitivesDeserializationBenchmark {
3432
3533 private Gson gson;
3634 private String json;
3735
3836 public static void main(String[] args) {
39 Runner.main(BagOfPrimitivesDeserializationBenchmark.class, args);
37 NonUploadingCaliperRunner.run(BagOfPrimitivesDeserializationBenchmark.class, args);
4038 }
4139
42 @Override
43 protected void setUp() throws Exception {
40 @BeforeExperiment
41 void setUp() throws Exception {
4442 this.gson = new Gson();
4543 BagOfPrimitives bag = new BagOfPrimitives(10L, 1, false, "foo");
4644 this.json = gson.toJson(bag);
1414 */
1515 package com.google.gson.metrics;
1616
17 import com.google.caliper.BeforeExperiment;
18 import com.google.gson.Gson;
19 import com.google.gson.reflect.TypeToken;
20 import com.google.gson.stream.JsonReader;
1721 import java.io.IOException;
1822 import java.io.StringReader;
1923 import java.lang.reflect.Field;
2125 import java.util.ArrayList;
2226 import java.util.List;
2327
24 import com.google.caliper.Runner;
25 import com.google.caliper.SimpleBenchmark;
26 import com.google.gson.Gson;
27 import com.google.gson.reflect.TypeToken;
28 import com.google.gson.stream.JsonReader;
29
3028 /**
3129 * Caliper based micro benchmarks for Gson
3230 *
3331 * @author Inderjeet Singh
3432 */
35 public class CollectionsDeserializationBenchmark extends SimpleBenchmark {
33 public class CollectionsDeserializationBenchmark {
3634
3735 private static final Type LIST_TYPE = new TypeToken<List<BagOfPrimitives>>(){}.getType();
3836 private Gson gson;
3937 private String json;
4038
4139 public static void main(String[] args) {
42 Runner.main(CollectionsDeserializationBenchmark.class, args);
40 NonUploadingCaliperRunner.run(CollectionsDeserializationBenchmark.class, args);
4341 }
4442
45 @Override
46 protected void setUp() throws Exception {
43 @BeforeExperiment
44 void setUp() throws Exception {
4745 this.gson = new Gson();
4846 List<BagOfPrimitives> bags = new ArrayList<BagOfPrimitives>();
4947 for (int i = 0; i < 100; ++i) {
0 package com.google.gson.metrics;
1
2 import com.google.caliper.runner.CaliperMain;
3
4 class NonUploadingCaliperRunner {
5 private static String[] concat(String first, String... others) {
6 if (others.length == 0) {
7 return new String[] { first };
8 } else {
9 String[] result = new String[others.length + 1];
10 result[0] = first;
11 System.arraycopy(others, 0, result, 1, others.length);
12 return result;
13 }
14 }
15
16 public static void run(Class<?> c, String[] args) {
17 // Disable result upload; Caliper uploads results to webapp by default, see https://github.com/google/caliper/issues/356
18 CaliperMain.main(c, concat("-Cresults.upload.options.url=", args));
19 }
20 }
1515
1616 package com.google.gson.metrics;
1717
18 import com.fasterxml.jackson.annotation.JsonProperty;
19 import com.fasterxml.jackson.core.JsonFactory;
20 import com.fasterxml.jackson.core.JsonFactoryBuilder;
21 import com.fasterxml.jackson.core.type.TypeReference;
22 import com.fasterxml.jackson.databind.DeserializationFeature;
23 import com.fasterxml.jackson.databind.MapperFeature;
24 import com.fasterxml.jackson.databind.ObjectMapper;
25 import com.fasterxml.jackson.databind.json.JsonMapper;
26 import com.google.caliper.BeforeExperiment;
1827 import com.google.caliper.Param;
19 import com.google.caliper.Runner;
20 import com.google.caliper.SimpleBenchmark;
2128 import com.google.gson.Gson;
2229 import com.google.gson.GsonBuilder;
2330 import com.google.gson.JsonParser;
2431 import com.google.gson.annotations.SerializedName;
2532 import com.google.gson.reflect.TypeToken;
2633 import java.io.CharArrayReader;
34 import java.io.File;
2735 import java.io.IOException;
28 import java.io.InputStream;
2936 import java.io.InputStreamReader;
3037 import java.io.Reader;
3138 import java.io.StringWriter;
3239 import java.lang.reflect.Type;
40 import java.net.URL;
3341 import java.text.SimpleDateFormat;
3442 import java.util.Date;
3543 import java.util.List;
36 import org.codehaus.jackson.JsonFactory;
37 import org.codehaus.jackson.annotate.JsonProperty;
38 import org.codehaus.jackson.map.DeserializationConfig;
39 import org.codehaus.jackson.map.ObjectMapper;
40 import org.codehaus.jackson.type.TypeReference;
44 import java.util.Locale;
45 import java.util.zip.ZipEntry;
46 import java.util.zip.ZipFile;
4147
4248 /**
4349 * Measure Gson and Jackson parsing and binding performance.
4652 * That file contains Twitter feed data, which is representative of what
4753 * applications will be parsing.
4854 */
49 public final class ParseBenchmark extends SimpleBenchmark {
55 public final class ParseBenchmark {
5056 @Param Document document;
5157 @Param Api api;
5258
101107 private char[] text;
102108 private Parser parser;
103109
104 @Override protected void setUp() throws Exception {
105 text = resourceToString("/" + document.name() + ".json").toCharArray();
110 @BeforeExperiment
111 void setUp() throws Exception {
112 text = resourceToString(document.name() + ".json").toCharArray();
106113 parser = api.newParser();
107114 }
108115
112119 }
113120 }
114121
115 private static String resourceToString(String path) throws Exception {
116 InputStream in = ParseBenchmark.class.getResourceAsStream(path);
117 if (in == null) {
118 throw new IllegalArgumentException("No such file: " + path);
119 }
120
121 Reader reader = new InputStreamReader(in, "UTF-8");
122 char[] buffer = new char[8192];
123 StringWriter writer = new StringWriter();
124 int count;
125 while ((count = reader.read(buffer)) != -1) {
126 writer.write(buffer, 0, count);
127 }
128 reader.close();
129 return writer.toString();
122 private static File getResourceFile(String path) throws Exception {
123 URL url = ParseBenchmark.class.getResource(path);
124 if (url == null) {
125 throw new IllegalArgumentException("Resource " + path + " does not exist");
126 }
127 File file = new File(url.toURI());
128 if (!file.isFile()) {
129 throw new IllegalArgumentException("Resource " + path + " is not a file");
130 }
131 return file;
132 }
133
134 private static String resourceToString(String fileName) throws Exception {
135 ZipFile zipFile = new ZipFile(getResourceFile("/ParseBenchmarkData.zip"));
136 try {
137 ZipEntry zipEntry = zipFile.getEntry(fileName);
138 Reader reader = new InputStreamReader(zipFile.getInputStream(zipEntry));
139 char[] buffer = new char[8192];
140 StringWriter writer = new StringWriter();
141 int count;
142 while ((count = reader.read(buffer)) != -1) {
143 writer.write(buffer, 0, count);
144 }
145 reader.close();
146 return writer.toString();
147
148 } finally {
149 zipFile.close();
150 }
130151 }
131152
132153 public static void main(String[] args) throws Exception {
133 Runner.main(ParseBenchmark.class, args);
154 NonUploadingCaliperRunner.run(ParseBenchmark.class, args);
134155 }
135156
136157 interface Parser {
138159 }
139160
140161 private static class GsonStreamParser implements Parser {
162 @Override
141163 public void parse(char[] data, Document document) throws Exception {
142164 com.google.gson.stream.JsonReader jsonReader
143165 = new com.google.gson.stream.JsonReader(new CharArrayReader(data));
185207 }
186208
187209 private static class GsonSkipParser implements Parser {
210 @Override
188211 public void parse(char[] data, Document document) throws Exception {
189212 com.google.gson.stream.JsonReader jsonReader
190213 = new com.google.gson.stream.JsonReader(new CharArrayReader(data));
194217 }
195218
196219 private static class JacksonStreamParser implements Parser {
197 public void parse(char[] data, Document document) throws Exception {
198 JsonFactory jsonFactory = new JsonFactory();
199 org.codehaus.jackson.JsonParser jp = jsonFactory.createJsonParser(new CharArrayReader(data));
200 jp.configure(org.codehaus.jackson.JsonParser.Feature.CANONICALIZE_FIELD_NAMES, false);
220 @Override
221 public void parse(char[] data, Document document) throws Exception {
222 JsonFactory jsonFactory = new JsonFactoryBuilder().configure(JsonFactory.Feature.CANONICALIZE_FIELD_NAMES, false).build();
223 com.fasterxml.jackson.core.JsonParser jp = jsonFactory.createParser(new CharArrayReader(data));
201224 int depth = 0;
202225 do {
203226 switch (jp.nextToken()) {
226249 }
227250
228251 private static class GsonDomParser implements Parser {
229 public void parse(char[] data, Document document) throws Exception {
230 new JsonParser().parse(new CharArrayReader(data));
252 @Override
253 public void parse(char[] data, Document document) throws Exception {
254 JsonParser.parseReader(new CharArrayReader(data));
231255 }
232256 }
233257
236260 .setDateFormat("EEE MMM dd HH:mm:ss Z yyyy")
237261 .create();
238262
263 @Override
239264 public void parse(char[] data, Document document) throws Exception {
240265 gson.fromJson(new CharArrayReader(data), document.gsonType);
241266 }
242267 }
243268
244269 private static class JacksonBindParser implements Parser {
245 private static ObjectMapper mapper = new ObjectMapper();
270 private static final ObjectMapper mapper;
246271
247272 static {
248 mapper.configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);
249 mapper.configure(DeserializationConfig.Feature.AUTO_DETECT_FIELDS, true);
250 mapper.setDateFormat(new SimpleDateFormat("EEE MMM dd HH:mm:ss Z yyyy"));
251 }
252
273 mapper = JsonMapper.builder()
274 .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
275 .configure(MapperFeature.AUTO_DETECT_FIELDS, true)
276 .build();
277 mapper.setDateFormat(new SimpleDateFormat("EEE MMM dd HH:mm:ss Z yyyy", Locale.ENGLISH));
278 }
279
280 @Override
253281 public void parse(char[] data, Document document) throws Exception {
254282 mapper.readValue(new CharArrayReader(data), document.jacksonType);
255283 }
metrics/src/main/java/com/google/gson/metrics/ParseBenchmarkData.zip less more
Binary diff not shown
1414 */
1515 package com.google.gson.metrics;
1616
17 import com.google.caliper.BeforeExperiment;
1718 import com.google.caliper.Param;
18 import com.google.caliper.Runner;
19 import com.google.caliper.SimpleBenchmark;
2019 import com.google.gson.Gson;
2120 import com.google.gson.GsonBuilder;
2221
2726 * @author Jesse Wilson
2827 * @author Joel Leitch
2928 */
30 public class SerializationBenchmark extends SimpleBenchmark {
29 public class SerializationBenchmark {
3130
3231 private Gson gson;
3332 private BagOfPrimitives bag;
3534 private boolean pretty;
3635
3736 public static void main(String[] args) {
38 Runner.main(SerializationBenchmark.class, args);
37 NonUploadingCaliperRunner.run(SerializationBenchmark.class, args);
3938 }
4039
41 @Override
42 protected void setUp() throws Exception {
40 @BeforeExperiment
41 void setUp() throws Exception {
4342 this.gson = pretty ? new GsonBuilder().setPrettyPrinting().create() : new Gson();
4443 this.bag = new BagOfPrimitives(10L, 1, false, "foo");
4544 }
1010
1111 <groupId>com.google.code.gson</groupId>
1212 <artifactId>gson-parent</artifactId>
13 <version>2.8.8</version>
13 <version>2.9.0</version>
1414 <packaging>pom</packaging>
1515
1616 <name>Gson Parent</name>
1919
2020 <modules>
2121 <module>gson</module>
22 <module>extras</module>
23 <module>codegen</module>
24 <module>metrics</module>
25 <module>proto</module>
2226 </modules>
2327
2428 <properties>
2529 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
26 <java.version>1.6</java.version>
30 <javaVersion>7</javaVersion>
2731 </properties>
2832
2933 <scm>
3034 <url>https://github.com/google/gson/</url>
3135 <connection>scm:git:https://github.com/google/gson.git</connection>
3236 <developerConnection>scm:git:git@github.com:google/gson.git</developerConnection>
33 <tag>gson-parent-2.8.8</tag>
37 <tag>gson-parent-2.9.0</tag>
3438 </scm>
3539
3640 <issueManagement>
4044
4145 <licenses>
4246 <license>
43 <name>Apache 2.0</name>
47 <name>Apache-2.0</name>
4448 <url>https://www.apache.org/licenses/LICENSE-2.0.txt</url>
4549 </license>
4650 </licenses>
6266 <plugin>
6367 <groupId>org.apache.maven.plugins</groupId>
6468 <artifactId>maven-compiler-plugin</artifactId>
65 <version>3.8.1</version>
66 <executions>
67 <execution>
68 <id>default-compile</id>
69 <configuration>
70 <jdkToolchain>
71 <version>9</version>
72 </jdkToolchain>
73 <release>9</release>
74 </configuration>
75 </execution>
76 <execution>
77 <id>base-compile</id>
78 <goals>
79 <goal>compile</goal>
80 </goals>
81 <configuration>
82 <excludes>
83 <exclude>module-info.java</exclude>
84 </excludes>
85 </configuration>
86 </execution>
87 </executions>
69 <version>3.9.0</version>
8870 <configuration>
71 <release>${javaVersion}</release>
8972 <jdkToolchain>
90 <version>[1.5,9)</version>
73 <version>[11,)</version>
9174 </jdkToolchain>
92 <source>1.6</source>
93 <target>1.6</target>
9475 </configuration>
9576 </plugin>
9677 <plugin>
9778 <groupId>org.apache.maven.plugins</groupId>
9879 <artifactId>maven-javadoc-plugin</artifactId>
99 <version>3.3.0</version>
80 <version>3.3.1</version>
81 <configuration>
82 <jdkToolchain>
83 <version>[11,)</version>
84 </jdkToolchain>
85 <!-- Exclude `missing` group because some tags have been omitted when they are redundant -->
86 <doclint>all,-missing</doclint>
87 <!-- Link against newer Java API Javadoc because most users likely
88 use a newer Java version than the one used for building this project -->
89 <detectJavaApiLink>false</detectJavaApiLink>
90 <links>
91 <link>https://docs.oracle.com/en/java/javase/11/docs/api/</link>
92 </links>
93 <!-- Disable detection of offline links between Maven modules:
94 (1) Only `gson` module is published, so for other modules Javadoc links don't
95 matter much at the moment; (2) The derived URL for the modules is based on
96 the project URL (= Gson GitHub repo) which is incorrect because it is not
97 hosting the Javadoc (3) It might fail due to https://bugs.openjdk.java.net/browse/JDK-8212233 -->
98 <detectOfflineLinks>false</detectOfflineLinks>
99 </configuration>
100100 </plugin>
101101 <plugin>
102102 <groupId>org.apache.maven.plugins</groupId>
103103 <artifactId>maven-jar-plugin</artifactId>
104 </plugin>
105 <plugin>
106 <groupId>org.apache.felix</groupId>
107 <artifactId>maven-bundle-plugin</artifactId>
108 <version>5.1.2</version>
109 <inherited>true</inherited>
104 <version>3.2.2</version>
110105 </plugin>
111106 </plugins>
112107 </pluginManagement>
119114 <dependency>
120115 <groupId>org.apache.maven.scm</groupId>
121116 <artifactId>maven-scm-api</artifactId>
122 <version>1.11.3</version>
117 <version>1.12.2</version>
123118 </dependency>
124119 <dependency>
125120 <groupId>org.apache.maven.scm</groupId>
126121 <artifactId>maven-scm-provider-gitexe</artifactId>
127 <version>1.11.3</version>
122 <version>1.12.2</version>
128123 </dependency>
129124 </dependencies>
130125 <configuration>
133128 </plugin>
134129 </plugins>
135130 </build>
136 <profiles>
137 <profile>
138 <id>doclint-java8-disable</id>
139 <activation>
140 <jdk>[1.8,)</jdk>
141 </activation>
142 <build>
143 <plugins>
144 <plugin>
145 <groupId>org.apache.maven.plugins</groupId>
146 <artifactId>maven-javadoc-plugin</artifactId>
147 <configuration>
148 <additionalparam>-Xdoclint:none</additionalparam>
149 </configuration>
150 </plugin>
151 </plugins>
152 </build>
153 </profile>
154 </profiles>
155131 </project>
0 # proto
1
2 This Maven module contains the source code for a JSON serializer and deserializer for
3 [Protocol Buffers (protobuf)](https://developers.google.com/protocol-buffers/docs/javatutorial)
4 messages.
5
6 The artifacts created by this module are currently not deployed to Maven Central.
0 <?xml version="1.0" encoding="UTF-8"?>
1
2 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
4
5 <modelVersion>4.0.0</modelVersion>
6 <groupId>com.google.code.gson</groupId>
7 <artifactId>proto</artifactId>
8 <packaging>jar</packaging>
9 <version>0.6-SNAPSHOT</version>
10 <name>Gson Protobuf Support</name>
11 <description>Gson support for Protobufs</description>
12 <properties>
13 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
14 </properties>
15 <distributionManagement>
16 <repository>
17 <id>local.repo</id>
18 <name>file repository to svn</name>
19 <url>file://${basedir}/../../mavenrepo</url>
20 </repository>
21 </distributionManagement>
22 <repositories>
23 <repository>
24 <id>gson</id>
25 <url>http://google-gson.googlecode.com/svn/mavenrepo</url>
26 <snapshots>
27 <enabled>true</enabled>
28 </snapshots>
29 <releases>
30 <enabled>true</enabled>
31 </releases>
32 </repository>
33 </repositories>
34 <licenses>
35 <license>
36 <name>The Apache Software License, Version 2.0</name>
37 <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
38 <distribution>repo</distribution>
39 </license>
40 </licenses>
41 <scm>
42 <connection>scm:svn:http://google-gson.googlecode.com/svn/trunk/proto</connection>
43 <developerConnection>scm:svn:https://google-gson.googlecode.com/svn/trunk/proto</developerConnection>
44 <url>http://google-gson.codegoogle.com/svn/trunk/proto</url>
45 </scm>
46 <issueManagement>
47 <system>Google Code Issue Tracking</system>
48 <url>http://code.google.com/p/google-gson/issues/list</url>
49 </issueManagement>
50
51 <dependencies>
52
53 <!-- Gson: Java to Json conversion -->
54 <dependency>
55 <groupId>com.google.code.gson</groupId>
56 <artifactId>gson</artifactId>
57 <version>2.4</version>
58 <scope>compile</scope>
59 </dependency>
60
61 <dependency>
62 <groupId>com.google.protobuf</groupId>
63 <artifactId>protobuf-java</artifactId>
64 <version>2.6.1</version>
65 <scope>compile</scope>
66 </dependency>
67
68 <dependency>
69 <groupId>com.google.guava</groupId>
70 <artifactId>guava</artifactId>
71 <version>18.0</version>
72 <scope>compile</scope>
73 </dependency>
74
75 <dependency>
76 <groupId>junit</groupId>
77 <artifactId>junit</artifactId>
78 <version>4.13.1</version>
79 <scope>test</scope>
80 </dependency>
81
82 <dependency>
83 <groupId>com.google.truth</groupId>
84 <artifactId>truth</artifactId>
85 <version>0.27</version>
86 <scope>test</scope>
87 </dependency>
88 </dependencies>
89
90 <build>
91 <finalName>gson-proto</finalName>
92 <plugins>
93 <plugin>
94 <artifactId>maven-antrun-plugin</artifactId>
95 <version>1.8</version>
96 <executions>
97 <execution>
98 <id>compile-protoc</id>
99 <phase>generate-sources</phase>
100 <configuration>
101 <tasks>
102 <mkdir dir="target/generated" />
103 <path id="proto.path">
104 <fileset dir="src/main/protobuf">
105 <include name="**/*.proto" />
106 </fileset>
107 </path>
108 <pathconvert pathsep=" " property="proto.files" refid="proto.path" />
109 <exec executable="protoc" failonerror="true">
110 <arg value="--java_out=src/main/java" />
111 <arg value="--proto_path=/usr/include" />
112 <arg value="-I${project.basedir}/src/main/protobuf" />
113 <arg line="${proto.files}" />
114 </exec>
115 </tasks>
116 </configuration>
117 <goals>
118 <goal>run</goal>
119 </goals>
120 </execution>
121 </executions>
122 </plugin>
123 <plugin>
124 <groupId>org.apache.maven.plugins</groupId>
125 <artifactId>maven-compiler-plugin</artifactId>
126 <version>2.3.2</version>
127 <configuration>
128 <source>1.6</source>
129 <target>1.6</target>
130 </configuration>
131 </plugin>
132 <plugin>
133 <groupId>org.apache.maven.plugins</groupId>
134 <artifactId>maven-eclipse-plugin</artifactId>
135 <version>2.8</version>
136 <configuration>
137 <downloadSources>true</downloadSources>
138 <downloadJavadocs>true</downloadJavadocs>
139 <workspace>../eclipse-ws</workspace>
140 <workspaceCodeStylesURL>file:///${basedir}/../lib/gson-formatting-styles.xml</workspaceCodeStylesURL>
141 </configuration>
142 </plugin>
143 <plugin>
144 <groupId>org.apache.maven.plugins</groupId>
145 <artifactId>maven-install-plugin</artifactId>
146 <version>2.5.2</version>
147 <!-- configuration>
148 <updateReleaseInfo>true</updateReleaseInfo>
149 <createChecksum>true</createChecksum>
150 <groupId>${groupId}</groupId>
151 <artifactId>${artifactId}</artifactId>
152 <version>${version}</version>
153 <packaging>jar</packaging>
154 <classifier>sources</classifier>
155 <file>target/proto-sources.jar</file>
156 </configuration -->
157 </plugin>
158 <plugin>
159 <groupId>org.apache.maven.plugins</groupId>
160 <artifactId>maven-release-plugin</artifactId>
161 <version>2.1</version>
162 <configuration>
163 <arguments>-DenableCiProfile=true</arguments>
164 <tagBase>https://google-gson.googlecode.com/svn/tags/</tagBase>
165 </configuration>
166 </plugin>
167 <plugin>
168 <groupId>org.apache.maven.plugins</groupId>
169 <artifactId>maven-source-plugin</artifactId>
170 <version>2.1.2</version>
171 <executions>
172 <execution>
173 <id>attach-sources</id>
174 <goals>
175 <goal>jar</goal>
176 </goals>
177 </execution>
178 </executions>
179 </plugin>
180 <plugin>
181 <groupId>org.apache.maven.plugins</groupId>
182 <artifactId>maven-javadoc-plugin</artifactId>
183 <version>2.7</version>
184 <executions>
185 <execution>
186 <id>attach-javadocs</id>
187 <goals>
188 <goal>jar</goal>
189 </goals>
190 </execution>
191 </executions>
192 <configuration>
193 <links>
194 <link>http://download.oracle.com/javase/1.5.0/docs/api/</link>
195 </links>
196 <version>true</version>
197 <show>public</show>
198 </configuration>
199 </plugin>
200 <plugin>
201 <artifactId>maven-assembly-plugin</artifactId>
202 <configuration>
203 <descriptor>src/main/resources/assembly-descriptor.xml</descriptor>
204 <finalName>proto-${project.version}</finalName>
205 <outputDirectory>target/dist</outputDirectory>
206 <workDirectory>target/assembly/work</workDirectory>
207 </configuration>
208 </plugin>
209 </plugins>
210 </build>
211 <developers>
212 <developer>
213 <name>Inderjeet Singh</name>
214 <organization>Google Inc.</organization>
215 </developer>
216 </developers>
217 </project>
0 <?xml version="1.0" encoding="UTF-8"?>
1
2 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
3
4 <modelVersion>4.0.0</modelVersion>
5 <parent>
6 <groupId>com.google.code.gson</groupId>
7 <artifactId>gson-parent</artifactId>
8 <version>2.9.0</version>
9 </parent>
10
11 <artifactId>proto</artifactId>
12 <name>Gson Protobuf Support</name>
13 <description>Gson support for Protobufs</description>
14
15 <licenses>
16 <license>
17 <name>Apache-2.0</name>
18 <url>https://www.apache.org/licenses/LICENSE-2.0.txt</url>
19 </license>
20 </licenses>
21
22 <dependencies>
23 <dependency>
24 <groupId>com.google.code.gson</groupId>
25 <artifactId>gson</artifactId>
26 <version>${project.parent.version}</version>
27 </dependency>
28
29 <dependency>
30 <groupId>com.google.protobuf</groupId>
31 <artifactId>protobuf-java</artifactId>
32 <version>4.0.0-rc-2</version>
33 </dependency>
34
35 <dependency>
36 <groupId>com.google.guava</groupId>
37 <artifactId>guava</artifactId>
38 <version>31.0.1-jre</version>
39 </dependency>
40
41 <dependency>
42 <groupId>junit</groupId>
43 <artifactId>junit</artifactId>
44 <scope>test</scope>
45 </dependency>
46
47 <dependency>
48 <groupId>com.google.truth</groupId>
49 <artifactId>truth</artifactId>
50 <version>1.1.3</version>
51 <scope>test</scope>
52 </dependency>
53 </dependencies>
54
55 <build>
56 <finalName>gson-proto</finalName>
57 <!-- Setup based on https://quarkus.io/guides/grpc-getting-started#generating-java-files-from-proto-with-protobuf-maven-plugin -->
58 <extensions>
59 <extension>
60 <groupId>kr.motd.maven</groupId>
61 <artifactId>os-maven-plugin</artifactId>
62 <version>1.7.0</version>
63 </extension>
64 </extensions>
65
66 <plugins>
67 <plugin>
68 <groupId>org.xolstice.maven.plugins</groupId>
69 <artifactId>protobuf-maven-plugin</artifactId>
70 <version>0.6.1</version>
71 <configuration>
72 <protocArtifact>com.google.protobuf:protoc:3.17.3:exe:${os.detected.classifier}</protocArtifact>
73 </configuration>
74 <executions>
75 <execution>
76 <goals>
77 <goal>compile</goal>
78 <goal>test-compile</goal>
79 </goals>
80 </execution>
81 </executions>
82 </plugin>
83 </plugins>
84
85 <pluginManagement>
86 <plugins>
87 <plugin>
88 <groupId>org.apache.maven.plugins</groupId>
89 <artifactId>maven-deploy-plugin</artifactId>
90 <version>3.0.0-M2</version>
91 <configuration>
92 <!-- Not deployed -->
93 <skip>true</skip>
94 </configuration>
95 </plugin>
96 </plugins>
97 </pluginManagement>
98 </build>
99
100 <developers>
101 <developer>
102 <name>Inderjeet Singh</name>
103 <organization>Google Inc.</organization>
104 </developer>
105 </developers>
106 </project>
3636 import com.google.protobuf.DynamicMessage;
3737 import com.google.protobuf.Extension;
3838 import com.google.protobuf.Message;
39
4039 import java.lang.reflect.Field;
4140 import java.lang.reflect.InvocationTargetException;
4241 import java.lang.reflect.Method;
7574 /**
7675 * Determines how enum <u>values</u> should be serialized.
7776 */
78 public static enum EnumSerialization {
77 public enum EnumSerialization {
7978 /**
8079 * Serializes and deserializes enum values using their <b>number</b>. When this is used, custom
8180 * value names set on enums are ignored.
116115 * For example, if you use the following parameters: {@link CaseFormat#LOWER_UNDERSCORE},
117116 * {@link CaseFormat#LOWER_CAMEL}, the following conversion will occur:
118117 *
119 * <pre>
118 * <pre>{@code
120119 * PROTO <-> JSON
121120 * my_field myField
122121 * foo foo
123122 * n__id_ct nIdCt
124 * </pre>
123 * }</pre>
125124 */
126125 public Builder setFieldNameSerializationFormat(CaseFormat fromFieldNameFormat,
127126 CaseFormat toFieldNameFormat) {
191190 private static final com.google.protobuf.Descriptors.FieldDescriptor.Type ENUM_TYPE =
192191 com.google.protobuf.Descriptors.FieldDescriptor.Type.ENUM;
193192
194 private static final ConcurrentMap<String, Map<Class<?>, Method>> mapOfMapOfMethods =
193 private static final ConcurrentMap<String, ConcurrentMap<Class<?>, Method>> mapOfMapOfMethods =
195194 new MapMaker().makeMap();
196195
197196 private final EnumSerialization enumSerialization;
308307 }
309308 }
310309 }
311 return (Message) protoBuilder.build();
310 return protoBuilder.build();
312311 } catch (SecurityException e) {
313312 throw new JsonParseException(e);
314313 } catch (NoSuchMethodException e) {
388387 EnumValueDescriptor fieldValue = desc.findValueByNumber(jsonElement.getAsInt());
389388 if (fieldValue == null) {
390389 throw new IllegalArgumentException(
391 String.format("Unrecognized enum value: %s", jsonElement.getAsInt()));
390 String.format("Unrecognized enum value: %d", jsonElement.getAsInt()));
392391 }
393392 return fieldValue;
394393 }
396395
397396 private static Method getCachedMethod(Class<?> clazz, String methodName,
398397 Class<?>... methodParamTypes) throws NoSuchMethodException {
399 Map<Class<?>, Method> mapOfMethods = mapOfMapOfMethods.get(methodName);
398 ConcurrentMap<Class<?>, Method> mapOfMethods = mapOfMapOfMethods.get(methodName);
400399 if (mapOfMethods == null) {
401400 mapOfMethods = new MapMaker().makeMap();
402 Map<Class<?>, Method> previous =
401 ConcurrentMap<Class<?>, Method> previous =
403402 mapOfMapOfMethods.putIfAbsent(methodName, mapOfMethods);
404403 mapOfMethods = previous == null ? mapOfMethods : previous;
405404 }
0 //
1 // Copyright (C) 2010 Google Inc.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 //
15
16 syntax = "proto2";
17
18 package google.gson.protobuf.generated;
19 option java_package = "com.google.gson.protobuf.generated";
20
21 import "google/protobuf/descriptor.proto";
22
23 extend google.protobuf.FieldOptions {
24 // Indicates a field name that overrides the default for serialization
25 optional string serialized_name = 92066888;
26 }
27
28 extend google.protobuf.EnumValueOptions {
29 // Indicates a field value that overrides the default for serialization
30 optional string serialized_value = 92066888;
31 }
0 //
1 // Copyright (C) 2010 Google Inc.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 //
15
16 syntax = "proto2";
17
18 package google.gson.protobuf.generated;
19 option java_package = "com.google.gson.protobuf.generated";
20
21 import "annotations.proto";
22
23 message SimpleProto {
24 optional string msg = 1;
25 optional int32 count = 2;
26 }
27
28 message ProtoWithDifferentCaseFormat {
29 repeated string name_that_tests_case_format = 1;
30 optional string another_field = 2;
31 }
32
33 message ProtoWithRepeatedFields {
34 repeated int64 numbers = 1;
35 repeated SimpleProto simples = 2;
36 optional string name = 3;
37 }
38
39 // -- A more complex message with annotations and nested protos
40
41 message OuterMessage {
42 optional int32 month = 1;
43 optional int32 year = 2;
44 optional int64 long_timestamp = 3 [(serialized_name) = "timeStamp"];
45 optional string country_code_5f55 = 4;
46 }
47
48 message ProtoWithAnnotations {
49 optional string id = 1;
50 optional OuterMessage outer_message = 2 [(serialized_name) = "expiration_date"];
51
52 message InnerMessage {
53 optional int32 n__id_ct = 1;
54
55 enum Type {
56 UNKNOWN = 0;
57 TEXT = 1 [(serialized_value) = "text/plain"];
58 IMAGE = 2 [(serialized_value) = "image/png"];
59 }
60 optional Type content = 2;
61
62 message Data {
63 optional string data = 1;
64 optional int32 width = 2;
65 optional int32 height = 3;
66 }
67 repeated Data data = 3 [(serialized_name) = "$binary_data$"];
68 }
69 optional InnerMessage inner_message_1 = 3;
70 optional InnerMessage inner_message_2 = 4;
71 }
+0
-32
proto/src/main/protobuf/annotations.proto less more
0 //
1 // Copyright (C) 2010 Google Inc.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 //
15
16 syntax = "proto2";
17
18 package google.gson.protobuf.generated;
19 option java_package = "com.google.gson.protobuf.generated";
20
21 import "google/protobuf/descriptor.proto";
22
23 extend google.protobuf.FieldOptions {
24 // Indicates a field name that overrides the default for serialization
25 optional string serialized_name = 92066888;
26 }
27
28 extend google.protobuf.EnumValueOptions {
29 // Indicates a field value that overrides the default for serialization
30 optional string serialized_value = 92066888;
31 }
+0
-70
proto/src/main/protobuf/bag.proto less more
0 //
1 // Copyright (C) 2010 Google Inc.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 //
15
16 package google.gson.protobuf.generated;
17 option java_package = "com.google.gson.protobuf.generated";
18
19 import "annotations.proto";
20
21 message SimpleProto {
22 optional string msg = 1;
23 optional int32 count = 2;
24 }
25
26 message ProtoWithDifferentCaseFormat {
27 repeated string name_that_tests_case_format = 1;
28 optional string another_field = 2;
29 }
30
31 message ProtoWithRepeatedFields {
32 repeated int64 numbers = 1;
33 repeated SimpleProto simples = 2;
34 optional string name = 3;
35 }
36
37 // -- A more complex message with annotations and nested protos
38
39 message OuterMessage {
40 optional int32 month = 1;
41 optional int32 year = 2;
42 optional int64 long_timestamp = 3 [(serialized_name) = "timeStamp"];
43 optional string country_code_5f55 = 4;
44 }
45
46 message ProtoWithAnnotations {
47 optional string id = 1;
48 optional OuterMessage outer_message = 2 [(serialized_name) = "expiration_date"];
49
50 message InnerMessage {
51 optional int32 n__id_ct = 1;
52
53 enum Type {
54 UNKNOWN = 0;
55 TEXT = 1 [(serialized_value) = "text/plain"];
56 IMAGE = 2 [(serialized_value) = "image/png"];
57 }
58 optional Type content = 2;
59
60 message Data {
61 optional string data = 1;
62 optional int32 width = 2;
63 optional int32 height = 3;
64 }
65 repeated Data data = 3 [(serialized_name) = "$binary_data$"];
66 }
67 optional InnerMessage inner_message_1 = 3;
68 optional InnerMessage inner_message_2 = 4;
69 }
1515 package com.google.gson.protobuf.functional;
1616
1717 import static com.google.common.truth.Truth.assertThat;
18 import static com.google.common.truth.Truth.assert_;
18 import static com.google.common.truth.Truth.assertWithMessage;
1919
2020 import com.google.common.base.CaseFormat;
2121 import com.google.gson.Gson;
2929 import com.google.gson.protobuf.generated.Bag.ProtoWithAnnotations.InnerMessage;
3030 import com.google.gson.protobuf.generated.Bag.ProtoWithAnnotations.InnerMessage.Data;
3131 import com.google.gson.protobuf.generated.Bag.ProtoWithAnnotations.InnerMessage.Type;
32 import com.google.protobuf.GeneratedMessage;
33
32 import com.google.protobuf.GeneratedMessageV3;
3433 import junit.framework.TestCase;
3534
3635 /**
5150 .addSerializedNameExtension(Annotations.serializedName)
5251 .addSerializedEnumValueExtension(Annotations.serializedValue);
5352 gson = new GsonBuilder()
54 .registerTypeHierarchyAdapter(GeneratedMessage.class, protoTypeAdapter.build())
53 .registerTypeHierarchyAdapter(GeneratedMessageV3.class, protoTypeAdapter.build())
5554 .create();
5655 gsonWithEnumNumbers = new GsonBuilder()
57 .registerTypeHierarchyAdapter(GeneratedMessage.class, protoTypeAdapter
56 .registerTypeHierarchyAdapter(GeneratedMessageV3.class, protoTypeAdapter
5857 .setEnumSerialization(EnumSerialization.NUMBER)
5958 .build())
6059 .create();
6160 gsonWithLowerHyphen = new GsonBuilder()
62 .registerTypeHierarchyAdapter(GeneratedMessage.class, protoTypeAdapter
61 .registerTypeHierarchyAdapter(GeneratedMessageV3.class, protoTypeAdapter
6362 .setFieldNameSerializationFormat(CaseFormat.LOWER_UNDERSCORE, CaseFormat.LOWER_HYPHEN)
6463 .build())
6564 .create();
156155 + "}");
157156 try {
158157 gson.fromJson(json, InnerMessage.class);
159 assert_().fail("Should have thrown");
158 assertWithMessage("Should have thrown").fail();
160159 } catch (JsonParseException e) {
161160 // expected
162161 }
2323 import com.google.gson.protobuf.generated.Bag.ProtoWithDifferentCaseFormat;
2424 import com.google.gson.protobuf.generated.Bag.ProtoWithRepeatedFields;
2525 import com.google.gson.protobuf.generated.Bag.SimpleProto;
26 import com.google.protobuf.GeneratedMessage;
27
26 import com.google.protobuf.GeneratedMessageV3;
2827 import junit.framework.TestCase;
2928
3029 /**
4140 super.setUp();
4241 gson =
4342 new GsonBuilder()
44 .registerTypeHierarchyAdapter(GeneratedMessage.class,
43 .registerTypeHierarchyAdapter(GeneratedMessageV3.class,
4544 ProtoTypeAdapter.newBuilder()
4645 .setEnumSerialization(EnumSerialization.NUMBER)
4746 .build())
4948 upperCamelGson =
5049 new GsonBuilder()
5150 .registerTypeHierarchyAdapter(
52 GeneratedMessage.class, ProtoTypeAdapter.newBuilder()
51 GeneratedMessageV3.class, ProtoTypeAdapter.newBuilder()
5352 .setFieldNameSerializationFormat(
5453 CaseFormat.LOWER_UNDERSCORE, CaseFormat.UPPER_CAMEL)
5554 .build())
2020 import com.google.gson.protobuf.ProtoTypeAdapter.EnumSerialization;
2121 import com.google.gson.protobuf.generated.Bag.SimpleProto;
2222 import com.google.protobuf.Descriptors.Descriptor;
23 import com.google.protobuf.GeneratedMessage;
24
23 import com.google.protobuf.GeneratedMessageV3;
2524 import junit.framework.TestCase;
2625
2726 public class ProtosWithPrimitiveTypesTest extends TestCase {
3130 protected void setUp() throws Exception {
3231 super.setUp();
3332 gson = new GsonBuilder().registerTypeHierarchyAdapter(
34 GeneratedMessage.class, ProtoTypeAdapter.newBuilder()
33 GeneratedMessageV3.class, ProtoTypeAdapter.newBuilder()
3534 .setEnumSerialization(EnumSerialization.NUMBER)
3635 .build())
3736 .create();
+0
-1
settings.gradle less more
0 include ':gson'