Back to Repositories

Testing Null Object and Field Handling in GSON Library

This test suite validates GSON’s handling of null objects and fields during JSON serialization and deserialization. It covers various scenarios including null primitives, collections, custom serializers, and field initialization behaviors.

Test Coverage Overview

The test suite provides comprehensive coverage of null handling in GSON, including:
  • Top-level null object serialization/deserialization
  • Explicit null handling for primitives, arrays, and collections
  • Custom serialization of null values
  • Field initialization and default values
  • Edge cases with wrapped primitives and absent JSON elements

Implementation Analysis

The testing approach uses JUnit to systematically verify GSON’s null handling capabilities.
  • Uses GsonBuilder configuration for null serialization control
  • Implements custom serializers to test null handling extensibility
  • Validates both serialization and deserialization paths
  • Tests interaction with primitive and object types

Technical Details

Testing infrastructure includes:
  • JUnit 4 test framework
  • GSON builder configuration with serializeNulls()
  • Custom type adapters and serializers
  • Test classes with various field types and initialization patterns
  • Truth assertion library for verification

Best Practices Demonstrated

The test suite exemplifies high-quality testing practices:
  • Comprehensive edge case coverage
  • Clear test method naming and organization
  • Proper test setup and initialization
  • Verification of both positive and negative cases
  • Systematic testing of API behaviors

google/gson

gson/src/test/java/com/google/gson/functional/NullObjectAndFieldTest.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 com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonNull;
import com.google.gson.JsonObject;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;
import com.google.gson.common.TestTypes.BagOfPrimitives;
import com.google.gson.common.TestTypes.ClassWithObjects;
import java.lang.reflect.Type;
import java.util.Collection;
import org.junit.Before;
import org.junit.Test;

/**
 * Functional tests for the different cases for serializing (or ignoring) null fields and object.
 *
 * @author Inderjeet Singh
 * @author Joel Leitch
 */
public class NullObjectAndFieldTest {
  private GsonBuilder gsonBuilder;

  @Before
  public void setUp() throws Exception {
    gsonBuilder = new GsonBuilder().serializeNulls();
  }

  @Test
  public void testTopLevelNullObjectSerialization() {
    Gson gson = gsonBuilder.create();
    String actual = gson.toJson(null);
    assertThat(actual).isEqualTo("null");

    actual = gson.toJson(null, String.class);
    assertThat(actual).isEqualTo("null");
  }

  @Test
  public void testTopLevelNullObjectDeserialization() {
    Gson gson = gsonBuilder.create();
    String actual = gson.fromJson("null", String.class);
    assertThat(actual).isNull();
  }

  @Test
  public void testExplicitSerializationOfNulls() {
    Gson gson = gsonBuilder.create();
    ClassWithObjects target = new ClassWithObjects(null);
    String actual = gson.toJson(target);
    String expected = "{\"bag\":null}";
    assertThat(actual).isEqualTo(expected);
  }

  @Test
  public void testExplicitDeserializationOfNulls() {
    Gson gson = gsonBuilder.create();
    ClassWithObjects target = gson.fromJson("{\"bag\":null}", ClassWithObjects.class);
    assertThat(target.bag).isNull();
  }

  @Test
  public void testExplicitSerializationOfNullArrayMembers() {
    Gson gson = gsonBuilder.create();
    ClassWithMembers target = new ClassWithMembers();
    String json = gson.toJson(target);
    assertThat(json).contains("\"array\":null");
  }

  /** Added to verify http://code.google.com/p/google-gson/issues/detail?id=68 */
  @Test
  public void testNullWrappedPrimitiveMemberSerialization() {
    Gson gson = gsonBuilder.serializeNulls().create();
    ClassWithNullWrappedPrimitive target = new ClassWithNullWrappedPrimitive();
    String json = gson.toJson(target);
    assertThat(json).contains("\"value\":null");
  }

  /** Added to verify http://code.google.com/p/google-gson/issues/detail?id=68 */
  @Test
  public void testNullWrappedPrimitiveMemberDeserialization() {
    Gson gson = gsonBuilder.create();
    String json = "{'value':null}";
    ClassWithNullWrappedPrimitive target = gson.fromJson(json, ClassWithNullWrappedPrimitive.class);
    assertThat(target.value).isNull();
  }

  @Test
  public void testExplicitSerializationOfNullCollectionMembers() {
    Gson gson = gsonBuilder.create();
    ClassWithMembers target = new ClassWithMembers();
    String json = gson.toJson(target);
    assertThat(json).contains("\"col\":null");
  }

  @Test
  public void testExplicitSerializationOfNullStringMembers() {
    Gson gson = gsonBuilder.create();
    ClassWithMembers target = new ClassWithMembers();
    String json = gson.toJson(target);
    assertThat(json).contains("\"str\":null");
  }

  @Test
  public void testCustomSerializationOfNulls() {
    gsonBuilder.registerTypeAdapter(ClassWithObjects.class, new ClassWithObjectsSerializer());
    Gson gson = gsonBuilder.create();
    ClassWithObjects target = new ClassWithObjects(new BagOfPrimitives());
    String actual = gson.toJson(target);
    String expected = "{\"bag\":null}";
    assertThat(actual).isEqualTo(expected);
  }

  @Test
  public void testPrintPrintingObjectWithNulls() {
    gsonBuilder = new GsonBuilder();
    Gson gson = gsonBuilder.create();
    String result = gson.toJson(new ClassWithMembers());
    assertThat(result).isEqualTo("{}");

    gson = gsonBuilder.serializeNulls().create();
    result = gson.toJson(new ClassWithMembers());
    assertThat(result).contains("\"str\":null");
  }

  @Test
  public void testPrintPrintingArraysWithNulls() {
    gsonBuilder = new GsonBuilder();
    Gson gson = gsonBuilder.create();
    String result = gson.toJson(new String[] {"1", null, "3"});
    assertThat(result).isEqualTo("[\"1\",null,\"3\"]");

    gson = gsonBuilder.serializeNulls().create();
    result = gson.toJson(new String[] {"1", null, "3"});
    assertThat(result).isEqualTo("[\"1\",null,\"3\"]");
  }

  // test for issue 389
  @Test
  public void testAbsentJsonElementsAreSetToNull() {
    Gson gson = new Gson();
    ClassWithInitializedMembers target =
        gson.fromJson("{array:[1,2,3]}", ClassWithInitializedMembers.class);
    assertThat(target.array).hasLength(3);
    assertThat(target.array[1]).isEqualTo(2);
    assertThat(target.str1).isEqualTo(ClassWithInitializedMembers.MY_STRING_DEFAULT);
    assertThat(target.str2).isNull();
    assertThat(target.int1).isEqualTo(ClassWithInitializedMembers.MY_INT_DEFAULT);
    // test the default value of a primitive int field per JVM spec
    assertThat(target.int2).isEqualTo(0);
    assertThat(target.bool1).isEqualTo(ClassWithInitializedMembers.MY_BOOLEAN_DEFAULT);
    // test the default value of a primitive boolean field per JVM spec
    assertThat(target.bool2).isFalse();
  }

  public static class ClassWithInitializedMembers {
    // Using a mix of no-args constructor and field initializers
    // Also, some fields are initialized and some are not (so initialized per JVM spec)
    public static final String MY_STRING_DEFAULT = "string";
    private static final int MY_INT_DEFAULT = 2;
    private static final boolean MY_BOOLEAN_DEFAULT = true;
    int[] array;
    String str1;
    String str2;
    int int1 = MY_INT_DEFAULT;
    int int2;
    boolean bool1 = MY_BOOLEAN_DEFAULT;
    boolean bool2;

    public ClassWithInitializedMembers() {
      str1 = MY_STRING_DEFAULT;
    }
  }

  private static class ClassWithNullWrappedPrimitive {
    private Long value;
  }

  @SuppressWarnings("unused")
  private static class ClassWithMembers {
    String str;
    int[] array;
    Collection<String> col;
  }

  private static class ClassWithObjectsSerializer implements JsonSerializer<ClassWithObjects> {
    @Override
    public JsonElement serialize(
        ClassWithObjects src, Type typeOfSrc, JsonSerializationContext context) {
      JsonObject obj = new JsonObject();
      obj.add("bag", JsonNull.INSTANCE);
      return obj;
    }
  }

  @Test
  public void testExplicitNullSetsFieldToNullDuringDeserialization() {
    Gson gson = new Gson();
    String json = "{value:null}";
    ObjectWithField obj = gson.fromJson(json, ObjectWithField.class);
    assertThat(obj.value).isNull();
  }

  @Test
  public void testCustomTypeAdapterPassesNullSerialization() {
    Gson gson =
        new GsonBuilder()
            .registerTypeAdapter(
                ObjectWithField.class,
                (JsonSerializer<ObjectWithField>)
                    (src, typeOfSrc, context) -> context.serialize(null))
            .create();
    ObjectWithField target = new ObjectWithField();
    target.value = "value1";
    String json = gson.toJson(target);
    assertThat(json).doesNotContain("value1");
  }

  @Test
  public void testCustomTypeAdapterPassesNullDeserialization() {
    Gson gson =
        new GsonBuilder()
            .registerTypeAdapter(
                ObjectWithField.class,
                (JsonDeserializer<ObjectWithField>)
                    (json, type, context) -> context.deserialize(null, type))
            .create();
    String json = "{value:'value1'}";
    ObjectWithField target = gson.fromJson(json, ObjectWithField.class);
    assertThat(target).isNull();
  }

  private static class ObjectWithField {
    String value = "";
  }
}