Back to Repositories

Testing Custom Serialization Inheritance Handling in google/gson

This test suite validates custom serialization functionality in Google’s GSON library, focusing on how different serializer implementations handle inheritance and type adaptation. The tests verify proper serializer invocation for base and subclass instances in various scenarios.

Test Coverage Overview

The test suite provides comprehensive coverage of custom serialization scenarios in GSON.

Key areas tested include:
  • Base class serializer behavior with base class fields
  • Subclass serializer handling for base class fields
  • Array serialization with inherited types
  • Null serialization handling

Implementation Analysis

The testing approach uses JUnit to validate GSON’s serialization behavior across inheritance hierarchies. The implementation employs custom serializers registered through GsonBuilder, demonstrating type adapter registration and JsonSerializer interface usage.

Key patterns include:
  • Type-specific serializer registration
  • Inheritance-aware serialization testing
  • JSON structure validation

Technical Details

Testing tools and configuration:
  • JUnit test framework
  • GSON library with GsonBuilder
  • Custom JsonSerializer implementations
  • Truth assertion library
  • Test helper classes (Base, Sub, BaseSerializer, SubSerializer)

Best Practices Demonstrated

The test suite exemplifies several testing best practices for serialization libraries.

Notable practices include:
  • Isolated test cases for specific serialization scenarios
  • Clear test method naming conventions
  • Proper setup of serializer hierarchies
  • Thorough assertion of JSON structure
  • Edge case handling (null serialization)

google/gson

gson/src/test/java/com/google/gson/functional/CustomSerializerTest.java

            
/*
 * Copyright (C) 2009 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.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonSerializer;
import com.google.gson.common.TestTypes.Base;
import com.google.gson.common.TestTypes.BaseSerializer;
import com.google.gson.common.TestTypes.ClassWithBaseArrayField;
import com.google.gson.common.TestTypes.ClassWithBaseField;
import com.google.gson.common.TestTypes.Sub;
import com.google.gson.common.TestTypes.SubSerializer;
import org.junit.Test;

/**
 * Functional Test exercising custom serialization only. When test applies to both serialization and
 * deserialization then add it to CustomTypeAdapterTest.
 *
 * @author Inderjeet Singh
 */
public class CustomSerializerTest {

  @Test
  public void testBaseClassSerializerInvokedForBaseClassFields() {
    Gson gson =
        new GsonBuilder()
            .registerTypeAdapter(Base.class, new BaseSerializer())
            .registerTypeAdapter(Sub.class, new SubSerializer())
            .create();
    ClassWithBaseField target = new ClassWithBaseField(new Base());
    JsonObject json = (JsonObject) gson.toJsonTree(target);
    JsonObject base = json.get("base").getAsJsonObject();
    assertThat(base.get(Base.SERIALIZER_KEY).getAsString()).isEqualTo(BaseSerializer.NAME);
  }

  @Test
  public void testSubClassSerializerInvokedForBaseClassFieldsHoldingSubClassInstances() {
    Gson gson =
        new GsonBuilder()
            .registerTypeAdapter(Base.class, new BaseSerializer())
            .registerTypeAdapter(Sub.class, new SubSerializer())
            .create();
    ClassWithBaseField target = new ClassWithBaseField(new Sub());
    JsonObject json = (JsonObject) gson.toJsonTree(target);
    JsonObject base = json.get("base").getAsJsonObject();
    assertThat(base.get(Base.SERIALIZER_KEY).getAsString()).isEqualTo(SubSerializer.NAME);
  }

  @Test
  public void testSubClassSerializerInvokedForBaseClassFieldsHoldingArrayOfSubClassInstances() {
    Gson gson =
        new GsonBuilder()
            .registerTypeAdapter(Base.class, new BaseSerializer())
            .registerTypeAdapter(Sub.class, new SubSerializer())
            .create();
    ClassWithBaseArrayField target = new ClassWithBaseArrayField(new Base[] {new Sub(), new Sub()});
    JsonObject json = (JsonObject) gson.toJsonTree(target);
    JsonArray array = json.get("base").getAsJsonArray();
    for (JsonElement element : array) {
      JsonElement serializerKey = element.getAsJsonObject().get(Base.SERIALIZER_KEY);
      assertThat(serializerKey.getAsString()).isEqualTo(SubSerializer.NAME);
    }
  }

  @Test
  public void testBaseClassSerializerInvokedForBaseClassFieldsHoldingSubClassInstances() {
    Gson gson = new GsonBuilder().registerTypeAdapter(Base.class, new BaseSerializer()).create();
    ClassWithBaseField target = new ClassWithBaseField(new Sub());
    JsonObject json = (JsonObject) gson.toJsonTree(target);
    JsonObject base = json.get("base").getAsJsonObject();
    assertThat(base.get(Base.SERIALIZER_KEY).getAsString()).isEqualTo(BaseSerializer.NAME);
  }

  @Test
  public void testSerializerReturnsNull() {
    Gson gson =
        new GsonBuilder()
            .registerTypeAdapter(
                Base.class, (JsonSerializer<Base>) (src, typeOfSrc, context) -> null)
            .create();
    JsonElement json = gson.toJsonTree(new Base());
    assertThat(json.isJsonNull()).isTrue();
  }
}