From 0b6a7bf7d9259f62003cbd458931ae0e61e7334c Mon Sep 17 00:00:00 2001 From: Marcono1234 Date: Thu, 4 Aug 2022 19:32:30 +0200 Subject: [PATCH] Deprecate JsonElement constructor (#1761) * Deprecate JsonElement constructor Creating custom JsonElement subclasses is discouraged. * Improve test and documentation * Improve JsonTreeReaderTest, adjust deprecation comments --- .../main/java/com/google/gson/JsonArray.java | 13 ++++++++-- .../java/com/google/gson/JsonElement.java | 9 +++++++ .../main/java/com/google/gson/JsonNull.java | 5 ++-- .../main/java/com/google/gson/JsonObject.java | 8 +++++- .../java/com/google/gson/JsonPrimitive.java | 7 +++-- .../gson/internal/bind/JsonTreeReader.java | 5 ++-- .../internal/bind/JsonTreeReaderTest.java | 26 +++++++++++++++++++ 7 files changed, 64 insertions(+), 9 deletions(-) diff --git a/gson/src/main/java/com/google/gson/JsonArray.java b/gson/src/main/java/com/google/gson/JsonArray.java index fe8b686d16..d332ed721b 100644 --- a/gson/src/main/java/com/google/gson/JsonArray.java +++ b/gson/src/main/java/com/google/gson/JsonArray.java @@ -36,10 +36,19 @@ public final class JsonArray extends JsonElement implements Iterable(); } - + + /** + * Creates an empty JsonArray with the desired initial capacity. + * + * @param capacity initial capacity. + * @throws IllegalArgumentException if the {@code capacity} is + * negative + */ + @SuppressWarnings("deprecation") // superclass constructor public JsonArray(int capacity) { elements = new ArrayList<>(capacity); } @@ -171,7 +180,7 @@ public boolean contains(JsonElement element) { public int size() { return elements.size(); } - + /** * Returns true if the array is empty * diff --git a/gson/src/main/java/com/google/gson/JsonElement.java b/gson/src/main/java/com/google/gson/JsonElement.java index fb6a5f1ae3..56a8989429 100644 --- a/gson/src/main/java/com/google/gson/JsonElement.java +++ b/gson/src/main/java/com/google/gson/JsonElement.java @@ -31,6 +31,15 @@ * @author Joel Leitch */ public abstract class JsonElement { + /** + * @deprecated Creating custom {@code JsonElement} subclasses is highly discouraged + * and can lead to undefined behavior.
+ * This constructor is only kept for backward compatibility. + */ + @Deprecated + public JsonElement() { + } + /** * Returns a deep copy of this element. Immutable elements like primitives * and nulls are not copied. diff --git a/gson/src/main/java/com/google/gson/JsonNull.java b/gson/src/main/java/com/google/gson/JsonNull.java index 67cb9325b2..934dfc7de8 100644 --- a/gson/src/main/java/com/google/gson/JsonNull.java +++ b/gson/src/main/java/com/google/gson/JsonNull.java @@ -25,7 +25,7 @@ */ public final class JsonNull extends JsonElement { /** - * singleton for JsonNull + * Singleton for JsonNull * * @since 1.8 */ @@ -33,7 +33,8 @@ public final class JsonNull extends JsonElement { /** * Creates a new JsonNull object. - * Deprecated since Gson version 1.8. Use {@link #INSTANCE} instead + * + * @deprecated Deprecated since Gson version 1.8. Use {@link #INSTANCE} instead */ @Deprecated public JsonNull() { diff --git a/gson/src/main/java/com/google/gson/JsonObject.java b/gson/src/main/java/com/google/gson/JsonObject.java index 285a84290a..80ee19d38d 100644 --- a/gson/src/main/java/com/google/gson/JsonObject.java +++ b/gson/src/main/java/com/google/gson/JsonObject.java @@ -17,7 +17,6 @@ package com.google.gson; import com.google.gson.internal.LinkedTreeMap; - import java.util.Map; import java.util.Set; @@ -32,6 +31,13 @@ public final class JsonObject extends JsonElement { private final LinkedTreeMap members = new LinkedTreeMap<>(); + /** + * Creates an empty JsonObject. + */ + @SuppressWarnings("deprecation") // superclass constructor + public JsonObject() { + } + /** * Creates a deep copy of this element and all its children * @since 2.8.2 diff --git a/gson/src/main/java/com/google/gson/JsonPrimitive.java b/gson/src/main/java/com/google/gson/JsonPrimitive.java index 5e95d5a82b..c994420cff 100644 --- a/gson/src/main/java/com/google/gson/JsonPrimitive.java +++ b/gson/src/main/java/com/google/gson/JsonPrimitive.java @@ -17,11 +17,10 @@ package com.google.gson; import com.google.gson.internal.$Gson$Preconditions; +import com.google.gson.internal.LazilyParsedNumber; import java.math.BigDecimal; import java.math.BigInteger; -import com.google.gson.internal.LazilyParsedNumber; - /** * A class representing a Json primitive value. A primitive value * is either a String, a Java primitive, or a Java primitive @@ -39,6 +38,7 @@ public final class JsonPrimitive extends JsonElement { * * @param bool the value to create the primitive with. */ + @SuppressWarnings("deprecation") // superclass constructor public JsonPrimitive(Boolean bool) { value = $Gson$Preconditions.checkNotNull(bool); } @@ -48,6 +48,7 @@ public JsonPrimitive(Boolean bool) { * * @param number the value to create the primitive with. */ + @SuppressWarnings("deprecation") // superclass constructor public JsonPrimitive(Number number) { value = $Gson$Preconditions.checkNotNull(number); } @@ -57,6 +58,7 @@ public JsonPrimitive(Number number) { * * @param string the value to create the primitive with. */ + @SuppressWarnings("deprecation") // superclass constructor public JsonPrimitive(String string) { value = $Gson$Preconditions.checkNotNull(string); } @@ -67,6 +69,7 @@ public JsonPrimitive(String string) { * * @param c the value to create the primitive with. */ + @SuppressWarnings("deprecation") // superclass constructor public JsonPrimitive(Character c) { // convert characters to strings since in JSON, characters are represented as a single // character string diff --git a/gson/src/main/java/com/google/gson/internal/bind/JsonTreeReader.java b/gson/src/main/java/com/google/gson/internal/bind/JsonTreeReader.java index a753402ed1..dfa42c486b 100644 --- a/gson/src/main/java/com/google/gson/internal/bind/JsonTreeReader.java +++ b/gson/src/main/java/com/google/gson/internal/bind/JsonTreeReader.java @@ -23,11 +23,12 @@ import com.google.gson.JsonPrimitive; import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonToken; +import com.google.gson.stream.MalformedJsonException; import java.io.IOException; import java.io.Reader; +import java.util.Arrays; import java.util.Iterator; import java.util.Map; -import java.util.Arrays; /** * This reader walks the elements of a JsonElement as if it was coming from a @@ -143,7 +144,7 @@ public JsonTreeReader(JsonElement element) { } else if (o == SENTINEL_CLOSED) { throw new IllegalStateException("JsonReader is closed"); } else { - throw new AssertionError(); + throw new MalformedJsonException("Custom JsonElement subclass " + o.getClass().getName() + " is not supported"); } } diff --git a/gson/src/test/java/com/google/gson/internal/bind/JsonTreeReaderTest.java b/gson/src/test/java/com/google/gson/internal/bind/JsonTreeReaderTest.java index 1166381bc8..dd4daf05ba 100644 --- a/gson/src/test/java/com/google/gson/internal/bind/JsonTreeReaderTest.java +++ b/gson/src/test/java/com/google/gson/internal/bind/JsonTreeReaderTest.java @@ -16,9 +16,11 @@ 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.stream.JsonToken; +import com.google.gson.stream.MalformedJsonException; import java.io.IOException; import junit.framework.TestCase; @@ -54,4 +56,28 @@ public void testHasNext_endOfDocument() throws IOException { reader.endObject(); assertFalse(reader.hasNext()); } + + public void testCustomJsonElementSubclass() throws IOException { + @SuppressWarnings("deprecation") // superclass constructor + class CustomSubclass extends JsonElement { + @Override + public JsonElement deepCopy() { + return this; + } + } + + JsonArray array = new JsonArray(); + array.add(new CustomSubclass()); + + JsonTreeReader reader = new JsonTreeReader(array); + reader.beginArray(); + try { + // Should fail due to custom JsonElement subclass + reader.peek(); + fail(); + } catch (MalformedJsonException expected) { + assertEquals("Custom JsonElement subclass " + CustomSubclass.class.getName() + " is not supported", + expected.getMessage()); + } + } }