/* * Copyright 2014 Nicolas Morel * * 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.github.nmorel.gwtjackson.shared.advanced; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import com.fasterxml.jackson.annotation.JsonPropertyOrder; import com.fasterxml.jackson.annotation.JsonTypeInfo; import com.fasterxml.jackson.annotation.JsonTypeInfo.As; import com.fasterxml.jackson.annotation.JsonTypeInfo.Id; import com.github.nmorel.gwtjackson.shared.AbstractTester; import com.github.nmorel.gwtjackson.shared.ObjectMapperTester; /** * @author Nicolas Morel. */ public class GenericsAndInheritanceTester extends AbstractTester { @JsonTypeInfo( property = "class", include = As.PROPERTY, use = Id.CLASS ) @JsonPropertyOrder( alphabetic = true ) public static class Result<T> { private String exceptionMessage; private T payload; public String getExceptionMessage() { return exceptionMessage; } public void setExceptionMessage( String exceptionMessage ) { this.exceptionMessage = exceptionMessage; } public T getPayload() { return payload; } public void setPayload( T payload ) { this.payload = payload; } } public static class GetResult<V extends Number, K> extends Result<K> { private String aString; private V aNumber; public String getaString() { return aString; } public void setaString( String aString ) { this.aString = aString; } public V getaNumber() { return aNumber; } public void setaNumber( V aNumber ) { this.aNumber = aNumber; } } public static class IntegerResult extends Result<Integer> {} //##### With Map @JsonTypeInfo( use = JsonTypeInfo.Id.MINIMAL_CLASS, include = JsonTypeInfo.As.PROPERTY ) public static class Owner { List<Parent<?>> parents = new ArrayList<Parent<?>>(); public List<Parent<?>> getParents() { return parents; } public void setParents( List<Parent<?>> parents ) { this.parents = parents; } } @JsonTypeInfo( use = JsonTypeInfo.Id.MINIMAL_CLASS, include = JsonTypeInfo.As.PROPERTY ) public static class Parent<T> { Child<T> child; Map<T, T> typed = new HashMap<T, T>(); Map untyped = new HashMap(); public Child<T> getChild() { return child; } public void setChild( Child<T> child ) { this.child = child; } public Map<T, T> getTyped() { return typed; } public void setTyped( Map<T, T> typed ) { this.typed = typed; } public Map getUntyped() { return untyped; } public void setUntyped( Map untyped ) { this.untyped = untyped; } } public static class IntegerParent extends Parent<Integer> {} public static class StringParent extends Parent<String> {} public static class Child<T> { Map<T, T> typed = new HashMap<T, T>(); Map untyped = new HashMap(); public Map<T, T> getTyped() { return typed; } public void setTyped( Map<T, T> typed ) { this.typed = typed; } public Map getUntyped() { return untyped; } public void setUntyped( Map untyped ) { this.untyped = untyped; } } public static final GenericsAndInheritanceTester INSTANCE = new GenericsAndInheritanceTester(); private GenericsAndInheritanceTester() { } public void test( ObjectMapperTester<Result<Integer>[]> mapper ) { Result<Integer>[] result = mapper.read( "[\n" + " {\n" + " \"class\":\"com.github.nmorel.gwtjackson.shared.advanced.GenericsAndInheritanceTester$Result\",\n" + " \"exceptionMessage\":null,\n" + " \"payload\":10" + " },\n" + " {\n" + " \"class\":\"com.github.nmorel.gwtjackson.shared.advanced.GenericsAndInheritanceTester$GetResult\",\n" + " \"exceptionMessage\":\"anException\",\n" + " \"payload\":45,\n" + " \"aString\":\"aSuperString\",\n" + " \"aNumber\":28.8\n" + " },\n" + " {\n" + " \"class\":\"com.github.nmorel.gwtjackson.shared.advanced.GenericsAndInheritanceTester$IntegerResult\",\n" + " \"payload\":70\n" + " }\n" + "]" ); assertEquals( 3, result.length ); assertEquals( Result.class, result[0].getClass() ); assertNull( result[0].getExceptionMessage() ); assertEquals( 10, result[0].getPayload().intValue() ); assertEquals( GetResult.class, result[1].getClass() ); assertEquals( "anException", result[1].getExceptionMessage() ); assertEquals( 45, result[1].getPayload().intValue() ); assertEquals( "aSuperString", ((GetResult<Double, Integer>) result[1]).getaString() ); assertEquals( 28.8, ((GetResult<Double, Integer>) result[1]).getaNumber() ); assertEquals( IntegerResult.class, result[2].getClass() ); assertNull( result[2].getExceptionMessage() ); assertEquals( 70, result[2].getPayload().intValue() ); assertEquals( "[" + "{" + "\"class\":\"com.github.nmorel.gwtjackson.shared.advanced.GenericsAndInheritanceTester$Result\"," + "\"exceptionMessage\":null," + "\"payload\":10" + "}," + "{" + "\"class\":\"com.github.nmorel.gwtjackson.shared.advanced.GenericsAndInheritanceTester$GetResult\"," + "\"aNumber\":28.8," + "\"aString\":\"aSuperString\"," + "\"exceptionMessage\":\"anException\"," + "\"payload\":45" + "}," + "{" + "\"class\":\"com.github.nmorel.gwtjackson.shared.advanced.GenericsAndInheritanceTester$IntegerResult\"," + "\"exceptionMessage\":null," + "\"payload\":70" + "}]", mapper.write( result ) ); } public void testMap( ObjectMapperTester<Owner> mapper ) { Owner owner = new Owner(); StringParent sp = new StringParent(); sp.setTyped( createMap( "1", "1" ) ); sp.setUntyped( createMap( "1", "1" ) ); Child<String> sc = new Child<String>(); sc.setTyped( createMap( "1", "1" ) ); sc.setUntyped( createMap( "1", "1" ) ); sp.setChild( sc ); IntegerParent ip = new IntegerParent(); ip.setTyped( createMap( 1, 1 ) ); ip.setUntyped( createMap( 1, 1 ) ); Child<Integer> ic = new Child<Integer>(); ic.setTyped( createMap( 1, 1 ) ); ic.setUntyped( createMap( 1, 1 ) ); ip.setChild( ic ); owner.getParents().add( sp ); owner.getParents().add( ip ); String json = mapper.write( owner ); assertEquals( "{" + "\"@c\":\".GenericsAndInheritanceTester$Owner\"," + "\"parents\":[" + "{" + "\"@c\":\".GenericsAndInheritanceTester$StringParent\"," + "\"child\":{" + "\"typed\":{\"1\":\"1\"},\"untyped\":{\"1\":\"1\"}" + "}," + "\"typed\":{\"1\":\"1\"}," + "\"untyped\":{\"1\":\"1\"}" + "}," + "{" + "\"@c\":\".GenericsAndInheritanceTester$IntegerParent\"," + "\"child\":{" + "\"typed\":{\"1\":1}," + "\"untyped\":{\"1\":1}" + "}," + "\"typed\":{\"1\":1}," + "\"untyped\":{\"1\":1}" + "}" + "]}", json ); owner = mapper.read( json ); sp = (StringParent) owner.getParents().get( 0 ); ip = (IntegerParent) owner.getParents().get( 1 ); // Raw map : keys are strings assertEquals( sp.getUntyped().get( "1" ), "1" ); assertEquals( sp.getChild().getUntyped().get( "1" ), "1" ); assertEquals( ip.getUntyped().get( "1" ), 1 ); assertEquals( ip.getChild().getUntyped().get( "1" ), 1 ); // Typed map : keys are integer or string assertEquals( sp.getTyped().get( "1" ), "1" ); assertEquals( sp.getChild().getTyped().get( "1" ), "1" ); assertEquals( ip.getTyped().get( 1 ), (Integer) 1 ); assertEquals( ip.getChild().getTyped().get( 1 ), (Integer) 1 ); } private static <T> Map<T, T> createMap( T t1, T t2 ) { Map<T, T> map = new HashMap<T, T>(); map.put( t1, t2 ); return map; } }