From 38ce93ae17b611b29da49ba87d5f60a02a6399db Mon Sep 17 00:00:00 2001 From: Marcono1234 Date: Sun, 11 Aug 2024 14:59:27 +0200 Subject: [PATCH 1/3] Move enum and `JsonElement` adapter classes to separate class files Their implementation is complex enough to probably justify having them in their own class files, to make maintaining them easier. For the users this should not be noticeable since these classes are still in the Gson internal package. --- gson/src/main/java/com/google/gson/Gson.java | 6 +- .../com/google/gson/internal/Streams.java | 6 +- .../gson/internal/bind/ArrayTypeAdapter.java | 2 +- .../gson/internal/bind/EnumTypeAdapter.java | 112 +++++++++ .../internal/bind/JsonElementTypeAdapter.java | 175 +++++++++++++ .../gson/internal/bind/TypeAdapters.java | 230 +----------------- 6 files changed, 299 insertions(+), 232 deletions(-) create mode 100644 gson/src/main/java/com/google/gson/internal/bind/EnumTypeAdapter.java create mode 100644 gson/src/main/java/com/google/gson/internal/bind/JsonElementTypeAdapter.java diff --git a/gson/src/main/java/com/google/gson/Gson.java b/gson/src/main/java/com/google/gson/Gson.java index 196dc90fc3..e7fef48cec 100644 --- a/gson/src/main/java/com/google/gson/Gson.java +++ b/gson/src/main/java/com/google/gson/Gson.java @@ -26,7 +26,9 @@ import com.google.gson.internal.bind.ArrayTypeAdapter; import com.google.gson.internal.bind.CollectionTypeAdapterFactory; import com.google.gson.internal.bind.DefaultDateTypeAdapter; +import com.google.gson.internal.bind.EnumTypeAdapter; import com.google.gson.internal.bind.JsonAdapterAnnotationTypeAdapterFactory; +import com.google.gson.internal.bind.JsonElementTypeAdapter; import com.google.gson.internal.bind.JsonTreeReader; import com.google.gson.internal.bind.JsonTreeWriter; import com.google.gson.internal.bind.MapTypeAdapterFactory; @@ -323,7 +325,7 @@ public Gson() { List factories = new ArrayList<>(); // built-in type adapters that cannot be overridden - factories.add(TypeAdapters.JSON_ELEMENT_FACTORY); + factories.add(JsonElementTypeAdapter.FACTORY); factories.add(ObjectTypeAdapter.getFactory(objectToNumberStrategy)); // the excluder must precede all adapters that handle user-defined types @@ -386,7 +388,7 @@ public Gson() { factories.add(new MapTypeAdapterFactory(constructorConstructor, complexMapKeySerialization)); this.jsonAdapterFactory = new JsonAdapterAnnotationTypeAdapterFactory(constructorConstructor); factories.add(jsonAdapterFactory); - factories.add(TypeAdapters.ENUM_FACTORY); + factories.add(EnumTypeAdapter.FACTORY); factories.add( new ReflectiveTypeAdapterFactory( constructorConstructor, diff --git a/gson/src/main/java/com/google/gson/internal/Streams.java b/gson/src/main/java/com/google/gson/internal/Streams.java index 46df853f5a..8ef82860de 100644 --- a/gson/src/main/java/com/google/gson/internal/Streams.java +++ b/gson/src/main/java/com/google/gson/internal/Streams.java @@ -21,7 +21,7 @@ import com.google.gson.JsonNull; import com.google.gson.JsonParseException; import com.google.gson.JsonSyntaxException; -import com.google.gson.internal.bind.TypeAdapters; +import com.google.gson.internal.bind.JsonElementTypeAdapter; import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonToken; import com.google.gson.stream.JsonWriter; @@ -43,7 +43,7 @@ public static JsonElement parse(JsonReader reader) throws JsonParseException { try { JsonToken unused = reader.peek(); isEmpty = false; - return TypeAdapters.JSON_ELEMENT.read(reader); + return JsonElementTypeAdapter.ADAPTER.read(reader); } catch (EOFException e) { /* * For compatibility with JSON 1.5 and earlier, we return a JsonNull for @@ -65,7 +65,7 @@ public static JsonElement parse(JsonReader reader) throws JsonParseException { /** Writes the JSON element to the writer, recursively. */ public static void write(JsonElement element, JsonWriter writer) throws IOException { - TypeAdapters.JSON_ELEMENT.write(writer, element); + JsonElementTypeAdapter.ADAPTER.write(writer, element); } public static Writer writerForAppendable(Appendable appendable) { diff --git a/gson/src/main/java/com/google/gson/internal/bind/ArrayTypeAdapter.java b/gson/src/main/java/com/google/gson/internal/bind/ArrayTypeAdapter.java index d4224d52cd..a18cbf9262 100644 --- a/gson/src/main/java/com/google/gson/internal/bind/ArrayTypeAdapter.java +++ b/gson/src/main/java/com/google/gson/internal/bind/ArrayTypeAdapter.java @@ -30,7 +30,7 @@ import java.lang.reflect.Type; import java.util.ArrayList; -/** Adapt an array of objects. */ +/** Adapter for arrays. */ public final class ArrayTypeAdapter extends TypeAdapter { public static final TypeAdapterFactory FACTORY = new TypeAdapterFactory() { diff --git a/gson/src/main/java/com/google/gson/internal/bind/EnumTypeAdapter.java b/gson/src/main/java/com/google/gson/internal/bind/EnumTypeAdapter.java new file mode 100644 index 0000000000..d1ac077f4b --- /dev/null +++ b/gson/src/main/java/com/google/gson/internal/bind/EnumTypeAdapter.java @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2024 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. + */ + +package com.google.gson.internal.bind; + +import com.google.gson.Gson; +import com.google.gson.TypeAdapter; +import com.google.gson.TypeAdapterFactory; +import com.google.gson.annotations.SerializedName; +import com.google.gson.reflect.TypeToken; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonToken; +import com.google.gson.stream.JsonWriter; +import java.io.IOException; +import java.lang.reflect.AccessibleObject; +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; + +/** Adapter for enum classes (but not for the base class {@code java.lang.Enum}). */ +public class EnumTypeAdapter> extends TypeAdapter { + public static final TypeAdapterFactory FACTORY = + new TypeAdapterFactory() { + @Override + public TypeAdapter create(Gson gson, TypeToken typeToken) { + Class 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 adapter = (TypeAdapter) new EnumTypeAdapter(rawType); + return adapter; + } + }; + + private final Map nameToConstant = new HashMap<>(); + private final Map stringToConstant = new HashMap<>(); + private final Map constantToName = new HashMap<>(); + + private EnumTypeAdapter(final Class classOfT) { + try { + // Uses reflection to find enum constants to work around name mismatches for obfuscated + // classes + Field[] fields = classOfT.getDeclaredFields(); + ArrayList constantFieldsList = new ArrayList<>(fields.length); + for (Field f : fields) { + if (f.isEnumConstant()) { + constantFieldsList.add(f); + } + } + + Field[] constantFields = constantFieldsList.toArray(new Field[0]); + AccessibleObject.setAccessible(constantFields, true); + + for (Field constantField : constantFields) { + @SuppressWarnings("unchecked") + 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) { + // IllegalAccessException should be impossible due to the `setAccessible` call above; + // and even that should probably not fail since enum constants are implicitly public + throw new AssertionError(e); + } + } + + @Override + public T read(JsonReader in) throws IOException { + if (in.peek() == JsonToken.NULL) { + in.nextNull(); + return null; + } + String key = in.nextString(); + T constant = nameToConstant.get(key); + // Note: If none of the approaches find the constant, this returns null + 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)); + } +} diff --git a/gson/src/main/java/com/google/gson/internal/bind/JsonElementTypeAdapter.java b/gson/src/main/java/com/google/gson/internal/bind/JsonElementTypeAdapter.java new file mode 100644 index 0000000000..8212c507c7 --- /dev/null +++ b/gson/src/main/java/com/google/gson/internal/bind/JsonElementTypeAdapter.java @@ -0,0 +1,175 @@ +/* + * Copyright (C) 2024 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. + */ + +package com.google.gson.internal.bind; + +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonNull; +import com.google.gson.JsonObject; +import com.google.gson.JsonPrimitive; +import com.google.gson.TypeAdapter; +import com.google.gson.TypeAdapterFactory; +import com.google.gson.internal.LazilyParsedNumber; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonToken; +import com.google.gson.stream.JsonWriter; +import java.io.IOException; +import java.util.ArrayDeque; +import java.util.Deque; +import java.util.Map; + +/** Adapter for {@link JsonElement} and subclasses. */ +public class JsonElementTypeAdapter extends TypeAdapter { + public static final JsonElementTypeAdapter ADAPTER = new JsonElementTypeAdapter(); + + public static final TypeAdapterFactory FACTORY = + TypeAdapters.newTypeHierarchyFactory(JsonElement.class, ADAPTER); + + private JsonElementTypeAdapter() {} + + /** + * 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); + } + } + + @Override + public JsonElement read(JsonReader in) throws IOException { + // Optimization if value already exists as JsonElement + 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 stack = new ArrayDeque<>(); + + while (true) { + 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(); + } + } + } + + @Override + public void write(JsonWriter out, JsonElement value) throws IOException { + if (value == null || value.isJsonNull()) { + out.nullValue(); + } else if (value.isJsonPrimitive()) { + JsonPrimitive primitive = value.getAsJsonPrimitive(); + if (primitive.isNumber()) { + out.value(primitive.getAsNumber()); + } else if (primitive.isBoolean()) { + out.value(primitive.getAsBoolean()); + } else { + out.value(primitive.getAsString()); + } + + } else if (value.isJsonArray()) { + out.beginArray(); + for (JsonElement e : value.getAsJsonArray()) { + write(out, e); + } + out.endArray(); + + } else if (value.isJsonObject()) { + out.beginObject(); + for (Map.Entry e : value.getAsJsonObject().entrySet()) { + out.name(e.getKey()); + write(out, e.getValue()); + } + out.endObject(); + + } else { + throw new IllegalArgumentException("Couldn't write " + value.getClass()); + } + } +} diff --git a/gson/src/main/java/com/google/gson/internal/bind/TypeAdapters.java b/gson/src/main/java/com/google/gson/internal/bind/TypeAdapters.java index 75177a2134..295552a5b2 100644 --- a/gson/src/main/java/com/google/gson/internal/bind/TypeAdapters.java +++ b/gson/src/main/java/com/google/gson/internal/bind/TypeAdapters.java @@ -17,16 +17,10 @@ package com.google.gson.internal.bind; 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; @@ -35,32 +29,29 @@ import com.google.gson.stream.JsonToken; 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; 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; -/** Type adapters for basic types. */ +/** + * Type adapters for basic types. More complex adapters exist as separate classes in the enclosing + * package. + */ public final class TypeAdapters { private TypeAdapters() { throw new UnsupportedOperationException(); @@ -814,219 +805,6 @@ public void write(JsonWriter out, Locale value) throws IOException { public static final TypeAdapterFactory LOCALE_FACTORY = newFactory(Locale.class, LOCALE); - public static final TypeAdapter JSON_ELEMENT = - new TypeAdapter() { - /** - * 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); - } - } - - @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 stack = new ArrayDeque<>(); - - while (true) { - 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(); - } - } - } - - @Override - public void write(JsonWriter out, JsonElement value) throws IOException { - if (value == null || value.isJsonNull()) { - out.nullValue(); - } else if (value.isJsonPrimitive()) { - JsonPrimitive primitive = value.getAsJsonPrimitive(); - if (primitive.isNumber()) { - out.value(primitive.getAsNumber()); - } else if (primitive.isBoolean()) { - out.value(primitive.getAsBoolean()); - } else { - out.value(primitive.getAsString()); - } - - } else if (value.isJsonArray()) { - out.beginArray(); - for (JsonElement e : value.getAsJsonArray()) { - write(out, e); - } - out.endArray(); - - } else if (value.isJsonObject()) { - out.beginObject(); - for (Map.Entry e : value.getAsJsonObject().entrySet()) { - out.name(e.getKey()); - write(out, e.getValue()); - } - 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> extends TypeAdapter { - private final Map nameToConstant = new HashMap<>(); - private final Map stringToConstant = new HashMap<>(); - private final Map constantToName = new HashMap<>(); - - public EnumTypeAdapter(final Class classOfT) { - try { - // Uses reflection to find enum constants to work around name mismatches for obfuscated - // classes - Field[] fields = classOfT.getDeclaredFields(); - ArrayList constantFieldsList = new ArrayList<>(fields.length); - for (Field f : fields) { - if (f.isEnumConstant()) { - constantFieldsList.add(f); - } - } - - Field[] constantFields = constantFieldsList.toArray(new Field[0]); - AccessibleObject.setAccessible(constantFields, true); - - for (Field constantField : constantFields) { - @SuppressWarnings("unchecked") - 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 { - 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 TypeAdapter create(Gson gson, TypeToken typeToken) { - Class 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 adapter = (TypeAdapter) new EnumTypeAdapter(rawType); - return adapter; - } - }; - @SuppressWarnings("TypeParameterNaming") public static TypeAdapterFactory newFactory( final TypeToken type, final TypeAdapter typeAdapter) { From effad958b6de39e7f45164d841cad77768d125b9 Mon Sep 17 00:00:00 2001 From: Marcono1234 Date: Tue, 13 Aug 2024 22:20:12 +0200 Subject: [PATCH 2/3] Add back `TypeAdapters` constants used by external projects Note: `JSON_ELEMENT_FACTORY` seems to be rarely used, therefore this has not been added back. --- .../gson/internal/bind/TypeAdapters.java | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/gson/src/main/java/com/google/gson/internal/bind/TypeAdapters.java b/gson/src/main/java/com/google/gson/internal/bind/TypeAdapters.java index 295552a5b2..3de3c7db30 100644 --- a/gson/src/main/java/com/google/gson/internal/bind/TypeAdapters.java +++ b/gson/src/main/java/com/google/gson/internal/bind/TypeAdapters.java @@ -17,6 +17,7 @@ package com.google.gson.internal.bind; import com.google.gson.Gson; +import com.google.gson.JsonElement; import com.google.gson.JsonIOException; import com.google.gson.JsonSyntaxException; import com.google.gson.TypeAdapter; @@ -805,6 +806,30 @@ public void write(JsonWriter out, Locale value) throws IOException { public static final TypeAdapterFactory LOCALE_FACTORY = newFactory(Locale.class, LOCALE); + /* + * The following adapter and factory fields are only deprecated for now because external projects + * might be using them, despite being part of Gson's internal implementation + */ + + /** + * @deprecated {@code TypeAdapters} is an internal Gson class. To obtain the adapter for {@link + * JsonElement} and subclasses use instead: + *
{@code
+   * TypeAdapter adapter = gson.getAdapter(JsonElement.class);
+   * }
+ */ + @Deprecated + public static final TypeAdapter JSON_ELEMENT = JsonElementTypeAdapter.ADAPTER; + + /** + * @deprecated {@code TypeAdapters} is an internal Gson class. To obtain the adapter for a + * specific enum class use instead: + *
{@code
+   * TypeAdapter adapter = gson.getAdapter(MyEnum.class);
+   * }
+ */ + @Deprecated public static final TypeAdapterFactory ENUM_FACTORY = EnumTypeAdapter.FACTORY; + @SuppressWarnings("TypeParameterNaming") public static TypeAdapterFactory newFactory( final TypeToken type, final TypeAdapter typeAdapter) { From 72d5aabcd8c8ca0f958933ca96bff36c655bf94a Mon Sep 17 00:00:00 2001 From: Marcono1234 Date: Sat, 17 Aug 2024 14:17:58 +0200 Subject: [PATCH 3/3] Add back `TypeAdapters.JSON_ELEMENT_FACTORY` --- .../google/gson/internal/bind/TypeAdapters.java | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/gson/src/main/java/com/google/gson/internal/bind/TypeAdapters.java b/gson/src/main/java/com/google/gson/internal/bind/TypeAdapters.java index 3de3c7db30..d3de3805c6 100644 --- a/gson/src/main/java/com/google/gson/internal/bind/TypeAdapters.java +++ b/gson/src/main/java/com/google/gson/internal/bind/TypeAdapters.java @@ -807,8 +807,9 @@ public void write(JsonWriter out, Locale value) throws IOException { public static final TypeAdapterFactory LOCALE_FACTORY = newFactory(Locale.class, LOCALE); /* - * The following adapter and factory fields are only deprecated for now because external projects - * might be using them, despite being part of Gson's internal implementation + * The following adapter and factory fields have not been removed yet and are only deprecated + * for now because external projects might be using them, despite being part of Gson's internal + * implementation. */ /** @@ -821,6 +822,16 @@ public void write(JsonWriter out, Locale value) throws IOException { @Deprecated public static final TypeAdapter JSON_ELEMENT = JsonElementTypeAdapter.ADAPTER; + /** + * @deprecated {@code TypeAdapters} is an internal Gson class. To obtain the adapter for {@link + * JsonElement} and subclasses use instead: + *
{@code
+   * TypeAdapter adapter = gson.getAdapter(JsonElement.class);
+   * }
+ */ + @Deprecated + public static final TypeAdapterFactory JSON_ELEMENT_FACTORY = JsonElementTypeAdapter.FACTORY; + /** * @deprecated {@code TypeAdapters} is an internal Gson class. To obtain the adapter for a * specific enum class use instead: