Back to Repositories

Testing InstanceCreator Type Resolution in google/gson

This test suite validates the InstanceCreator functionality in Google’s Gson library, focusing on custom deserialization scenarios and type handling. The tests verify proper instance creation for base types, subtypes, and collection types during JSON deserialization.

Test Coverage Overview

The test suite provides comprehensive coverage of InstanceCreator implementations across different scenarios.

  • Base type and subtype deserialization validation
  • Field-level instance creation testing
  • Collection type handling verification
  • Parametrized type deserialization checks

Implementation Analysis

The testing approach utilizes JUnit to verify custom deserialization behavior. Tests employ the GsonBuilder pattern to register type adapters and validate instance creation outcomes.

Key implementation patterns include:
  • Lambda-based InstanceCreator definitions
  • Type token usage for generic type handling
  • Inheritance-based test cases

Technical Details

Testing infrastructure includes:

  • JUnit test framework
  • Gson library with GsonBuilder configuration
  • Custom test types (Base, Sub, ClassWithBaseField)
  • TypeToken for generic type resolution
  • Truth assertion library for verification

Best Practices Demonstrated

The test suite exemplifies high-quality testing practices through well-structured test cases and comprehensive verification.

  • Clear test method naming conventions
  • Focused test scenarios with specific assertions
  • Proper type safety and generic handling
  • Regression test coverage

google/gson

gson/src/test/java/com/google/gson/functional/InstanceCreatorTest.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.InstanceCreator;
import com.google.gson.common.TestTypes.Base;
import com.google.gson.common.TestTypes.ClassWithBaseField;
import com.google.gson.common.TestTypes.Sub;
import com.google.gson.reflect.TypeToken;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import java.util.SortedSet;
import java.util.TreeSet;
import org.junit.Test;

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

  @Test
  public void testInstanceCreatorReturnsBaseType() {
    Gson gson =
        new GsonBuilder()
            .registerTypeAdapter(Base.class, (InstanceCreator<Base>) type -> new Base())
            .create();
    String json = "{baseName:'BaseRevised',subName:'Sub'}";
    Base base = gson.fromJson(json, Base.class);
    assertThat(base.baseName).isEqualTo("BaseRevised");
  }

  @Test
  public void testInstanceCreatorReturnsSubTypeForTopLevelObject() {
    Gson gson =
        new GsonBuilder()
            .registerTypeAdapter(Base.class, (InstanceCreator<Base>) type -> new Sub())
            .create();

    String json = "{baseName:'Base',subName:'SubRevised'}";
    Base base = gson.fromJson(json, Base.class);
    assertThat(base).isInstanceOf(Sub.class);

    Sub sub = (Sub) base;
    assertThat(sub.subName).isNotEqualTo("SubRevised");
    assertThat(sub.subName).isEqualTo(Sub.SUB_NAME);
  }

  @Test
  public void testInstanceCreatorReturnsSubTypeForField() {
    Gson gson =
        new GsonBuilder()
            .registerTypeAdapter(Base.class, (InstanceCreator<Base>) type -> new Sub())
            .create();
    String json = "{base:{baseName:'Base',subName:'SubRevised'}}";
    ClassWithBaseField target = gson.fromJson(json, ClassWithBaseField.class);
    assertThat(target.base).isInstanceOf(Sub.class);
    assertThat(((Sub) target.base).subName).isEqualTo(Sub.SUB_NAME);
  }

  // This regressed in Gson 2.0 and 2.1
  @Test
  public void testInstanceCreatorForCollectionType() {
    @SuppressWarnings("serial")
    class SubArrayList<T> extends ArrayList<T> {}
    InstanceCreator<List<String>> listCreator = type -> new SubArrayList<>();
    Type listOfStringType = new TypeToken<List<String>>() {}.getType();
    Gson gson = new GsonBuilder().registerTypeAdapter(listOfStringType, listCreator).create();
    List<String> list = gson.fromJson("[\"a\"]", listOfStringType);
    assertThat(list.getClass()).isEqualTo(SubArrayList.class);
  }

  @SuppressWarnings("unchecked")
  @Test
  public void testInstanceCreatorForParametrizedType() {
    @SuppressWarnings("serial")
    class SubTreeSet<T> extends TreeSet<T> {}
    InstanceCreator<SortedSet<?>> sortedSetCreator = type -> new SubTreeSet<>();
    Gson gson = new GsonBuilder().registerTypeAdapter(SortedSet.class, sortedSetCreator).create();

    Type sortedSetType = new TypeToken<SortedSet<String>>() {}.getType();
    SortedSet<String> set = gson.fromJson("[\"a\"]", sortedSetType);
    assertThat(set.first()).isEqualTo("a");
    assertThat(set.getClass()).isEqualTo(SubTreeSet.class);

    set = gson.fromJson("[\"b\"]", SortedSet.class);
    assertThat(set.first()).isEqualTo("b");
    assertThat(set.getClass()).isEqualTo(SubTreeSet.class);
  }
}