Testing GSON Object Serialization and Deserialization Workflows in google/gson
This test suite validates core JSON serialization and deserialization functionality in the Google GSON library. It covers basic object mapping, primitive handling, nested objects, arrays, and edge cases to ensure robust JSON processing.
Test Coverage Overview
Implementation Analysis
Technical Details
Best Practices Demonstrated
google/gson
gson/src/test/java/com/google/gson/functional/ObjectTest.java
/*
* Copyright (C) 2008 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.functional;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertThrows;
import com.google.gson.ExclusionStrategy;
import com.google.gson.FieldAttributes;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.InstanceCreator;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonIOException;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSerializer;
import com.google.gson.JsonSyntaxException;
import com.google.gson.common.TestTypes.ArrayOfObjects;
import com.google.gson.common.TestTypes.BagOfPrimitiveWrappers;
import com.google.gson.common.TestTypes.BagOfPrimitives;
import com.google.gson.common.TestTypes.ClassWithArray;
import com.google.gson.common.TestTypes.ClassWithNoFields;
import com.google.gson.common.TestTypes.ClassWithObjects;
import com.google.gson.common.TestTypes.ClassWithTransientFields;
import com.google.gson.common.TestTypes.Nested;
import com.google.gson.common.TestTypes.PrimitiveArray;
import com.google.gson.reflect.TypeToken;
import com.google.gson.stream.MalformedJsonException;
import java.io.EOFException;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.TimeZone;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
/**
* Functional tests for Json serialization and deserialization of regular classes.
*
* @author Inderjeet Singh
* @author Joel Leitch
*/
public class ObjectTest {
private Gson gson;
private TimeZone oldTimeZone;
private Locale oldLocale;
@Before
public void setUp() throws Exception {
gson = new Gson();
oldTimeZone = TimeZone.getDefault();
TimeZone.setDefault(TimeZone.getTimeZone("America/Los_Angeles"));
oldLocale = Locale.getDefault();
Locale.setDefault(Locale.US);
}
@After
public void tearDown() {
TimeZone.setDefault(oldTimeZone);
Locale.setDefault(oldLocale);
}
@Test
public void testJsonInSingleQuotesDeserialization() {
String json = "{'stringValue':'no message','intValue':10,'longValue':20}";
BagOfPrimitives target = gson.fromJson(json, BagOfPrimitives.class);
assertThat(target.stringValue).isEqualTo("no message");
assertThat(target.intValue).isEqualTo(10);
assertThat(target.longValue).isEqualTo(20);
}
@Test
public void testJsonInMixedQuotesDeserialization() {
String json = "{\"stringValue\":'no message','intValue':10,'longValue':20}";
BagOfPrimitives target = gson.fromJson(json, BagOfPrimitives.class);
assertThat(target.stringValue).isEqualTo("no message");
assertThat(target.intValue).isEqualTo(10);
assertThat(target.longValue).isEqualTo(20);
}
@Test
public void testBagOfPrimitivesSerialization() {
BagOfPrimitives target = new BagOfPrimitives(10, 20, false, "stringValue");
assertThat(gson.toJson(target)).isEqualTo(target.getExpectedJson());
}
@Test
public void testBagOfPrimitivesDeserialization() {
BagOfPrimitives src = new BagOfPrimitives(10, 20, false, "stringValue");
String json = src.getExpectedJson();
BagOfPrimitives target = gson.fromJson(json, BagOfPrimitives.class);
assertThat(target.getExpectedJson()).isEqualTo(json);
}
@Test
public void testBagOfPrimitiveWrappersSerialization() {
BagOfPrimitiveWrappers target = new BagOfPrimitiveWrappers(10L, 20, false);
assertThat(gson.toJson(target)).isEqualTo(target.getExpectedJson());
}
@Test
public void testBagOfPrimitiveWrappersDeserialization() {
BagOfPrimitiveWrappers target = new BagOfPrimitiveWrappers(10L, 20, false);
String jsonString = target.getExpectedJson();
target = gson.fromJson(jsonString, BagOfPrimitiveWrappers.class);
assertThat(target.getExpectedJson()).isEqualTo(jsonString);
}
@Test
public void testClassWithTransientFieldsSerialization() {
ClassWithTransientFields<Long> target = new ClassWithTransientFields<>(1L);
assertThat(gson.toJson(target)).isEqualTo(target.getExpectedJson());
}
@Test
public void testClassWithTransientFieldsDeserialization() {
String json = "{\"longValue\":[1]}";
ClassWithTransientFields<?> target = gson.fromJson(json, ClassWithTransientFields.class);
assertThat(target.getExpectedJson()).isEqualTo(json);
}
@Test
public void testClassWithTransientFieldsDeserializationTransientFieldsPassedInJsonAreIgnored() {
String json = "{\"transientLongValue\":5,\"longValue\":[1]}";
ClassWithTransientFields<?> target = gson.fromJson(json, ClassWithTransientFields.class);
assertThat(target.transientLongValue).isEqualTo(1);
}
@Test
public void testClassWithNoFieldsSerialization() {
assertThat(gson.toJson(new ClassWithNoFields())).isEqualTo("{}");
}
@Test
public void testClassWithNoFieldsDeserialization() {
String json = "{}";
ClassWithNoFields target = gson.fromJson(json, ClassWithNoFields.class);
ClassWithNoFields expected = new ClassWithNoFields();
assertThat(target).isEqualTo(expected);
}
private static class Subclass extends Superclass1 {}
private static class Superclass1 extends Superclass2 {
@SuppressWarnings({"unused", "HidingField"})
String s;
}
private static class Superclass2 {
@SuppressWarnings("unused")
String s;
}
@Test
public void testClassWithDuplicateFields() {
String expectedMessage =
"Class com.google.gson.functional.ObjectTest$Subclass declares multiple JSON fields named"
+ " 's'; conflict is caused by fields"
+ " com.google.gson.functional.ObjectTest$Superclass1#s and"
+ " com.google.gson.functional.ObjectTest$Superclass2#s\n"
+ "See https://github.com/google/gson/blob/main/Troubleshooting.md#duplicate-fields";
var e = assertThrows(IllegalArgumentException.class, () -> gson.getAdapter(Subclass.class));
assertThat(e).hasMessageThat().isEqualTo(expectedMessage);
// Detection should also work properly when duplicate fields exist only for serialization
Gson gson =
new GsonBuilder()
.addDeserializationExclusionStrategy(
new ExclusionStrategy() {
@Override
public boolean shouldSkipField(FieldAttributes f) {
// Skip all fields for deserialization
return true;
}
@Override
public boolean shouldSkipClass(Class<?> clazz) {
return false;
}
})
.create();
e = assertThrows(IllegalArgumentException.class, () -> gson.getAdapter(Subclass.class));
assertThat(e).hasMessageThat().isEqualTo(expectedMessage);
}
@Test
public void testNestedSerialization() {
Nested target =
new Nested(
new BagOfPrimitives(10, 20, false, "stringValue"),
new BagOfPrimitives(30, 40, true, "stringValue"));
assertThat(gson.toJson(target)).isEqualTo(target.getExpectedJson());
}
@Test
public void testNestedDeserialization() {
String json =
"{\"primitive1\":{\"longValue\":10,\"intValue\":20,\"booleanValue\":false,"
+ "\"stringValue\":\"stringValue\"},\"primitive2\":{\"longValue\":30,\"intValue\":40,"
+ "\"booleanValue\":true,\"stringValue\":\"stringValue\"}}";
Nested target = gson.fromJson(json, Nested.class);
assertThat(target.getExpectedJson()).isEqualTo(json);
}
@Test
public void testNullSerialization() {
assertThat(gson.toJson(null)).isEqualTo("null");
}
@Test
public void testEmptyStringDeserialization() {
Object object = gson.fromJson("", Object.class);
assertThat(object).isNull();
}
@Test
public void testTruncatedDeserialization() {
Type type = new TypeToken<List<String>>() {}.getType();
var e = assertThrows(JsonParseException.class, () -> gson.fromJson("[\"a\", \"b\",", type));
assertThat(e).hasCauseThat().isInstanceOf(EOFException.class);
}
@Test
public void testNullDeserialization() {
String myNullObject = null;
Object object = gson.fromJson(myNullObject, Object.class);
assertThat(object).isNull();
}
@Test
public void testNullFieldsSerialization() {
Nested target = new Nested(new BagOfPrimitives(10, 20, false, "stringValue"), null);
assertThat(gson.toJson(target)).isEqualTo(target.getExpectedJson());
}
@Test
public void testNullFieldsDeserialization() {
String json =
"{\"primitive1\":{\"longValue\":10,\"intValue\":20,\"booleanValue\":false"
+ ",\"stringValue\":\"stringValue\"}}";
Nested target = gson.fromJson(json, Nested.class);
assertThat(target.getExpectedJson()).isEqualTo(json);
}
@Test
public void testArrayOfObjectsSerialization() {
ArrayOfObjects target = new ArrayOfObjects();
assertThat(gson.toJson(target)).isEqualTo(target.getExpectedJson());
}
@Test
public void testArrayOfObjectsDeserialization() {
String json = new ArrayOfObjects().getExpectedJson();
ArrayOfObjects target = gson.fromJson(json, ArrayOfObjects.class);
assertThat(target.getExpectedJson()).isEqualTo(json);
}
@Test
public void testArrayOfArraysSerialization() {
ArrayOfArrays target = new ArrayOfArrays();
assertThat(gson.toJson(target)).isEqualTo(target.getExpectedJson());
}
@Test
public void testArrayOfArraysDeserialization() {
String json = new ArrayOfArrays().getExpectedJson();
ArrayOfArrays target = gson.fromJson(json, ArrayOfArrays.class);
assertThat(target.getExpectedJson()).isEqualTo(json);
}
@Test
public void testArrayOfObjectsAsFields() {
ClassWithObjects classWithObjects = new ClassWithObjects();
BagOfPrimitives bagOfPrimitives = new BagOfPrimitives();
String stringValue = "someStringValueInArray";
String classWithObjectsJson = gson.toJson(classWithObjects);
String bagOfPrimitivesJson = gson.toJson(bagOfPrimitives);
ClassWithArray classWithArray =
new ClassWithArray(new Object[] {stringValue, classWithObjects, bagOfPrimitives});
String json = gson.toJson(classWithArray);
assertThat(json).contains(classWithObjectsJson);
assertThat(json).contains(bagOfPrimitivesJson);
assertThat(json).contains("\"" + stringValue + "\"");
}
/** Created in response to Issue 14: http://code.google.com/p/google-gson/issues/detail?id=14 */
@Test
public void testNullArraysDeserialization() {
String json = "{\"array\": null}";
ClassWithArray target = gson.fromJson(json, ClassWithArray.class);
assertThat(target.array).isNull();
}
/** Created in response to Issue 14: http://code.google.com/p/google-gson/issues/detail?id=14 */
@Test
public void testNullObjectFieldsDeserialization() {
String json = "{\"bag\": null}";
ClassWithObjects target = gson.fromJson(json, ClassWithObjects.class);
assertThat(target.bag).isNull();
}
@Test
public void testEmptyCollectionInAnObjectDeserialization() {
String json = "{\"children\":[]}";
ClassWithCollectionField target = gson.fromJson(json, ClassWithCollectionField.class);
assertThat(target).isNotNull();
assertThat(target.children).isEmpty();
}
private static class ClassWithCollectionField {
Collection<String> children = new ArrayList<>();
}
@Test
public void testPrimitiveArrayInAnObjectDeserialization() {
String json = "{\"longArray\":[0,1,2,3,4,5,6,7,8,9]}";
PrimitiveArray target = gson.fromJson(json, PrimitiveArray.class);
assertThat(target.getExpectedJson()).isEqualTo(json);
}
/** Created in response to Issue 14: http://code.google.com/p/google-gson/issues/detail?id=14 */
@Test
public void testNullPrimitiveFieldsDeserialization() {
String json = "{\"longValue\":null}";
BagOfPrimitives target = gson.fromJson(json, BagOfPrimitives.class);
assertThat(target.longValue).isEqualTo(BagOfPrimitives.DEFAULT_VALUE);
}
@Test
public void testEmptyCollectionInAnObjectSerialization() {
ClassWithCollectionField target = new ClassWithCollectionField();
assertThat(gson.toJson(target)).isEqualTo("{\"children\":[]}");
}
@Test
public void testPrivateNoArgConstructorDeserialization() {
ClassWithPrivateNoArgsConstructor target =
gson.fromJson("{\"a\":20}", ClassWithPrivateNoArgsConstructor.class);
assertThat(target.a).isEqualTo(20);
}
@Test
public void testAnonymousLocalClassesSerialization() {
assertThat(
gson.toJson(
new ClassWithNoFields() {
// empty anonymous class
}))
.isEqualTo("null");
class Local {}
assertThat(gson.toJson(new Local())).isEqualTo("null");
}
@Test
public void testAnonymousLocalClassesCustomSerialization() {
Gson gson =
new GsonBuilder()
.registerTypeHierarchyAdapter(
ClassWithNoFields.class,
(JsonSerializer<ClassWithNoFields>)
(src, typeOfSrc, context) -> new JsonPrimitive("custom-value"))
.create();
assertThat(
gson.toJson(
new ClassWithNoFields() {
// empty anonymous class
}))
.isEqualTo("\"custom-value\"");
class Local {}
gson =
new GsonBuilder()
.registerTypeAdapter(
Local.class,
(JsonSerializer<Local>)
(src, typeOfSrc, context) -> new JsonPrimitive("custom-value"))
.create();
assertThat(gson.toJson(new Local())).isEqualTo("\"custom-value\"");
}
@Test
public void testAnonymousLocalClassesCustomDeserialization() {
Gson gson =
new GsonBuilder()
.registerTypeHierarchyAdapter(
ClassWithNoFields.class,
(JsonDeserializer<ClassWithNoFields>)
(json, typeOfT, context) -> new ClassWithNoFields())
.create();
assertThat(gson.fromJson("{}", ClassWithNoFields.class)).isNotNull();
Class<?> anonymousClass = new ClassWithNoFields() {}.getClass();
// Custom deserializer is ignored
assertThat(gson.fromJson("{}", anonymousClass)).isNull();
class Local {}
gson =
new GsonBuilder()
.registerTypeAdapter(
Local.class,
(JsonDeserializer<Local>)
(json, typeOfT, context) -> {
throw new AssertionError("should not be called");
})
.create();
// Custom deserializer is ignored
assertThat(gson.fromJson("{}", Local.class)).isNull();
}
@Test
public void testPrimitiveArrayFieldSerialization() {
PrimitiveArray target = new PrimitiveArray(new long[] {1L, 2L, 3L});
assertThat(gson.toJson(target)).isEqualTo(target.getExpectedJson());
}
/** Tests that a class field with type Object can be serialized properly. See issue 54 */
@Test
public void testClassWithObjectFieldSerialization() {
ClassWithObjectField obj = new ClassWithObjectField();
obj.member = "abc";
String json = gson.toJson(obj);
assertThat(json).contains("abc");
}
private static class ClassWithObjectField {
@SuppressWarnings("unused")
Object member;
}
@Test
public void testInnerClassSerialization() {
Parent p = new Parent();
Parent.Child c = p.new Child();
String json = gson.toJson(c);
assertThat(json).contains("value2");
assertThat(json).doesNotContain("value1");
}
@Test
public void testInnerClassDeserialization() {
Parent p = new Parent();
Gson gson =
new GsonBuilder()
.registerTypeAdapter(
Parent.Child.class,
new InstanceCreator<Parent.Child>() {
@Override
public Parent.Child createInstance(Type type) {
return p.new Child();
}
})
.create();
String json = "{'value2':3}";
Parent.Child c = gson.fromJson(json, Parent.Child.class);
assertThat(c.value2).isEqualTo(3);
}
private static class Parent {
@SuppressWarnings("unused")
int value1 = 1;
@SuppressWarnings("ClassCanBeStatic")
private class Child {
int value2 = 2;
}
}
private static class ArrayOfArrays {
private final BagOfPrimitives[][] elements;
public ArrayOfArrays() {
elements = new BagOfPrimitives[3][2];
for (int i = 0; i < elements.length; ++i) {
BagOfPrimitives[] row = elements[i];
for (int j = 0; j < row.length; ++j) {
row[j] = new BagOfPrimitives(i + j, i * j, false, i + "_" + j);
}
}
}
public String getExpectedJson() {
StringBuilder sb = new StringBuilder("{\"elements\":[");
boolean first = true;
for (BagOfPrimitives[] row : elements) {
if (first) {
first = false;
} else {
sb.append(",");
}
boolean firstOfRow = true;
sb.append("[");
for (BagOfPrimitives element : row) {
if (firstOfRow) {
firstOfRow = false;
} else {
sb.append(",");
}
sb.append(element.getExpectedJson());
}
sb.append("]");
}
sb.append("]}");
return sb.toString();
}
}
private static class ClassWithPrivateNoArgsConstructor {
public int a;
private ClassWithPrivateNoArgsConstructor() {
a = 10;
}
}
/** In response to Issue 41 http://code.google.com/p/google-gson/issues/detail?id=41 */
@Test
public void testObjectFieldNamesWithoutQuotesDeserialization() {
String json = "{longValue:1,'booleanValue':true,\"stringValue\":'bar'}";
BagOfPrimitives bag = gson.fromJson(json, BagOfPrimitives.class);
assertThat(bag.longValue).isEqualTo(1);
assertThat(bag.booleanValue).isTrue();
assertThat(bag.stringValue).isEqualTo("bar");
}
@Test
public void testStringFieldWithNumberValueDeserialization() {
String json = "{\"stringValue\":1}";
BagOfPrimitives bag = gson.fromJson(json, BagOfPrimitives.class);
assertThat(bag.stringValue).isEqualTo("1");
json = "{\"stringValue\":1.5E+6}";
bag = gson.fromJson(json, BagOfPrimitives.class);
assertThat(bag.stringValue).isEqualTo("1.5E+6");
json = "{\"stringValue\":true}";
bag = gson.fromJson(json, BagOfPrimitives.class);
assertThat(bag.stringValue).isEqualTo("true");
}
/** Created to reproduce issue 140 */
@Test
public void testStringFieldWithEmptyValueSerialization() {
ClassWithEmptyStringFields target = new ClassWithEmptyStringFields();
target.a = "5794749";
String json = gson.toJson(target);
assertThat(json).contains("\"a\":\"5794749\"");
assertThat(json).contains("\"b\":\"\"");
assertThat(json).contains("\"c\":\"\"");
}
/** Created to reproduce issue 140 */
@Test
public void testStringFieldWithEmptyValueDeserialization() {
String json = "{a:\"5794749\",b:\"\",c:\"\"}";
ClassWithEmptyStringFields target = gson.fromJson(json, ClassWithEmptyStringFields.class);
assertThat(target.a).isEqualTo("5794749");
assertThat(target.b).isEqualTo("");
assertThat(target.c).isEqualTo("");
}
private static class ClassWithEmptyStringFields {
String a = "";
String b = "";
String c = "";
}
@Test
public void testJsonObjectSerialization() {
Gson gson = new GsonBuilder().serializeNulls().create();
JsonObject obj = new JsonObject();
String json = gson.toJson(obj);
assertThat(json).isEqualTo("{}");
}
/** Test for issue 215. */
@Test
public void testSingletonLists() {
Gson gson = new Gson();
Product product = new Product();
assertThat(gson.toJson(product)).isEqualTo("{\"attributes\":[],\"departments\":[]}");
Product deserialized = gson.fromJson(gson.toJson(product), Product.class);
assertThat(deserialized.attributes).isEmpty();
assertThat(deserialized.departments).isEmpty();
product.departments.add(new Department());
assertThat(gson.toJson(product))
.isEqualTo("{\"attributes\":[],\"departments\":[{\"name\":\"abc\",\"code\":\"123\"}]}");
deserialized = gson.fromJson(gson.toJson(product), Product.class);
assertThat(deserialized.attributes).isEmpty();
assertThat(deserialized.departments).hasSize(1);
product.attributes.add("456");
assertThat(gson.toJson(product))
.isEqualTo(
"{\"attributes\":[\"456\"],\"departments\":[{\"name\":\"abc\",\"code\":\"123\"}]}");
deserialized = gson.fromJson(gson.toJson(product), Product.class);
assertThat(deserialized.attributes).containsExactly("456");
assertThat(deserialized.departments).hasSize(1);
}
static final class Department {
public String name = "abc";
public String code = "123";
}
static final class Product {
private List<String> attributes = new ArrayList<>();
private List<Department> departments = new ArrayList<>();
}
// http://code.google.com/p/google-gson/issues/detail?id=270
@Test
@SuppressWarnings("JavaUtilDate")
public void testDateAsMapObjectField() {
HasObjectMap a = new HasObjectMap();
a.map.put("date", new Date(0));
assertThat(gson.toJson(a))
.matches("\\{\"map\":\\{\"date\":\"Dec 31, 1969,? 4:00:00\\hPM\"\\}\\}");
}
static class HasObjectMap {
Map<String, Object> map = new HashMap<>();
}
/**
* Tests serialization of a class with {@code static} field.
*
* <p>Important: It is not documented that this is officially supported; this test just checks the
* current behavior.
*/
@Test
public void testStaticFieldSerialization() {
// By default Gson should ignore static fields
assertThat(gson.toJson(new ClassWithStaticField())).isEqualTo("{}");
Gson gson =
new GsonBuilder()
// Include static fields
.excludeFieldsWithModifiers(0)
.create();
String json = gson.toJson(new ClassWithStaticField());
assertThat(json).isEqualTo("{\"s\":\"initial\"}");
json = gson.toJson(new ClassWithStaticFinalField());
assertThat(json).isEqualTo("{\"s\":\"initial\"}");
}
/**
* Tests deserialization of a class with {@code static} field.
*
* <p>Important: It is not documented that this is officially supported; this test just checks the
* current behavior.
*/
@Test
public void testStaticFieldDeserialization() {
// By default Gson should ignore static fields
ClassWithStaticField deserialized =
gson.fromJson("{\"s\":\"custom\"}", ClassWithStaticField.class);
assertThat(deserialized).isNotNull();
assertThat(ClassWithStaticField.s).isEqualTo("initial");
Gson gson =
new GsonBuilder()
// Include static fields
.excludeFieldsWithModifiers(0)
.create();
String oldValue = ClassWithStaticField.s;
try {
ClassWithStaticField obj = gson.fromJson("{\"s\":\"custom\"}", ClassWithStaticField.class);
assertThat(obj).isNotNull();
assertThat(ClassWithStaticField.s).isEqualTo("custom");
} finally {
ClassWithStaticField.s = oldValue;
}
var e =
assertThrows(
JsonIOException.class,
() -> gson.fromJson("{\"s\":\"custom\"}", ClassWithStaticFinalField.class));
assertThat(e)
.hasMessageThat()
.isEqualTo(
"Cannot set value of 'static final' field"
+ " 'com.google.gson.functional.ObjectTest$ClassWithStaticFinalField#s'");
}
@SuppressWarnings({"PrivateConstructorForUtilityClass", "NonFinalStaticField"})
static class ClassWithStaticField {
static String s = "initial";
}
@SuppressWarnings("PrivateConstructorForUtilityClass")
static class ClassWithStaticFinalField {
static final String s = "initial";
}
@Test
public void testThrowingDefaultConstructor() {
// TODO: Adjust this once Gson throws more specific exception type
var e =
assertThrows(
RuntimeException.class, () -> gson.fromJson("{}", ClassWithThrowingConstructor.class));
assertThat(e)
.hasMessageThat()
.isEqualTo(
"Failed to invoke constructor"
+ " 'com.google.gson.functional.ObjectTest$ClassWithThrowingConstructor()' with"
+ " no args");
assertThat(e).hasCauseThat().isSameInstanceAs(ClassWithThrowingConstructor.thrownException);
}
static class ClassWithThrowingConstructor {
@SuppressWarnings("StaticAssignmentOfThrowable")
static final RuntimeException thrownException = new RuntimeException("Custom exception");
public ClassWithThrowingConstructor() {
throw thrownException;
}
}
@Test
public void testDeeplyNested() {
int defaultLimit = 255;
// json = {"r":{"r": ... {"r":null} ... }}
String json = "{\"r\":".repeat(defaultLimit) + "null" + "}".repeat(defaultLimit);
RecursiveClass deserialized = gson.fromJson(json, RecursiveClass.class);
assertThat(deserialized).isNotNull();
assertThat(deserialized.r).isNotNull();
// json = {"r":{"r": ... {"r":null} ... }}
String json2 = "{\"r\":".repeat(defaultLimit + 1) + "null" + "}".repeat(defaultLimit + 1);
JsonSyntaxException e =
assertThrows(JsonSyntaxException.class, () -> gson.fromJson(json2, RecursiveClass.class));
assertThat(e).hasCauseThat().isInstanceOf(MalformedJsonException.class);
assertThat(e)
.hasCauseThat()
.hasMessageThat()
.isEqualTo(
"Nesting limit 255 reached at line 1 column 1277 path $" + ".r".repeat(defaultLimit));
}
private static class RecursiveClass {
RecursiveClass r;
}
}