gson-comments/gson/src/main/java/com/google/gson/internal/bind/TypeAdapters.java

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

1156 lines
38 KiB
Java
Raw Normal View History

2011-07-11 18:46:52 +02:00
/*
* Copyright (C) 2011 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
2011-08-03 02:25:10 +02:00
package com.google.gson.internal.bind;
2011-07-11 18:46:52 +02:00
import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonIOException;
import com.google.gson.JsonNull;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSyntaxException;
import com.google.gson.TypeAdapter;
import com.google.gson.TypeAdapterFactory;
import com.google.gson.annotations.SerializedName;
import com.google.gson.internal.LazilyParsedNumber;
import com.google.gson.internal.NumberLimits;
import com.google.gson.internal.TroubleshootingGuide;
import com.google.gson.reflect.TypeToken;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken;
2023-01-21 14:27:59 +01:00
import com.google.gson.stream.JsonTreeReader;
import com.google.gson.stream.JsonWriter;
import java.io.IOException;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.net.InetAddress;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.BitSet;
import java.util.Calendar;
2015-11-07 00:41:15 +01:00
import java.util.Currency;
import java.util.Deque;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicIntegerArray;
2011-07-11 18:46:52 +02:00
/** Type adapters for basic types. */
public final class TypeAdapters {
private TypeAdapters() {
throw new UnsupportedOperationException();
}
2011-07-11 18:46:52 +02:00
@SuppressWarnings("rawtypes")
public static final TypeAdapter<Class> CLASS =
new TypeAdapter<Class>() {
@Override
public void write(JsonWriter out, Class value) throws IOException {
throw new UnsupportedOperationException(
"Attempted to serialize java.lang.Class: "
+ value.getName()
+ ". Forgot to register a type adapter?"
+ "\nSee "
+ TroubleshootingGuide.createUrl("java-lang-class-unsupported"));
}
@Override
public Class read(JsonReader in) throws IOException {
throw new UnsupportedOperationException(
"Attempted to deserialize a java.lang.Class. Forgot to register a type adapter?"
+ "\nSee "
+ TroubleshootingGuide.createUrl("java-lang-class-unsupported"));
}
}.nullSafe();
public static final TypeAdapterFactory CLASS_FACTORY = newFactory(Class.class, CLASS);
public static final TypeAdapter<BitSet> BIT_SET =
new TypeAdapter<BitSet>() {
@Override
public BitSet read(JsonReader in) throws IOException {
BitSet bitset = new BitSet();
2011-12-03 20:46:25 +01:00
in.beginArray();
int i = 0;
2011-12-03 20:46:25 +01:00
JsonToken tokenType = in.peek();
while (tokenType != JsonToken.END_ARRAY) {
boolean set;
switch (tokenType) {
case NUMBER:
case STRING:
int intValue = in.nextInt();
if (intValue == 0) {
set = false;
} else if (intValue == 1) {
set = true;
} else {
throw new JsonSyntaxException(
"Invalid bitset value "
+ intValue
+ ", expected 0 or 1; at path "
+ in.getPreviousPath());
}
break;
case BOOLEAN:
2011-12-03 20:46:25 +01:00
set = in.nextBoolean();
break;
default:
throw new JsonSyntaxException(
"Invalid bitset value type: " + tokenType + "; at path " + in.getPath());
}
if (set) {
bitset.set(i);
}
++i;
2011-12-03 20:46:25 +01:00
tokenType = in.peek();
}
in.endArray();
return bitset;
}
@Override
public void write(JsonWriter out, BitSet src) throws IOException {
2011-12-03 20:46:25 +01:00
out.beginArray();
for (int i = 0, length = src.length(); i < length; i++) {
Fix error prone warnings (#2316) * Fix `OperatorPrecedence` warn in `JsonWriter#close` * Fix `ReferenceEquality` warn in `LinkedTreeMap#replaceInParent` * Fix `UnnecessaryParentheses` warn in `LinkedTreeMap#replaceInParent` * Fix `ReferenceEquality` warn in `LinkedTreeMap#hasNext` * Fix `ReferenceEquality` warn in `LinkedTreeMap#nextNode` * Adds `error_prone_annotations` to the `pom.xml` of `gson` * Fix `InlineMeSuggester` warns in `JsonParser` * Fix `UnnecessaryParentheses` warns in `ConstructorConstructor#newDefaultImplementationConstructor` * Fix `ThreadLocalUsage` warn in `Gson` * Fix `JdkObsolete` warn in `GsonBuilder` * Fix `ReferenceEquality` warn in `LazilyParsedNumber#equals` * Fix `OperatorPrecedence` warn in `TreeTypeAdapter#create` * Fix `OperatorPrecedence` warn in `ArrayTypeAdapter` * Fix `UnnecessaryParentheses` warn in `TypeAdapters` * Adds `-XepExcludedPaths` flag to ErrorProne plugin to exclude tests and proto path * Fix `ClassNewInstance` warn in `InterceptorAdapter` * Fix `ThreadLocalUsage` warn in `GraphAdapterBuilder` * Fix `JdkObsolete` warn in `GraphAdapterBuilder` * Revert "Adds `error_prone_annotations` to the `pom.xml` of `gson`" This reverts commit 14af14dfa23b46a54f4855a70ccf2b0a2cdc3e3f. * Revert "Fix `InlineMeSuggester` warns in `JsonParser`" This reverts commit 095bfd517e06510e4cc9cc6b1aac58ad9bf3038a. * Adds `@SuppressWarnings("ThreadLocalUsage")` * Fix `OperatorPrecedence` in `JsonWriter` * Revert "Fix `ReferenceEquality` warn in `LinkedTreeMap#nextNode`" This reverts commit 387746c7f7e3d0943c8f80501f5d9c3710f4862e. * Adds `@SuppressWarnings("ReferenceEquality")` * Adds `guava-testlib` to the gson `pom.xml` * `@SuppressWarnings("TruthSelfEquals")` removed to use `EqualsTester()`
2023-02-15 14:18:43 +01:00
int value = src.get(i) ? 1 : 0;
2011-12-03 20:46:25 +01:00
out.value(value);
}
2011-12-03 20:46:25 +01:00
out.endArray();
}
}.nullSafe();
public static final TypeAdapterFactory BIT_SET_FACTORY = newFactory(BitSet.class, BIT_SET);
2011-07-11 18:46:52 +02:00
public static final TypeAdapter<Boolean> BOOLEAN =
new TypeAdapter<Boolean>() {
@Override
2011-12-03 20:46:25 +01:00
public Boolean read(JsonReader in) throws IOException {
JsonToken peek = in.peek();
if (peek == JsonToken.NULL) {
2011-12-03 20:46:25 +01:00
in.nextNull();
return null;
} else if (peek == JsonToken.STRING) {
// support strings for compatibility with GSON 1.7
2011-12-03 20:46:25 +01:00
return Boolean.parseBoolean(in.nextString());
}
2011-12-03 20:46:25 +01:00
return in.nextBoolean();
2011-07-11 18:46:52 +02:00
}
@Override
2011-12-03 20:46:25 +01:00
public void write(JsonWriter out, Boolean value) throws IOException {
out.value(value);
2011-07-11 18:46:52 +02:00
}
};
/**
* Writes a boolean as a string. Useful for map keys, where booleans aren't otherwise permitted.
*/
public static final TypeAdapter<Boolean> BOOLEAN_AS_STRING =
new TypeAdapter<Boolean>() {
2011-12-03 20:46:25 +01:00
@Override
public Boolean read(JsonReader in) throws IOException {
if (in.peek() == JsonToken.NULL) {
in.nextNull();
return null;
}
2011-12-03 20:46:25 +01:00
return Boolean.valueOf(in.nextString());
}
@Override
2011-12-03 20:46:25 +01:00
public void write(JsonWriter out, Boolean value) throws IOException {
out.value(value == null ? "null" : value.toString());
}
};
public static final TypeAdapterFactory BOOLEAN_FACTORY =
2011-07-11 18:46:52 +02:00
newFactory(boolean.class, Boolean.class, BOOLEAN);
2011-07-11 18:46:52 +02:00
public static final TypeAdapter<Number> BYTE =
2011-09-09 06:39:29 +02:00
new TypeAdapter<Number>() {
@Override
2011-12-03 20:46:25 +01:00
public Number read(JsonReader in) throws IOException {
if (in.peek() == JsonToken.NULL) {
in.nextNull();
return null;
}
2011-07-11 18:46:52 +02:00
int intValue;
2011-09-09 06:39:29 +02:00
try {
intValue = in.nextInt();
} catch (NumberFormatException e) {
2011-12-03 20:46:25 +01:00
throw new JsonSyntaxException(e);
}
2011-12-03 20:46:25 +01:00
// Allow up to 255 to support unsigned values
if (intValue > 255 || intValue < Byte.MIN_VALUE) {
throw new JsonSyntaxException(
"Lossy conversion from " + intValue + " to byte; at path " + in.getPreviousPath());
}
return (byte) intValue;
}
@Override
2011-12-03 20:46:25 +01:00
public void write(JsonWriter out, Number value) throws IOException {
if (value == null) {
out.nullValue();
} else {
out.value(value.byteValue());
}
}
2011-07-11 18:46:52 +02:00
};
public static final TypeAdapterFactory BYTE_FACTORY = newFactory(byte.class, Byte.class, BYTE);
2011-07-11 18:46:52 +02:00
2011-09-09 06:39:29 +02:00
public static final TypeAdapter<Number> SHORT =
new TypeAdapter<Number>() {
@Override
2011-12-03 20:46:25 +01:00
public Number read(JsonReader in) throws IOException {
if (in.peek() == JsonToken.NULL) {
in.nextNull();
return null;
}
int intValue;
try {
intValue = in.nextInt();
} catch (NumberFormatException e) {
throw new JsonSyntaxException(e);
}
// Allow up to 65535 to support unsigned values
if (intValue > 65535 || intValue < Short.MIN_VALUE) {
throw new JsonSyntaxException(
"Lossy conversion from " + intValue + " to short; at path " + in.getPreviousPath());
}
return (short) intValue;
}
@Override
2011-12-03 20:46:25 +01:00
public void write(JsonWriter out, Number value) throws IOException {
if (value == null) {
out.nullValue();
} else {
out.value(value.shortValue());
}
}
};
public static final TypeAdapterFactory SHORT_FACTORY =
newFactory(short.class, Short.class, SHORT);
public static final TypeAdapter<Number> INTEGER =
2011-09-09 06:39:29 +02:00
new TypeAdapter<Number>() {
@Override
2011-12-03 20:46:25 +01:00
public Number read(JsonReader in) throws IOException {
if (in.peek() == JsonToken.NULL) {
in.nextNull();
return null;
}
try {
2011-12-03 20:46:25 +01:00
return in.nextInt();
} catch (NumberFormatException e) {
throw new JsonSyntaxException(e);
}
}
2011-09-09 06:39:29 +02:00
@Override
public void write(JsonWriter out, Number value) throws IOException {
if (value == null) {
2011-09-09 06:39:29 +02:00
out.nullValue();
} else {
out.value(value.intValue());
}
}
};
2011-09-09 06:39:29 +02:00
public static final TypeAdapterFactory INTEGER_FACTORY =
2011-12-03 20:46:25 +01:00
newFactory(int.class, Integer.class, INTEGER);
public static final TypeAdapter<AtomicInteger> ATOMIC_INTEGER =
new TypeAdapter<AtomicInteger>() {
@Override
2011-09-09 06:39:29 +02:00
public AtomicInteger read(JsonReader in) throws IOException {
try {
return new AtomicInteger(in.nextInt());
} catch (NumberFormatException e) {
throw new JsonSyntaxException(e);
}
}
2011-07-11 18:46:52 +02:00
@Override
public void write(JsonWriter out, AtomicInteger value) throws IOException {
out.value(value.get());
}
}.nullSafe();
2015-11-05 23:03:51 +01:00
public static final TypeAdapterFactory ATOMIC_INTEGER_FACTORY =
newFactory(AtomicInteger.class, TypeAdapters.ATOMIC_INTEGER);
public static final TypeAdapter<AtomicBoolean> ATOMIC_BOOLEAN =
new TypeAdapter<AtomicBoolean>() {
@Override
public AtomicBoolean read(JsonReader in) throws IOException {
return new AtomicBoolean(in.nextBoolean());
}
@Override
public void write(JsonWriter out, AtomicBoolean value) throws IOException {
out.value(value.get());
}
}.nullSafe();
2015-11-05 23:03:51 +01:00
public static final TypeAdapterFactory ATOMIC_BOOLEAN_FACTORY =
newFactory(AtomicBoolean.class, TypeAdapters.ATOMIC_BOOLEAN);
public static final TypeAdapter<AtomicIntegerArray> ATOMIC_INTEGER_ARRAY =
new TypeAdapter<AtomicIntegerArray>() {
@Override
public AtomicIntegerArray read(JsonReader in) throws IOException {
List<Integer> list = new ArrayList<>();
in.beginArray();
while (in.hasNext()) {
try {
int integer = in.nextInt();
list.add(integer);
} catch (NumberFormatException e) {
throw new JsonSyntaxException(e);
}
}
in.endArray();
int length = list.size();
AtomicIntegerArray array = new AtomicIntegerArray(length);
for (int i = 0; i < length; ++i) {
array.set(i, list.get(i));
}
return array;
}
@Override
public void write(JsonWriter out, AtomicIntegerArray value) throws IOException {
out.beginArray();
for (int i = 0, length = value.length(); i < length; i++) {
out.value(value.get(i));
}
out.endArray();
}
}.nullSafe();
2015-11-05 23:03:51 +01:00
public static final TypeAdapterFactory ATOMIC_INTEGER_ARRAY_FACTORY =
newFactory(AtomicIntegerArray.class, TypeAdapters.ATOMIC_INTEGER_ARRAY);
2011-09-09 06:39:29 +02:00
public static final TypeAdapter<Number> LONG =
new TypeAdapter<Number>() {
@Override
2011-12-03 20:46:25 +01:00
public Number read(JsonReader in) throws IOException {
if (in.peek() == JsonToken.NULL) {
in.nextNull();
return null;
}
2011-12-03 20:46:25 +01:00
try {
return in.nextLong();
} catch (NumberFormatException e) {
throw new JsonSyntaxException(e);
2011-12-16 20:10:54 +01:00
}
}
@Override
public void write(JsonWriter out, Number value) throws IOException {
if (value == null) {
out.nullValue();
} else {
out.value(value.longValue());
}
}
};
public static final TypeAdapter<Number> FLOAT =
new TypeAdapter<Number>() {
@Override
2011-12-03 20:46:25 +01:00
public Number read(JsonReader in) throws IOException {
if (in.peek() == JsonToken.NULL) {
in.nextNull();
return null;
}
2011-12-03 20:46:25 +01:00
return (float) in.nextDouble();
}
@Override
2011-12-03 20:46:25 +01:00
public void write(JsonWriter out, Number value) throws IOException {
Down to 22 failing tests. Consolidated all of the different code paths that we use to construct instances. We now have an ObjectConstructor class that knows what type it constructs; this means that we don't need to ever do reflection to lookup a constructor at construction time. Cleaned up some buggy type adapters, particularly around handling of null. Removed dead code for object graph navigation. Moved some classes into 'internal' so they are visible to the 'bind' subpackage. Turned some TypeAdapterFactory/TypeAdapter pairs inside out so that the TypeAdapter is now the inner class. This is necessary so that the factories can take parameters. Added an API to request the 'next' type adapter for a type. This allows type adapters to compose other type adapters. We're using this in two places: - where the user has excluded a type from serialization but not deserialization, we need to use the "default" deserialization but interpose null on serialization. We create a type adapter that delegates for one and returns null for the other. - similarly when a DOM type serializer is registered but no deserializer, or vice versa. This is the biggest change to the MiniGson core. For backwards compatibility, return null for the empty string. Simplify JsonSerializationContext/JsonDeserializationContext to simply call through to GSON. SerializeDefault is currently unsupported. More useful error messages when calling getAsBoolean on a JsonNull. Remove currently unused MemoryRefStack. We might need this back again, though wiring it back in will be much more difficult because we don't interject ourselves between the users' various type adapters.
2011-09-11 09:04:56 +02:00
if (value == null) {
2011-12-03 20:46:25 +01:00
out.nullValue();
2011-09-09 05:40:39 +02:00
} else {
Down to 22 failing tests. Consolidated all of the different code paths that we use to construct instances. We now have an ObjectConstructor class that knows what type it constructs; this means that we don't need to ever do reflection to lookup a constructor at construction time. Cleaned up some buggy type adapters, particularly around handling of null. Removed dead code for object graph navigation. Moved some classes into 'internal' so they are visible to the 'bind' subpackage. Turned some TypeAdapterFactory/TypeAdapter pairs inside out so that the TypeAdapter is now the inner class. This is necessary so that the factories can take parameters. Added an API to request the 'next' type adapter for a type. This allows type adapters to compose other type adapters. We're using this in two places: - where the user has excluded a type from serialization but not deserialization, we need to use the "default" deserialization but interpose null on serialization. We create a type adapter that delegates for one and returns null for the other. - similarly when a DOM type serializer is registered but no deserializer, or vice versa. This is the biggest change to the MiniGson core. For backwards compatibility, return null for the empty string. Simplify JsonSerializationContext/JsonDeserializationContext to simply call through to GSON. SerializeDefault is currently unsupported. More useful error messages when calling getAsBoolean on a JsonNull. Remove currently unused MemoryRefStack. We might need this back again, though wiring it back in will be much more difficult because we don't interject ourselves between the users' various type adapters.
2011-09-11 09:04:56 +02:00
// For backward compatibility don't call `JsonWriter.value(float)` because that method
// has been newly added and not all custom JsonWriter implementations might override
// it yet
Down to 22 failing tests. Consolidated all of the different code paths that we use to construct instances. We now have an ObjectConstructor class that knows what type it constructs; this means that we don't need to ever do reflection to lookup a constructor at construction time. Cleaned up some buggy type adapters, particularly around handling of null. Removed dead code for object graph navigation. Moved some classes into 'internal' so they are visible to the 'bind' subpackage. Turned some TypeAdapterFactory/TypeAdapter pairs inside out so that the TypeAdapter is now the inner class. This is necessary so that the factories can take parameters. Added an API to request the 'next' type adapter for a type. This allows type adapters to compose other type adapters. We're using this in two places: - where the user has excluded a type from serialization but not deserialization, we need to use the "default" deserialization but interpose null on serialization. We create a type adapter that delegates for one and returns null for the other. - similarly when a DOM type serializer is registered but no deserializer, or vice versa. This is the biggest change to the MiniGson core. For backwards compatibility, return null for the empty string. Simplify JsonSerializationContext/JsonDeserializationContext to simply call through to GSON. SerializeDefault is currently unsupported. More useful error messages when calling getAsBoolean on a JsonNull. Remove currently unused MemoryRefStack. We might need this back again, though wiring it back in will be much more difficult because we don't interject ourselves between the users' various type adapters.
2011-09-11 09:04:56 +02:00
Number floatNumber = value instanceof Float ? value : value.floatValue();
out.value(floatNumber);
}
}
};
2011-09-09 06:39:29 +02:00
public static final TypeAdapter<Number> DOUBLE =
Down to 22 failing tests. Consolidated all of the different code paths that we use to construct instances. We now have an ObjectConstructor class that knows what type it constructs; this means that we don't need to ever do reflection to lookup a constructor at construction time. Cleaned up some buggy type adapters, particularly around handling of null. Removed dead code for object graph navigation. Moved some classes into 'internal' so they are visible to the 'bind' subpackage. Turned some TypeAdapterFactory/TypeAdapter pairs inside out so that the TypeAdapter is now the inner class. This is necessary so that the factories can take parameters. Added an API to request the 'next' type adapter for a type. This allows type adapters to compose other type adapters. We're using this in two places: - where the user has excluded a type from serialization but not deserialization, we need to use the "default" deserialization but interpose null on serialization. We create a type adapter that delegates for one and returns null for the other. - similarly when a DOM type serializer is registered but no deserializer, or vice versa. This is the biggest change to the MiniGson core. For backwards compatibility, return null for the empty string. Simplify JsonSerializationContext/JsonDeserializationContext to simply call through to GSON. SerializeDefault is currently unsupported. More useful error messages when calling getAsBoolean on a JsonNull. Remove currently unused MemoryRefStack. We might need this back again, though wiring it back in will be much more difficult because we don't interject ourselves between the users' various type adapters.
2011-09-11 09:04:56 +02:00
new TypeAdapter<Number>() {
@Override
2011-12-03 20:46:25 +01:00
public Number read(JsonReader in) throws IOException {
if (in.peek() == JsonToken.NULL) {
in.nextNull();
2011-09-09 05:40:39 +02:00
return null;
}
2011-12-03 20:46:25 +01:00
return in.nextDouble();
2011-07-11 18:46:52 +02:00
}
2020-05-09 17:37:21 +02:00
@Override
public void write(JsonWriter out, Number value) throws IOException {
if (value == null) {
out.nullValue();
} else {
out.value(value.doubleValue());
}
}
};
public static final TypeAdapter<Character> CHARACTER =
new TypeAdapter<Character>() {
@Override
public Character read(JsonReader in) throws IOException {
if (in.peek() == JsonToken.NULL) {
in.nextNull();
return null;
}
String str = in.nextString();
if (str.length() != 1) {
throw new JsonSyntaxException(
"Expecting character, got: " + str + "; at " + in.getPreviousPath());
}
2011-12-16 20:10:54 +01:00
return str.charAt(0);
}
@Override
public void write(JsonWriter out, Character value) throws IOException {
out.value(value == null ? null : String.valueOf(value));
}
};
2015-11-05 23:03:51 +01:00
public static final TypeAdapterFactory CHARACTER_FACTORY =
newFactory(char.class, Character.class, CHARACTER);
2011-07-11 18:46:52 +02:00
public static final TypeAdapter<String> STRING =
new TypeAdapter<String>() {
@Override
2011-12-03 20:46:25 +01:00
public String read(JsonReader in) throws IOException {
JsonToken peek = in.peek();
if (peek == JsonToken.NULL) {
in.nextNull();
return null;
}
/* coerce booleans to strings for backwards compatibility */
if (peek == JsonToken.BOOLEAN) {
2011-12-03 20:46:25 +01:00
return Boolean.toString(in.nextBoolean());
}
2011-12-03 20:46:25 +01:00
return in.nextString();
}
2020-05-09 17:37:21 +02:00
@Override
public void write(JsonWriter out, String value) throws IOException {
out.value(value);
}
};
public static final TypeAdapter<BigDecimal> BIG_DECIMAL =
new TypeAdapter<BigDecimal>() {
@Override
public BigDecimal read(JsonReader in) throws IOException {
if (in.peek() == JsonToken.NULL) {
in.nextNull();
return null;
}
String s = in.nextString();
try {
return NumberLimits.parseBigDecimal(s);
} catch (NumberFormatException e) {
throw new JsonSyntaxException(
"Failed parsing '" + s + "' as BigDecimal; at path " + in.getPreviousPath(), e);
}
}
@Override
public void write(JsonWriter out, BigDecimal value) throws IOException {
out.value(value);
}
};
public static final TypeAdapter<BigInteger> BIG_INTEGER =
new TypeAdapter<BigInteger>() {
@Override
public BigInteger read(JsonReader in) throws IOException {
2011-12-03 20:46:25 +01:00
if (in.peek() == JsonToken.NULL) {
in.nextNull();
return null;
}
String s = in.nextString();
try {
return NumberLimits.parseBigInteger(s);
} catch (NumberFormatException e) {
throw new JsonSyntaxException(
"Failed parsing '" + s + "' as BigInteger; at path " + in.getPreviousPath(), e);
}
}
2011-07-11 18:46:52 +02:00
@Override
public void write(JsonWriter out, BigInteger value) throws IOException {
out.value(value);
}
};
public static final TypeAdapter<LazilyParsedNumber> LAZILY_PARSED_NUMBER =
new TypeAdapter<LazilyParsedNumber>() {
// Normally users should not be able to access and deserialize LazilyParsedNumber because
// it is an internal type, but implement this nonetheless in case there are legit corner
// cases where this is possible
@Override
public LazilyParsedNumber read(JsonReader in) throws IOException {
if (in.peek() == JsonToken.NULL) {
in.nextNull();
return null;
}
return new LazilyParsedNumber(in.nextString());
}
@Override
public void write(JsonWriter out, LazilyParsedNumber value) throws IOException {
out.value(value);
}
};
public static final TypeAdapterFactory STRING_FACTORY = newFactory(String.class, STRING);
2011-07-11 18:46:52 +02:00
public static final TypeAdapter<StringBuilder> STRING_BUILDER =
new TypeAdapter<StringBuilder>() {
@Override
2011-12-03 20:46:25 +01:00
public StringBuilder read(JsonReader in) throws IOException {
if (in.peek() == JsonToken.NULL) {
in.nextNull();
return null;
}
2011-12-03 20:46:25 +01:00
return new StringBuilder(in.nextString());
}
@Override
2011-12-03 20:46:25 +01:00
public void write(JsonWriter out, StringBuilder value) throws IOException {
out.value(value == null ? null : value.toString());
}
};
public static final TypeAdapterFactory STRING_BUILDER_FACTORY =
newFactory(StringBuilder.class, STRING_BUILDER);
public static final TypeAdapter<StringBuffer> STRING_BUFFER =
new TypeAdapter<StringBuffer>() {
@Override
2011-12-03 20:46:25 +01:00
public StringBuffer read(JsonReader in) throws IOException {
if (in.peek() == JsonToken.NULL) {
in.nextNull();
return null;
}
2011-12-03 20:46:25 +01:00
return new StringBuffer(in.nextString());
}
@Override
2011-12-03 20:46:25 +01:00
public void write(JsonWriter out, StringBuffer value) throws IOException {
out.value(value == null ? null : value.toString());
}
};
public static final TypeAdapterFactory STRING_BUFFER_FACTORY =
newFactory(StringBuffer.class, STRING_BUFFER);
public static final TypeAdapter<URL> URL =
new TypeAdapter<URL>() {
@Override
2011-12-03 20:46:25 +01:00
public URL read(JsonReader in) throws IOException {
Merge remote-tracking branch 'origin/main' # Conflicts: # .github/ISSUE_TEMPLATE/config.yml # .github/dependabot.yml # .github/pull_request_template.md # .github/workflows/build.yml # .github/workflows/check-android-compatibility.yml # .github/workflows/check-api-compatibility.yml # .github/workflows/cifuzz.yml # .github/workflows/codeql-analysis.yml # extras/pom.xml # extras/src/main/java/com/google/gson/extras/examples/rawcollections/RawCollectionsExample.java # extras/src/main/java/com/google/gson/graph/GraphAdapterBuilder.java # extras/src/main/java/com/google/gson/interceptors/Intercept.java # extras/src/main/java/com/google/gson/interceptors/InterceptorFactory.java # extras/src/main/java/com/google/gson/interceptors/JsonPostDeserializer.java # extras/src/main/java/com/google/gson/typeadapters/PostConstructAdapterFactory.java # extras/src/main/java/com/google/gson/typeadapters/RuntimeTypeAdapterFactory.java # extras/src/main/java/com/google/gson/typeadapters/UtcDateTypeAdapter.java # extras/src/test/java/com/google/gson/graph/GraphAdapterBuilderTest.java # extras/src/test/java/com/google/gson/interceptors/InterceptorTest.java # extras/src/test/java/com/google/gson/typeadapters/PostConstructAdapterFactoryTest.java # extras/src/test/java/com/google/gson/typeadapters/RuntimeTypeAdapterFactoryTest.java # extras/src/test/java/com/google/gson/typeadapters/UtcDateTypeAdapterTest.java # graal-native-image-test/pom.xml # graal-native-image-test/src/test/java/com/google/gson/native_test/Java17RecordReflectionTest.java # graal-native-image-test/src/test/java/com/google/gson/native_test/ReflectionTest.java # gson/pom.xml # gson/src/main/java/com/google/gson/Gson.java # gson/src/main/java/com/google/gson/GsonBuilder.java # gson/src/main/java/com/google/gson/JsonParser.java # gson/src/main/java/com/google/gson/internal/LinkedTreeMap.java # gson/src/main/java/com/google/gson/internal/bind/DateTypeAdapter.java # gson/src/main/java/com/google/gson/internal/bind/DefaultDateTypeAdapter.java # gson/src/main/java/com/google/gson/internal/bind/MapTypeAdapterFactory.java # gson/src/main/java/com/google/gson/internal/bind/TypeAdapters.java # gson/src/main/java/com/google/gson/stream/JsonReader.java # gson/src/main/java/com/google/gson/stream/JsonTreeWriter.java # gson/src/main/java/com/google/gson/stream/JsonWriter.java # gson/src/test/java/com/google/gson/CommentsTest.java # gson/src/test/java/com/google/gson/GsonTest.java # gson/src/test/java/com/google/gson/MixedStreamTest.java # gson/src/test/java/com/google/gson/ToNumberPolicyTest.java # gson/src/test/java/com/google/gson/functional/ArrayTest.java # gson/src/test/java/com/google/gson/functional/ConcurrencyTest.java # gson/src/test/java/com/google/gson/functional/CustomDeserializerTest.java # gson/src/test/java/com/google/gson/functional/CustomTypeAdaptersTest.java # gson/src/test/java/com/google/gson/functional/DefaultTypeAdaptersTest.java # gson/src/test/java/com/google/gson/functional/EnumWithObfuscatedTest.java # gson/src/test/java/com/google/gson/functional/ExposeFieldsTest.java # gson/src/test/java/com/google/gson/functional/FormattingStyleTest.java # gson/src/test/java/com/google/gson/functional/InstanceCreatorTest.java # gson/src/test/java/com/google/gson/functional/InternationalizationTest.java # gson/src/test/java/com/google/gson/functional/Java17RecordTest.java # gson/src/test/java/com/google/gson/functional/JavaUtilConcurrentAtomicTest.java # gson/src/test/java/com/google/gson/functional/JsonAdapterAnnotationOnClassesTest.java # gson/src/test/java/com/google/gson/functional/JsonAdapterAnnotationOnFieldsTest.java # gson/src/test/java/com/google/gson/functional/JsonParserTest.java # gson/src/test/java/com/google/gson/functional/NullObjectAndFieldTest.java # gson/src/test/java/com/google/gson/functional/ObjectTest.java # gson/src/test/java/com/google/gson/functional/PrimitiveTest.java # gson/src/test/java/com/google/gson/functional/ReflectionAccessTest.java # gson/src/test/java/com/google/gson/functional/StreamingTypeAdaptersTest.java # gson/src/test/java/com/google/gson/functional/TreeTypeAdaptersTest.java # gson/src/test/java/com/google/gson/functional/TypeAdapterPrecedenceTest.java # gson/src/test/java/com/google/gson/internal/bind/Java17ReflectiveTypeAdapterFactoryTest.java # gson/src/test/java/com/google/gson/internal/bind/JsonTreeReaderTest.java # gson/src/test/java/com/google/gson/internal/bind/JsonTreeWriterTest.java # gson/src/test/java/com/google/gson/internal/reflect/Java17ReflectionHelperTest.java # gson/src/test/java/com/google/gson/stream/JsonReaderTest.java # metrics/pom.xml # metrics/src/main/java/com/google/gson/metrics/BagOfPrimitives.java # metrics/src/main/java/com/google/gson/metrics/BagOfPrimitivesDeserializationBenchmark.java # metrics/src/main/java/com/google/gson/metrics/CollectionsDeserializationBenchmark.java # metrics/src/main/java/com/google/gson/metrics/NonUploadingCaliperRunner.java # metrics/src/main/java/com/google/gson/metrics/ParseBenchmark.java # metrics/src/main/java/com/google/gson/metrics/SerializationBenchmark.java # pom.xml # proto/pom.xml # proto/src/main/java/com/google/gson/protobuf/ProtoTypeAdapter.java # proto/src/test/java/com/google/gson/protobuf/functional/ProtosWithAnnotationsTest.java # proto/src/test/java/com/google/gson/protobuf/functional/ProtosWithComplexAndRepeatedFieldsTest.java # proto/src/test/java/com/google/gson/protobuf/functional/ProtosWithPrimitiveTypesTest.java # shrinker-test/pom.xml # shrinker-test/src/main/java/com/example/ClassWithExposeAnnotation.java # shrinker-test/src/main/java/com/example/ClassWithHasArgsConstructor.java # shrinker-test/src/main/java/com/example/ClassWithJsonAdapterAnnotation.java # shrinker-test/src/main/java/com/example/ClassWithNoArgsConstructor.java # shrinker-test/src/main/java/com/example/ClassWithUnreferencedHasArgsConstructor.java # shrinker-test/src/main/java/com/example/ClassWithUnreferencedNoArgsConstructor.java # shrinker-test/src/main/java/com/example/ClassWithVersionAnnotations.java # shrinker-test/src/main/java/com/example/GenericClasses.java # shrinker-test/src/main/java/com/example/Main.java # shrinker-test/src/main/java/com/example/NoSerializedNameMain.java # shrinker-test/src/main/java/com/example/TestExecutor.java # shrinker-test/src/main/java/com/example/UnusedClass.java # shrinker-test/src/test/java/com/google/gson/it/ShrinkingIT.java
2024-03-12 12:56:07 +01:00
URI uri = URI.read(in);
return uri == null ? null : uri.toURL();
}
@Override
2011-12-03 20:46:25 +01:00
public void write(JsonWriter out, URL value) throws IOException {
out.value(value == null ? null : value.toExternalForm());
}
};
public static final TypeAdapterFactory URL_FACTORY = newFactory(URL.class, URL);
public static final TypeAdapter<URI> URI =
new TypeAdapter<URI>() {
@Override
2011-12-03 20:46:25 +01:00
public URI read(JsonReader in) throws IOException {
if (in.peek() == JsonToken.NULL) {
in.nextNull();
return null;
}
try {
2011-12-03 20:46:25 +01:00
String nextString = in.nextString();
return nextString.equals("null") ? null : new URI(nextString);
} catch (URISyntaxException e) {
throw new JsonIOException(e);
}
}
@Override
2011-12-03 20:46:25 +01:00
public void write(JsonWriter out, URI value) throws IOException {
out.value(value == null ? null : value.toASCIIString());
}
};
public static final TypeAdapterFactory URI_FACTORY = newFactory(URI.class, URI);
public static final TypeAdapter<InetAddress> INET_ADDRESS =
new TypeAdapter<InetAddress>() {
@Override
2011-12-03 20:46:25 +01:00
public InetAddress read(JsonReader in) throws IOException {
if (in.peek() == JsonToken.NULL) {
in.nextNull();
return null;
}
// regrettably, this should have included both the host name and the host address
// For compatibility, we use InetAddress.getByName rather than the possibly-better
// .getAllByName
@SuppressWarnings("AddressSelection")
InetAddress addr = InetAddress.getByName(in.nextString());
return addr;
}
@Override
2011-12-03 20:46:25 +01:00
public void write(JsonWriter out, InetAddress value) throws IOException {
out.value(value == null ? null : value.getHostAddress());
}
};
public static final TypeAdapterFactory INET_ADDRESS_FACTORY =
newTypeHierarchyFactory(InetAddress.class, INET_ADDRESS);
public static final TypeAdapter<UUID> UUID =
new TypeAdapter<UUID>() {
@Override
2011-12-03 20:46:25 +01:00
public UUID read(JsonReader in) throws IOException {
if (in.peek() == JsonToken.NULL) {
in.nextNull();
return null;
}
String s = in.nextString();
try {
return java.util.UUID.fromString(s);
} catch (IllegalArgumentException e) {
throw new JsonSyntaxException(
"Failed parsing '" + s + "' as UUID; at path " + in.getPreviousPath(), e);
}
}
@Override
2011-12-03 20:46:25 +01:00
public void write(JsonWriter out, UUID value) throws IOException {
out.value(value == null ? null : value.toString());
}
};
public static final TypeAdapterFactory UUID_FACTORY = newFactory(UUID.class, UUID);
2015-11-07 00:41:15 +01:00
public static final TypeAdapter<Currency> CURRENCY =
new TypeAdapter<Currency>() {
@Override
public Currency read(JsonReader in) throws IOException {
String s = in.nextString();
try {
return Currency.getInstance(s);
} catch (IllegalArgumentException e) {
throw new JsonSyntaxException(
"Failed parsing '" + s + "' as Currency; at path " + in.getPreviousPath(), e);
2015-11-07 00:41:15 +01:00
}
}
@Override
public void write(JsonWriter out, Currency value) throws IOException {
out.value(value.getCurrencyCode());
}
2015-11-07 00:41:15 +01:00
}.nullSafe();
public static final TypeAdapterFactory CURRENCY_FACTORY = newFactory(Currency.class, CURRENCY);
public static final TypeAdapter<Calendar> CALENDAR =
new TypeAdapter<Calendar>() {
private static final String YEAR = "year";
private static final String MONTH = "month";
private static final String DAY_OF_MONTH = "dayOfMonth";
private static final String HOUR_OF_DAY = "hourOfDay";
private static final String MINUTE = "minute";
private static final String SECOND = "second";
@Override
2011-12-03 20:46:25 +01:00
public Calendar read(JsonReader in) throws IOException {
if (in.peek() == JsonToken.NULL) {
in.nextNull();
return null;
}
2011-12-03 20:46:25 +01:00
in.beginObject();
int year = 0;
int month = 0;
int dayOfMonth = 0;
int hourOfDay = 0;
int minute = 0;
int second = 0;
2011-12-03 20:46:25 +01:00
while (in.peek() != JsonToken.END_OBJECT) {
String name = in.nextName();
int value = in.nextInt();
switch (name) {
case YEAR:
year = value;
break;
case MONTH:
month = value;
break;
case DAY_OF_MONTH:
dayOfMonth = value;
break;
case HOUR_OF_DAY:
hourOfDay = value;
break;
case MINUTE:
minute = value;
break;
case SECOND:
second = value;
break;
default:
// Ignore unknown JSON property
}
}
2011-12-03 20:46:25 +01:00
in.endObject();
return new GregorianCalendar(year, month, dayOfMonth, hourOfDay, minute, second);
}
@Override
2011-12-03 20:46:25 +01:00
public void write(JsonWriter out, Calendar value) throws IOException {
if (value == null) {
2011-12-03 20:46:25 +01:00
out.nullValue();
return;
}
2011-12-03 20:46:25 +01:00
out.beginObject();
out.name(YEAR);
out.value(value.get(Calendar.YEAR));
out.name(MONTH);
out.value(value.get(Calendar.MONTH));
out.name(DAY_OF_MONTH);
out.value(value.get(Calendar.DAY_OF_MONTH));
out.name(HOUR_OF_DAY);
out.value(value.get(Calendar.HOUR_OF_DAY));
out.name(MINUTE);
out.value(value.get(Calendar.MINUTE));
out.name(SECOND);
out.value(value.get(Calendar.SECOND));
out.endObject();
}
};
public static final TypeAdapterFactory CALENDAR_FACTORY =
newFactoryForMultipleTypes(Calendar.class, GregorianCalendar.class, CALENDAR);
public static final TypeAdapter<Locale> LOCALE =
new TypeAdapter<Locale>() {
2011-12-03 20:46:25 +01:00
@Override
public Locale read(JsonReader in) throws IOException {
if (in.peek() == JsonToken.NULL) {
in.nextNull();
return null;
}
2011-12-03 20:46:25 +01:00
String locale = in.nextString();
StringTokenizer tokenizer = new StringTokenizer(locale, "_");
String language = null;
String country = null;
String variant = null;
if (tokenizer.hasMoreElements()) {
language = tokenizer.nextToken();
}
if (tokenizer.hasMoreElements()) {
country = tokenizer.nextToken();
}
if (tokenizer.hasMoreElements()) {
variant = tokenizer.nextToken();
}
if (country == null && variant == null) {
return new Locale(language);
} else if (variant == null) {
return new Locale(language, country);
} else {
return new Locale(language, country, variant);
}
}
@Override
2011-12-03 20:46:25 +01:00
public void write(JsonWriter out, Locale value) throws IOException {
out.value(value == null ? null : value.toString());
}
};
public static final TypeAdapterFactory LOCALE_FACTORY = newFactory(Locale.class, LOCALE);
public static final TypeAdapter<JsonElement> JSON_ELEMENT =
new TypeAdapter<JsonElement>() {
/**
* Tries to begin reading a JSON array or JSON object, returning {@code null} if the next
* element is neither of those.
*/
private JsonElement tryBeginNesting(JsonReader in, JsonToken peeked) throws IOException {
switch (peeked) {
case BEGIN_ARRAY:
in.beginArray();
return new JsonArray();
case BEGIN_OBJECT:
in.beginObject();
return new JsonObject();
default:
return null;
}
}
/** Reads a {@link JsonElement} which cannot have any nested elements */
private JsonElement readTerminal(JsonReader in, JsonToken peeked) throws IOException {
switch (peeked) {
case STRING:
return new JsonPrimitive(in.nextString());
case NUMBER:
String number = in.nextString();
return new JsonPrimitive(new LazilyParsedNumber(number));
case BOOLEAN:
return new JsonPrimitive(in.nextBoolean());
case NULL:
in.nextNull();
return JsonNull.INSTANCE;
default:
// When read(JsonReader) is called with JsonReader in invalid state
throw new IllegalStateException("Unexpected token: " + peeked);
}
}
2011-12-03 20:46:25 +01:00
@Override
public JsonElement read(JsonReader in) throws IOException {
if (in instanceof JsonTreeReader) {
return ((JsonTreeReader) in).nextJsonElement();
}
// Either JsonArray or JsonObject
JsonElement current;
JsonToken peeked = in.peek();
current = tryBeginNesting(in, peeked);
if (current == null) {
return readTerminal(in, peeked);
}
Deque<JsonElement> stack = new ArrayDeque<>();
while (true) {
2011-12-03 20:46:25 +01:00
while (in.hasNext()) {
String name = null;
// Name is only used for JSON object members
if (current instanceof JsonObject) {
name = in.nextName();
}
peeked = in.peek();
JsonElement value = tryBeginNesting(in, peeked);
boolean isNesting = value != null;
if (value == null) {
value = readTerminal(in, peeked);
}
if (current instanceof JsonArray) {
((JsonArray) current).add(value);
} else {
((JsonObject) current).add(name, value);
}
if (isNesting) {
stack.addLast(current);
current = value;
}
}
// End current element
if (current instanceof JsonArray) {
in.endArray();
} else {
in.endObject();
}
if (stack.isEmpty()) {
return current;
} else {
// Continue with enclosing element
current = stack.removeLast();
}
}
}
2011-12-03 20:46:25 +01:00
@Override
public void write(JsonWriter out, JsonElement value) throws IOException {
if (value == null || value.isJsonNull()) {
2011-12-03 20:46:25 +01:00
out.nullValue();
} else if (value.isJsonPrimitive()) {
JsonPrimitive primitive = value.getAsJsonPrimitive();
if (primitive.isNumber()) {
2011-12-03 20:46:25 +01:00
out.value(primitive.getAsNumber());
} else if (primitive.isBoolean()) {
2011-12-03 20:46:25 +01:00
out.value(primitive.getAsBoolean());
} else {
2011-12-03 20:46:25 +01:00
out.value(primitive.getAsString());
}
} else if (value.isJsonArray()) {
2011-12-03 20:46:25 +01:00
out.beginArray();
for (JsonElement e : value.getAsJsonArray()) {
2011-12-03 20:46:25 +01:00
write(out, e);
}
2011-12-03 20:46:25 +01:00
out.endArray();
} else if (value.isJsonObject()) {
2011-12-03 20:46:25 +01:00
out.beginObject();
for (Map.Entry<String, JsonElement> e : value.getAsJsonObject().entrySet()) {
2011-12-03 20:46:25 +01:00
out.name(e.getKey());
write(out, e.getValue());
}
2011-12-03 20:46:25 +01:00
out.endObject();
} else {
throw new IllegalArgumentException("Couldn't write " + value.getClass());
}
}
};
public static final TypeAdapterFactory JSON_ELEMENT_FACTORY =
newTypeHierarchyFactory(JsonElement.class, JSON_ELEMENT);
private static final class EnumTypeAdapter<T extends Enum<T>> extends TypeAdapter<T> {
private final Map<String, T> nameToConstant = new HashMap<>();
private final Map<String, T> stringToConstant = new HashMap<>();
private final Map<T, String> constantToName = new HashMap<>();
public EnumTypeAdapter(final Class<T> classOfT) {
try {
// Uses reflection to find enum constants to work around name mismatches for obfuscated
// classes
// Reflection access might throw SecurityException, therefore run this in privileged
// context; should be acceptable because this only retrieves enum constants, but does not
// expose anything else
Merge remote-tracking branch 'origin/master' # Conflicts: # extras/pom.xml # extras/src/main/java/com/google/gson/graph/GraphAdapterBuilder.java # extras/src/main/java/com/google/gson/interceptors/InterceptorFactory.java # extras/src/test/java/com/google/gson/typeadapters/PostConstructAdapterFactoryTest.java # gson/src/main/java/com/google/gson/Gson.java # gson/src/main/java/com/google/gson/GsonBuilder.java # gson/src/main/java/com/google/gson/util/ISO8601Utils.java # gson/src/main/java/module-info.java # gson/src/test/java/com/google/gson/GsonTest.java # gson/src/test/java/com/google/gson/functional/ArrayTest.java # gson/src/test/java/com/google/gson/functional/CustomTypeAdaptersTest.java # gson/src/test/java/com/google/gson/functional/DefaultTypeAdaptersTest.java # gson/src/test/java/com/google/gson/functional/EnumWithObfuscatedTest.java # gson/src/test/java/com/google/gson/functional/InternationalizationTest.java # gson/src/test/java/com/google/gson/functional/Java17RecordTest.java # gson/src/test/java/com/google/gson/functional/JavaUtilConcurrentAtomicTest.java # gson/src/test/java/com/google/gson/functional/JavaUtilTest.java # gson/src/test/java/com/google/gson/functional/JsonAdapterAnnotationOnClassesTest.java # gson/src/test/java/com/google/gson/functional/JsonAdapterAnnotationOnFieldsTest.java # gson/src/test/java/com/google/gson/functional/JsonParserTest.java # gson/src/test/java/com/google/gson/functional/MapTest.java # gson/src/test/java/com/google/gson/functional/PrimitiveTest.java # gson/src/test/java/com/google/gson/functional/ReflectionAccessTest.java # gson/src/test/java/com/google/gson/functional/StreamingTypeAdaptersTest.java # gson/src/test/java/com/google/gson/functional/TypeAdapterPrecedenceTest.java # gson/src/test/java/com/google/gson/internal/bind/Java17ReflectiveTypeAdapterFactoryTest.java # gson/src/test/java/com/google/gson/internal/bind/JsonTreeReaderTest.java # gson/src/test/java/com/google/gson/internal/bind/JsonTreeWriterTest.java # gson/src/test/java/com/google/gson/internal/reflect/Java17ReflectionHelperTest.java # gson/src/test/java/com/google/gson/regression/JsonAdapterNullSafeTest.java # gson/src/test/java/com/google/gson/stream/JsonReaderPathTest.java # gson/src/test/java/com/google/gson/stream/JsonReaderTest.java # metrics/pom.xml # metrics/src/main/java/com/google/gson/metrics/NonUploadingCaliperRunner.java # metrics/src/main/java/com/google/gson/metrics/ParseBenchmark.java # pom.xml # proto/pom.xml
2023-02-23 14:02:45 +01:00
Field[] constantFields;
{
Field[] fields = classOfT.getDeclaredFields();
ArrayList<Field> constantFieldsList = new ArrayList<>(fields.length);
for (Field f : fields) {
if (f.isEnumConstant()) {
constantFieldsList.add(f);
}
}
Merge remote-tracking branch 'origin/master' # Conflicts: # extras/pom.xml # extras/src/main/java/com/google/gson/graph/GraphAdapterBuilder.java # extras/src/main/java/com/google/gson/interceptors/InterceptorFactory.java # extras/src/test/java/com/google/gson/typeadapters/PostConstructAdapterFactoryTest.java # gson/src/main/java/com/google/gson/Gson.java # gson/src/main/java/com/google/gson/GsonBuilder.java # gson/src/main/java/com/google/gson/util/ISO8601Utils.java # gson/src/main/java/module-info.java # gson/src/test/java/com/google/gson/GsonTest.java # gson/src/test/java/com/google/gson/functional/ArrayTest.java # gson/src/test/java/com/google/gson/functional/CustomTypeAdaptersTest.java # gson/src/test/java/com/google/gson/functional/DefaultTypeAdaptersTest.java # gson/src/test/java/com/google/gson/functional/EnumWithObfuscatedTest.java # gson/src/test/java/com/google/gson/functional/InternationalizationTest.java # gson/src/test/java/com/google/gson/functional/Java17RecordTest.java # gson/src/test/java/com/google/gson/functional/JavaUtilConcurrentAtomicTest.java # gson/src/test/java/com/google/gson/functional/JavaUtilTest.java # gson/src/test/java/com/google/gson/functional/JsonAdapterAnnotationOnClassesTest.java # gson/src/test/java/com/google/gson/functional/JsonAdapterAnnotationOnFieldsTest.java # gson/src/test/java/com/google/gson/functional/JsonParserTest.java # gson/src/test/java/com/google/gson/functional/MapTest.java # gson/src/test/java/com/google/gson/functional/PrimitiveTest.java # gson/src/test/java/com/google/gson/functional/ReflectionAccessTest.java # gson/src/test/java/com/google/gson/functional/StreamingTypeAdaptersTest.java # gson/src/test/java/com/google/gson/functional/TypeAdapterPrecedenceTest.java # gson/src/test/java/com/google/gson/internal/bind/Java17ReflectiveTypeAdapterFactoryTest.java # gson/src/test/java/com/google/gson/internal/bind/JsonTreeReaderTest.java # gson/src/test/java/com/google/gson/internal/bind/JsonTreeWriterTest.java # gson/src/test/java/com/google/gson/internal/reflect/Java17ReflectionHelperTest.java # gson/src/test/java/com/google/gson/regression/JsonAdapterNullSafeTest.java # gson/src/test/java/com/google/gson/stream/JsonReaderPathTest.java # gson/src/test/java/com/google/gson/stream/JsonReaderTest.java # metrics/pom.xml # metrics/src/main/java/com/google/gson/metrics/NonUploadingCaliperRunner.java # metrics/src/main/java/com/google/gson/metrics/ParseBenchmark.java # pom.xml # proto/pom.xml
2023-02-23 14:02:45 +01:00
constantFields = constantFieldsList.toArray(new Field[0]);
AccessibleObject.setAccessible(constantFields, true);
}
for (Field constantField : constantFields) {
2020-09-12 06:40:09 +02:00
@SuppressWarnings("unchecked")
Fix error prone warnings (#2316) * Fix `OperatorPrecedence` warn in `JsonWriter#close` * Fix `ReferenceEquality` warn in `LinkedTreeMap#replaceInParent` * Fix `UnnecessaryParentheses` warn in `LinkedTreeMap#replaceInParent` * Fix `ReferenceEquality` warn in `LinkedTreeMap#hasNext` * Fix `ReferenceEquality` warn in `LinkedTreeMap#nextNode` * Adds `error_prone_annotations` to the `pom.xml` of `gson` * Fix `InlineMeSuggester` warns in `JsonParser` * Fix `UnnecessaryParentheses` warns in `ConstructorConstructor#newDefaultImplementationConstructor` * Fix `ThreadLocalUsage` warn in `Gson` * Fix `JdkObsolete` warn in `GsonBuilder` * Fix `ReferenceEquality` warn in `LazilyParsedNumber#equals` * Fix `OperatorPrecedence` warn in `TreeTypeAdapter#create` * Fix `OperatorPrecedence` warn in `ArrayTypeAdapter` * Fix `UnnecessaryParentheses` warn in `TypeAdapters` * Adds `-XepExcludedPaths` flag to ErrorProne plugin to exclude tests and proto path * Fix `ClassNewInstance` warn in `InterceptorAdapter` * Fix `ThreadLocalUsage` warn in `GraphAdapterBuilder` * Fix `JdkObsolete` warn in `GraphAdapterBuilder` * Revert "Adds `error_prone_annotations` to the `pom.xml` of `gson`" This reverts commit 14af14dfa23b46a54f4855a70ccf2b0a2cdc3e3f. * Revert "Fix `InlineMeSuggester` warns in `JsonParser`" This reverts commit 095bfd517e06510e4cc9cc6b1aac58ad9bf3038a. * Adds `@SuppressWarnings("ThreadLocalUsage")` * Fix `OperatorPrecedence` in `JsonWriter` * Revert "Fix `ReferenceEquality` warn in `LinkedTreeMap#nextNode`" This reverts commit 387746c7f7e3d0943c8f80501f5d9c3710f4862e. * Adds `@SuppressWarnings("ReferenceEquality")` * Adds `guava-testlib` to the gson `pom.xml` * `@SuppressWarnings("TruthSelfEquals")` removed to use `EqualsTester()`
2023-02-15 14:18:43 +01:00
T constant = (T) constantField.get(null);
String name = constant.name();
String toStringVal = constant.toString();
SerializedName annotation = constantField.getAnnotation(SerializedName.class);
if (annotation != null) {
name = annotation.value();
for (String alternate : annotation.alternate()) {
nameToConstant.put(alternate, constant);
}
}
nameToConstant.put(name, constant);
stringToConstant.put(toStringVal, constant);
constantToName.put(constant, name);
}
} catch (IllegalAccessException e) {
throw new AssertionError(e);
}
}
@Override
public T read(JsonReader in) throws IOException {
2011-12-03 20:46:25 +01:00
if (in.peek() == JsonToken.NULL) {
in.nextNull();
return null;
}
String key = in.nextString();
T constant = nameToConstant.get(key);
return (constant == null) ? stringToConstant.get(key) : constant;
}
@Override
public void write(JsonWriter out, T value) throws IOException {
out.value(value == null ? null : constantToName.get(value));
}
}
public static final TypeAdapterFactory ENUM_FACTORY =
new TypeAdapterFactory() {
@Override
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) {
Class<? super T> rawType = typeToken.getRawType();
if (!Enum.class.isAssignableFrom(rawType) || rawType == Enum.class) {
return null;
}
if (!rawType.isEnum()) {
rawType = rawType.getSuperclass(); // handle anonymous subclasses
}
@SuppressWarnings({"rawtypes", "unchecked"})
TypeAdapter<T> adapter = (TypeAdapter<T>) new EnumTypeAdapter(rawType);
return adapter;
}
};
@SuppressWarnings("TypeParameterNaming")
public static <TT> TypeAdapterFactory newFactory(
final TypeToken<TT> type, final TypeAdapter<TT> typeAdapter) {
return new TypeAdapterFactory() {
2011-07-11 18:46:52 +02:00
@SuppressWarnings("unchecked") // we use a runtime check to make sure the 'T's equal
@Override
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) {
2011-07-11 18:46:52 +02:00
return typeToken.equals(type) ? (TypeAdapter<T>) typeAdapter : null;
}
};
}
@SuppressWarnings("TypeParameterNaming")
public static <TT> TypeAdapterFactory newFactory(
final Class<TT> type, final TypeAdapter<TT> typeAdapter) {
return new TypeAdapterFactory() {
2011-07-11 18:46:52 +02:00
@SuppressWarnings("unchecked") // we use a runtime check to make sure the 'T's equal
@Override
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) {
2011-07-11 18:46:52 +02:00
return typeToken.getRawType() == type ? (TypeAdapter<T>) typeAdapter : null;
}
@Override
public String toString() {
return "Factory[type=" + type.getName() + ",adapter=" + typeAdapter + "]";
}
2011-07-11 18:46:52 +02:00
};
}
@SuppressWarnings("TypeParameterNaming")
public static <TT> TypeAdapterFactory newFactory(
final Class<TT> unboxed, final Class<TT> boxed, final TypeAdapter<? super TT> typeAdapter) {
return new TypeAdapterFactory() {
2011-07-11 18:46:52 +02:00
@SuppressWarnings("unchecked") // we use a runtime check to make sure the 'T's equal
@Override
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) {
2011-07-11 18:46:52 +02:00
Class<? super T> rawType = typeToken.getRawType();
return (rawType == unboxed || rawType == boxed) ? (TypeAdapter<T>) typeAdapter : null;
}
@Override
public String toString() {
return "Factory[type="
+ boxed.getName()
+ "+"
+ unboxed.getName()
+ ",adapter="
+ typeAdapter
+ "]";
}
2011-07-11 18:46:52 +02:00
};
}
@SuppressWarnings("TypeParameterNaming")
public static <TT> TypeAdapterFactory newFactoryForMultipleTypes(
final Class<TT> base,
final Class<? extends TT> sub,
final TypeAdapter<? super TT> typeAdapter) {
return new TypeAdapterFactory() {
@SuppressWarnings("unchecked") // we use a runtime check to make sure the 'T's equal
@Override
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) {
Class<? super T> rawType = typeToken.getRawType();
return (rawType == base || rawType == sub) ? (TypeAdapter<T>) typeAdapter : null;
}
@Override
public String toString() {
return "Factory[type="
+ base.getName()
+ "+"
+ sub.getName()
+ ",adapter="
+ typeAdapter
+ "]";
}
};
}
/**
* Returns a factory for all subtypes of {@code typeAdapter}. We do a runtime check to confirm
* that the deserialized type matches the type requested.
*/
public static <T1> TypeAdapterFactory newTypeHierarchyFactory(
final Class<T1> clazz, final TypeAdapter<T1> typeAdapter) {
return new TypeAdapterFactory() {
@SuppressWarnings("unchecked")
@Override
public <T2> TypeAdapter<T2> create(Gson gson, TypeToken<T2> typeToken) {
final Class<? super T2> requestedType = typeToken.getRawType();
if (!clazz.isAssignableFrom(requestedType)) {
return null;
}
return (TypeAdapter<T2>)
new TypeAdapter<T1>() {
@Override
public void write(JsonWriter out, T1 value) throws IOException {
typeAdapter.write(out, value);
}
@Override
public T1 read(JsonReader in) throws IOException {
T1 result = typeAdapter.read(in);
if (result != null && !requestedType.isInstance(result)) {
throw new JsonSyntaxException(
"Expected a "
+ requestedType.getName()
+ " but was "
+ result.getClass().getName()
+ "; at path "
+ in.getPreviousPath());
}
return result;
}
};
2011-07-11 18:46:52 +02:00
}
@Override
public String toString() {
return "Factory[typeHierarchy=" + clazz.getName() + ",adapter=" + typeAdapter + "]";
}
2011-07-11 18:46:52 +02:00
};
}
}