/** * Copyright (C) 2009-2015 the original author or authors. * See the notice.md file distributed with this work for additional * information regarding copyright ownership. * * 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 org.fusesource.restygwt.client.codec; import org.fusesource.restygwt.client.JsonEncoderDecoder; import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonSubTypes; import com.fasterxml.jackson.annotation.JsonSubTypes.Type; import com.fasterxml.jackson.annotation.JsonTypeInfo.As; import com.fasterxml.jackson.annotation.JsonTypeInfo.Id; import com.fasterxml.jackson.annotation.JsonTypeInfo; import com.fasterxml.jackson.annotation.JsonTypeName; import com.google.gwt.core.client.GWT; import com.google.gwt.json.client.JSONValue; import com.google.gwt.junit.client.GWTTestCase; public class PolymorphicEncoderDecoderTestGwt extends GWTTestCase { @Override public String getModuleName() { return "org.fusesource.restygwt.PolymorphicEncoderDecoderTestGwt"; } @JsonTypeInfo(use = Id.CLASS, include = As.PROPERTY, property = "@class") @JsonSubTypes({ @Type(DefaultImplementationOfSubTypeInterface.class), @Type(SecondImplementationOfSubTypeInterface.class) }) interface JsonSubTypesWithAnInterface { String getValue(); } static abstract class AbstractSubType implements JsonSubTypesWithAnInterface { } static class DefaultImplementationOfSubTypeInterface extends AbstractSubType { private String value; @JsonCreator public DefaultImplementationOfSubTypeInterface(@JsonProperty("value") String value) { this.value = value; } @Override public String getValue() { return value; } } static class SecondImplementationOfSubTypeInterface extends AbstractSubType { public String value; @Override public String getValue() { return value; } } static interface JsonSubTypesWithAnInterfaceCodec extends JsonEncoderDecoder<JsonSubTypesWithAnInterface> { } static interface JsonSubTypesWithAnInterfaceImplementationCodec extends JsonEncoderDecoder<DefaultImplementationOfSubTypeInterface> { } public void testJsonSubTypesWithAnInterface() { JsonSubTypesWithAnInterfaceCodec codec = GWT.create(JsonSubTypesWithAnInterfaceCodec.class); String value = "Hello, world!"; JsonSubTypesWithAnInterface o1 = new DefaultImplementationOfSubTypeInterface(value); JSONValue json = codec.encode(o1); assertEquals(json.isObject().get("@class").isString().stringValue(), DefaultImplementationOfSubTypeInterface.class.getName().replace("$", ".")); JsonSubTypesWithAnInterface o2 = codec.decode(json); assertEquals(json.toString(), codec.encode(o2).toString()); assertEquals(value, o1.getValue()); assertEquals(o1.getValue(), o2.getValue()); assertEquals(o2.getClass(), DefaultImplementationOfSubTypeInterface.class); } public void testJsonSubTypesWithInterfaceUsingConcreteImplementationCodec() { JsonSubTypesWithAnInterfaceImplementationCodec codec = GWT.create(JsonSubTypesWithAnInterfaceImplementationCodec.class); String value = "Hello, world!"; DefaultImplementationOfSubTypeInterface o1 = new DefaultImplementationOfSubTypeInterface(value); JSONValue json = codec.encode(o1); JSONValue objectClass = json.isObject().get("@class"); assertNotNull(objectClass); assertEquals(DefaultImplementationOfSubTypeInterface.class.getName().replace("$","."), objectClass.isString().stringValue()); DefaultImplementationOfSubTypeInterface o2 = codec.decode(json); assertEquals(json.toString(), codec.encode(o2).toString()); assertEquals(value, o1.getValue()); } // ###################################################################################### @JsonTypeInfo(use = Id.CLASS, include = As.PROPERTY, property = "@class") @JsonSubTypes({ @Type(EnumOfSubTypeInterface.class) }) interface JsonSubTypesWithAnInterfaceForUseWithAnEnum { @JsonProperty("name") String name(); } enum EnumOfSubTypeInterface implements JsonSubTypesWithAnInterfaceForUseWithAnEnum { HELLO, WORLD } static interface JsonSubTypesWithAnInterfaceForUseWithAnEnumCodec extends JsonEncoderDecoder<JsonSubTypesWithAnInterfaceForUseWithAnEnum> { } public void testJsonSubTypesWithAnInterfaceImplementedByAnEnum() { JsonSubTypesWithAnInterfaceForUseWithAnEnumCodec codec = GWT.create(JsonSubTypesWithAnInterfaceForUseWithAnEnumCodec.class); JSONValue json = codec.encode(EnumOfSubTypeInterface.HELLO); JsonSubTypesWithAnInterfaceForUseWithAnEnum useWithAnEnum = codec.decode(json); assertEquals(useWithAnEnum.name(), EnumOfSubTypeInterface.HELLO.name()); } // ###################################################################################### @JsonTypeInfo(use = Id.CLASS, include = As.PROPERTY, property = "@class") @JsonSubTypes({ @Type(SubForJsonProperty.class) }) public static class BaseForJsonProperty { private String myField; @JsonProperty public String getMyField() { return myField; } public void setMyField(String myField) { this.myField = myField; } } public static class SubForJsonProperty extends BaseForJsonProperty { private String otherField; public String getOtherField() { return otherField; } public void setOtherField(String otherField) { this.otherField = otherField; } } static interface JsonPropertyOnSuperClassCodec extends JsonEncoderDecoder<BaseForJsonProperty> { } public void testJsonPropertyOnSuperClass() { JsonPropertyOnSuperClassCodec codec = GWT.create(JsonPropertyOnSuperClassCodec.class); SubForJsonProperty o1 = new SubForJsonProperty(); o1.setMyField("my-field-value"); o1.setOtherField("other-field-value"); JSONValue json = codec.encode(o1); assertEquals("{\"@class\":\"org.fusesource.restygwt.client.codec.PolymorphicEncoderDecoderTestGwt.SubForJsonProperty\", \"otherField\":\"other-field-value\", \"myField\":\"my-field-value\"}", json.toString()); } // ###################################################################################### @JsonSubTypes({ @Type(A.class), @Type(B.class) }) @JsonTypeName("A") @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "@class") static public class A { private String code; public String getCode() { return code; } public void setCode(String code) { this.code = code; } } @JsonTypeName("B") static public class B extends A { private String desc; public String getDesc() { return desc; } public void setDesc(String desc) { this.desc = desc; } } static public interface IdNamePolymorphicCodec extends JsonEncoderDecoder<A> { } public void testIdNamePolymorphic() { IdNamePolymorphicCodec codec = GWT.create(IdNamePolymorphicCodec.class); String json = "{\"code\":\"test code\"}"; A obj = codec.decode(json); } }