| /* |
| * 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 com.google.gson.Gson; |
| import com.google.gson.GsonBuilder; |
| import com.google.gson.ParameterizedTypeFixtures.MyParameterizedType; |
| import com.google.gson.ParameterizedTypeFixtures.MyParameterizedTypeAdapter; |
| import com.google.gson.ParameterizedTypeFixtures.MyParameterizedTypeInstanceCreator; |
| import com.google.gson.common.TestTypes.BagOfPrimitives; |
| import com.google.gson.reflect.TypeToken; |
| import java.io.Reader; |
| import java.io.Serializable; |
| import java.io.StringReader; |
| import java.io.StringWriter; |
| import java.io.Writer; |
| import java.lang.reflect.Type; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.List; |
| import junit.framework.TestCase; |
| |
| /** |
| * Functional tests for the serialization and deserialization of parameterized types in Gson. |
| * |
| * @author Inderjeet Singh |
| * @author Joel Leitch |
| */ |
| public class ParameterizedTypesTest extends TestCase { |
| private Gson gson; |
| |
| @Override |
| protected void setUp() throws Exception { |
| super.setUp(); |
| gson = new Gson(); |
| } |
| |
| public void testParameterizedTypesSerialization() throws Exception { |
| MyParameterizedType<Integer> src = new MyParameterizedType<>(10); |
| Type typeOfSrc = new TypeToken<MyParameterizedType<Integer>>() {}.getType(); |
| String json = gson.toJson(src, typeOfSrc); |
| assertEquals(src.getExpectedJson(), json); |
| } |
| |
| public void testParameterizedTypeDeserialization() throws Exception { |
| BagOfPrimitives bag = new BagOfPrimitives(); |
| MyParameterizedType<BagOfPrimitives> expected = new MyParameterizedType<>(bag); |
| Type expectedType = new TypeToken<MyParameterizedType<BagOfPrimitives>>() {}.getType(); |
| BagOfPrimitives bagDefaultInstance = new BagOfPrimitives(); |
| Gson gson = new GsonBuilder().registerTypeAdapter( |
| expectedType, new MyParameterizedTypeInstanceCreator<>(bagDefaultInstance)) |
| .create(); |
| |
| String json = expected.getExpectedJson(); |
| MyParameterizedType<BagOfPrimitives> actual = gson.fromJson(json, expectedType); |
| assertEquals(expected, actual); |
| } |
| |
| public void testTypesWithMultipleParametersSerialization() throws Exception { |
| MultiParameters<Integer, Float, Double, String, BagOfPrimitives> src = |
| new MultiParameters<>(10, 1.0F, 2.1D, "abc", new BagOfPrimitives()); |
| Type typeOfSrc = new TypeToken<MultiParameters<Integer, Float, Double, String, |
| BagOfPrimitives>>() {}.getType(); |
| String json = gson.toJson(src, typeOfSrc); |
| String expected = "{\"a\":10,\"b\":1.0,\"c\":2.1,\"d\":\"abc\"," |
| + "\"e\":{\"longValue\":0,\"intValue\":0,\"booleanValue\":false,\"stringValue\":\"\"}}"; |
| assertEquals(expected, json); |
| } |
| |
| public void testTypesWithMultipleParametersDeserialization() throws Exception { |
| Type typeOfTarget = new TypeToken<MultiParameters<Integer, Float, Double, String, |
| BagOfPrimitives>>() {}.getType(); |
| String json = "{\"a\":10,\"b\":1.0,\"c\":2.1,\"d\":\"abc\"," |
| + "\"e\":{\"longValue\":0,\"intValue\":0,\"booleanValue\":false,\"stringValue\":\"\"}}"; |
| MultiParameters<Integer, Float, Double, String, BagOfPrimitives> target = |
| gson.fromJson(json, typeOfTarget); |
| MultiParameters<Integer, Float, Double, String, BagOfPrimitives> expected = |
| new MultiParameters<>(10, 1.0F, 2.1D, "abc", new BagOfPrimitives()); |
| assertEquals(expected, target); |
| } |
| |
| public void testParameterizedTypeWithCustomSerializer() { |
| Type ptIntegerType = new TypeToken<MyParameterizedType<Integer>>() {}.getType(); |
| Type ptStringType = new TypeToken<MyParameterizedType<String>>() {}.getType(); |
| Gson gson = new GsonBuilder() |
| .registerTypeAdapter(ptIntegerType, new MyParameterizedTypeAdapter<Integer>()) |
| .registerTypeAdapter(ptStringType, new MyParameterizedTypeAdapter<String>()) |
| .create(); |
| MyParameterizedType<Integer> intTarget = new MyParameterizedType<>(10); |
| String json = gson.toJson(intTarget, ptIntegerType); |
| assertEquals(MyParameterizedTypeAdapter.<Integer>getExpectedJson(intTarget), json); |
| |
| MyParameterizedType<String> stringTarget = new MyParameterizedType<>("abc"); |
| json = gson.toJson(stringTarget, ptStringType); |
| assertEquals(MyParameterizedTypeAdapter.<String>getExpectedJson(stringTarget), json); |
| } |
| |
| public void testParameterizedTypesWithCustomDeserializer() { |
| Type ptIntegerType = new TypeToken<MyParameterizedType<Integer>>() {}.getType(); |
| Type ptStringType = new TypeToken<MyParameterizedType<String>>() {}.getType(); |
| Gson gson = new GsonBuilder().registerTypeAdapter( |
| ptIntegerType, new MyParameterizedTypeAdapter<Integer>()) |
| .registerTypeAdapter(ptStringType, new MyParameterizedTypeAdapter<String>()) |
| .registerTypeAdapter(ptStringType, new MyParameterizedTypeInstanceCreator<>("")) |
| .registerTypeAdapter(ptIntegerType, new MyParameterizedTypeInstanceCreator<>(0)) |
| .create(); |
| |
| MyParameterizedType<Integer> src = new MyParameterizedType<>(10); |
| String json = MyParameterizedTypeAdapter.<Integer>getExpectedJson(src); |
| MyParameterizedType<Integer> intTarget = gson.fromJson(json, ptIntegerType); |
| assertEquals(10, intTarget.value.intValue()); |
| |
| MyParameterizedType<String> srcStr = new MyParameterizedType<>("abc"); |
| json = MyParameterizedTypeAdapter.<String>getExpectedJson(srcStr); |
| MyParameterizedType<String> stringTarget = gson.fromJson(json, ptStringType); |
| assertEquals("abc", stringTarget.value); |
| } |
| |
| public void testParameterizedTypesWithWriterSerialization() throws Exception { |
| Writer writer = new StringWriter(); |
| MyParameterizedType<Integer> src = new MyParameterizedType<>(10); |
| Type typeOfSrc = new TypeToken<MyParameterizedType<Integer>>() {}.getType(); |
| gson.toJson(src, typeOfSrc, writer); |
| assertEquals(src.getExpectedJson(), writer.toString()); |
| } |
| |
| public void testParameterizedTypeWithReaderDeserialization() throws Exception { |
| BagOfPrimitives bag = new BagOfPrimitives(); |
| MyParameterizedType<BagOfPrimitives> expected = new MyParameterizedType<>(bag); |
| Type expectedType = new TypeToken<MyParameterizedType<BagOfPrimitives>>() {}.getType(); |
| BagOfPrimitives bagDefaultInstance = new BagOfPrimitives(); |
| Gson gson = new GsonBuilder().registerTypeAdapter( |
| expectedType, new MyParameterizedTypeInstanceCreator<>(bagDefaultInstance)) |
| .create(); |
| |
| Reader json = new StringReader(expected.getExpectedJson()); |
| MyParameterizedType<Integer> actual = gson.fromJson(json, expectedType); |
| assertEquals(expected, actual); |
| } |
| |
| @SuppressWarnings("varargs") |
| @SafeVarargs |
| private static <T> T[] arrayOf(T... args) { |
| return args; |
| } |
| |
| public void testVariableTypeFieldsAndGenericArraysSerialization() throws Exception { |
| Integer obj = 0; |
| Integer[] array = { 1, 2, 3 }; |
| List<Integer> list = new ArrayList<>(); |
| list.add(4); |
| list.add(5); |
| List<Integer>[] arrayOfLists = arrayOf(list, list); |
| |
| Type typeOfSrc = new TypeToken<ObjectWithTypeVariables<Integer>>() {}.getType(); |
| ObjectWithTypeVariables<Integer> objToSerialize = |
| new ObjectWithTypeVariables<>(obj, array, list, arrayOfLists, list, arrayOfLists); |
| String json = gson.toJson(objToSerialize, typeOfSrc); |
| |
| assertEquals(objToSerialize.getExpectedJson(), json); |
| } |
| |
| public void testVariableTypeFieldsAndGenericArraysDeserialization() throws Exception { |
| Integer obj = 0; |
| Integer[] array = { 1, 2, 3 }; |
| List<Integer> list = new ArrayList<>(); |
| list.add(4); |
| list.add(5); |
| List<Integer>[] arrayOfLists = arrayOf(list, list); |
| |
| Type typeOfSrc = new TypeToken<ObjectWithTypeVariables<Integer>>() {}.getType(); |
| ObjectWithTypeVariables<Integer> objToSerialize = |
| new ObjectWithTypeVariables<>(obj, array, list, arrayOfLists, list, arrayOfLists); |
| String json = gson.toJson(objToSerialize, typeOfSrc); |
| ObjectWithTypeVariables<Integer> objAfterDeserialization = gson.fromJson(json, typeOfSrc); |
| |
| assertEquals(objAfterDeserialization.getExpectedJson(), json); |
| } |
| |
| public void testVariableTypeDeserialization() throws Exception { |
| Type typeOfSrc = new TypeToken<ObjectWithTypeVariables<Integer>>() {}.getType(); |
| ObjectWithTypeVariables<Integer> objToSerialize = |
| new ObjectWithTypeVariables<>(0, null, null, null, null, null); |
| String json = gson.toJson(objToSerialize, typeOfSrc); |
| ObjectWithTypeVariables<Integer> objAfterDeserialization = gson.fromJson(json, typeOfSrc); |
| |
| assertEquals(objAfterDeserialization.getExpectedJson(), json); |
| } |
| |
| public void testVariableTypeArrayDeserialization() throws Exception { |
| Integer[] array = { 1, 2, 3 }; |
| |
| Type typeOfSrc = new TypeToken<ObjectWithTypeVariables<Integer>>() {}.getType(); |
| ObjectWithTypeVariables<Integer> objToSerialize = |
| new ObjectWithTypeVariables<>(null, array, null, null, null, null); |
| String json = gson.toJson(objToSerialize, typeOfSrc); |
| ObjectWithTypeVariables<Integer> objAfterDeserialization = gson.fromJson(json, typeOfSrc); |
| |
| assertEquals(objAfterDeserialization.getExpectedJson(), json); |
| } |
| |
| public void testParameterizedTypeWithVariableTypeDeserialization() throws Exception { |
| List<Integer> list = new ArrayList<>(); |
| list.add(4); |
| list.add(5); |
| |
| Type typeOfSrc = new TypeToken<ObjectWithTypeVariables<Integer>>() {}.getType(); |
| ObjectWithTypeVariables<Integer> objToSerialize = |
| new ObjectWithTypeVariables<>(null, null, list, null, null, null); |
| String json = gson.toJson(objToSerialize, typeOfSrc); |
| ObjectWithTypeVariables<Integer> objAfterDeserialization = gson.fromJson(json, typeOfSrc); |
| |
| assertEquals(objAfterDeserialization.getExpectedJson(), json); |
| } |
| |
| public void testParameterizedTypeGenericArraysSerialization() throws Exception { |
| List<Integer> list = new ArrayList<>(); |
| list.add(1); |
| list.add(2); |
| List<Integer>[] arrayOfLists = arrayOf(list, list); |
| |
| Type typeOfSrc = new TypeToken<ObjectWithTypeVariables<Integer>>() {}.getType(); |
| ObjectWithTypeVariables<Integer> objToSerialize = |
| new ObjectWithTypeVariables<>(null, null, null, arrayOfLists, null, null); |
| String json = gson.toJson(objToSerialize, typeOfSrc); |
| assertEquals("{\"arrayOfListOfTypeParameters\":[[1,2],[1,2]]}", json); |
| } |
| |
| public void testParameterizedTypeGenericArraysDeserialization() throws Exception { |
| List<Integer> list = new ArrayList<>(); |
| list.add(1); |
| list.add(2); |
| List<Integer>[] arrayOfLists = arrayOf(list, list); |
| |
| Type typeOfSrc = new TypeToken<ObjectWithTypeVariables<Integer>>() {}.getType(); |
| ObjectWithTypeVariables<Integer> objToSerialize = |
| new ObjectWithTypeVariables<>(null, null, null, arrayOfLists, null, null); |
| String json = gson.toJson(objToSerialize, typeOfSrc); |
| ObjectWithTypeVariables<Integer> objAfterDeserialization = gson.fromJson(json, typeOfSrc); |
| |
| assertEquals(objAfterDeserialization.getExpectedJson(), json); |
| } |
| |
| /** |
| * An test object that has fields that are type variables. |
| * |
| * @param <T> Enforce T to be a string to make writing the "toExpectedJson" method easier. |
| */ |
| private static class ObjectWithTypeVariables<T extends Number> { |
| private final T typeParameterObj; |
| private final T[] typeParameterArray; |
| private final List<T> listOfTypeParameters; |
| private final List<T>[] arrayOfListOfTypeParameters; |
| private final List<? extends T> listOfWildcardTypeParameters; |
| private final List<? extends T>[] arrayOfListOfWildcardTypeParameters; |
| |
| // For use by Gson |
| @SuppressWarnings("unused") |
| private ObjectWithTypeVariables() { |
| this(null, null, null, null, null, null); |
| } |
| |
| public ObjectWithTypeVariables(T obj, T[] array, List<T> list, List<T>[] arrayOfList, |
| List<? extends T> wildcardList, List<? extends T>[] arrayOfWildcardList) { |
| this.typeParameterObj = obj; |
| this.typeParameterArray = array; |
| this.listOfTypeParameters = list; |
| this.arrayOfListOfTypeParameters = arrayOfList; |
| this.listOfWildcardTypeParameters = wildcardList; |
| this.arrayOfListOfWildcardTypeParameters = arrayOfWildcardList; |
| } |
| |
| public String getExpectedJson() { |
| StringBuilder sb = new StringBuilder().append("{"); |
| |
| boolean needsComma = false; |
| if (typeParameterObj != null) { |
| sb.append("\"typeParameterObj\":").append(toString(typeParameterObj)); |
| needsComma = true; |
| } |
| |
| if (typeParameterArray != null) { |
| if (needsComma) { |
| sb.append(','); |
| } |
| sb.append("\"typeParameterArray\":["); |
| appendObjectsToBuilder(sb, Arrays.asList(typeParameterArray)); |
| sb.append(']'); |
| needsComma = true; |
| } |
| |
| if (listOfTypeParameters != null) { |
| if (needsComma) { |
| sb.append(','); |
| } |
| sb.append("\"listOfTypeParameters\":["); |
| appendObjectsToBuilder(sb, listOfTypeParameters); |
| sb.append(']'); |
| needsComma = true; |
| } |
| |
| if (arrayOfListOfTypeParameters != null) { |
| if (needsComma) { |
| sb.append(','); |
| } |
| sb.append("\"arrayOfListOfTypeParameters\":["); |
| appendObjectsToBuilder(sb, arrayOfListOfTypeParameters); |
| sb.append(']'); |
| needsComma = true; |
| } |
| |
| if (listOfWildcardTypeParameters != null) { |
| if (needsComma) { |
| sb.append(','); |
| } |
| sb.append("\"listOfWildcardTypeParameters\":["); |
| appendObjectsToBuilder(sb, listOfWildcardTypeParameters); |
| sb.append(']'); |
| needsComma = true; |
| } |
| |
| if (arrayOfListOfWildcardTypeParameters != null) { |
| if (needsComma) { |
| sb.append(','); |
| } |
| sb.append("\"arrayOfListOfWildcardTypeParameters\":["); |
| appendObjectsToBuilder(sb, arrayOfListOfWildcardTypeParameters); |
| sb.append(']'); |
| needsComma = true; |
| } |
| sb.append('}'); |
| return sb.toString(); |
| } |
| |
| private void appendObjectsToBuilder(StringBuilder sb, Iterable<? extends T> iterable) { |
| boolean isFirst = true; |
| for (T obj : iterable) { |
| if (!isFirst) { |
| sb.append(','); |
| } |
| isFirst = false; |
| sb.append(toString(obj)); |
| } |
| } |
| |
| private void appendObjectsToBuilder(StringBuilder sb, List<? extends T>[] arrayOfList) { |
| boolean isFirst = true; |
| for (List<? extends T> list : arrayOfList) { |
| if (!isFirst) { |
| sb.append(','); |
| } |
| isFirst = false; |
| if (list != null) { |
| sb.append('['); |
| appendObjectsToBuilder(sb, list); |
| sb.append(']'); |
| } else { |
| sb.append("null"); |
| } |
| } |
| } |
| |
| public String toString(T obj) { |
| return obj.toString(); |
| } |
| } |
| |
| private static class MultiParameters<A, B, C, D, E> { |
| A a; |
| B b; |
| C c; |
| D d; |
| E e; |
| // For use by Gson |
| @SuppressWarnings("unused") |
| private MultiParameters() { |
| } |
| MultiParameters(A a, B b, C c, D d, E e) { |
| super(); |
| this.a = a; |
| this.b = b; |
| this.c = c; |
| this.d = d; |
| this.e = e; |
| } |
| @Override |
| public int hashCode() { |
| final int prime = 31; |
| int result = 1; |
| result = prime * result + ((a == null) ? 0 : a.hashCode()); |
| result = prime * result + ((b == null) ? 0 : b.hashCode()); |
| result = prime * result + ((c == null) ? 0 : c.hashCode()); |
| result = prime * result + ((d == null) ? 0 : d.hashCode()); |
| result = prime * result + ((e == null) ? 0 : e.hashCode()); |
| return result; |
| } |
| @Override |
| @SuppressWarnings("unchecked") |
| public boolean equals(Object obj) { |
| if (this == obj) { |
| return true; |
| } |
| if (obj == null) { |
| return false; |
| } |
| if (getClass() != obj.getClass()) { |
| return false; |
| } |
| MultiParameters<A, B, C, D, E> other = (MultiParameters<A, B, C, D, E>) obj; |
| if (a == null) { |
| if (other.a != null) { |
| return false; |
| } |
| } else if (!a.equals(other.a)) { |
| return false; |
| } |
| if (b == null) { |
| if (other.b != null) { |
| return false; |
| } |
| } else if (!b.equals(other.b)) { |
| return false; |
| } |
| if (c == null) { |
| if (other.c != null) { |
| return false; |
| } |
| } else if (!c.equals(other.c)) { |
| return false; |
| } |
| if (d == null) { |
| if (other.d != null) { |
| return false; |
| } |
| } else if (!d.equals(other.d)) { |
| return false; |
| } |
| if (e == null) { |
| if (other.e != null) { |
| return false; |
| } |
| } else if (!e.equals(other.e)) { |
| return false; |
| } |
| return true; |
| } |
| } |
| |
| // Begin: tests to reproduce issue 103 |
| private static class Quantity { |
| @SuppressWarnings("unused") |
| int q = 10; |
| } |
| private static class MyQuantity extends Quantity { |
| @SuppressWarnings("unused") |
| int q2 = 20; |
| } |
| private interface Measurable<T> { |
| } |
| private interface Field<T> { |
| } |
| private interface Immutable { |
| } |
| |
| public static final class Amount<Q extends Quantity> |
| implements Measurable<Q>, Field<Amount<?>>, Serializable, Immutable { |
| private static final long serialVersionUID = -7560491093120970437L; |
| |
| int value = 30; |
| } |
| |
| public void testDeepParameterizedTypeSerialization() { |
| Amount<MyQuantity> amount = new Amount<>(); |
| String json = gson.toJson(amount); |
| assertTrue(json.contains("value")); |
| assertTrue(json.contains("30")); |
| } |
| |
| public void testDeepParameterizedTypeDeserialization() { |
| String json = "{value:30}"; |
| Type type = new TypeToken<Amount<MyQuantity>>() {}.getType(); |
| Amount<MyQuantity> amount = gson.fromJson(json, type); |
| assertEquals(30, amount.value); |
| } |
| // End: tests to reproduce issue 103 |
| } |