I used the Class option in java as a replacement for using null with better type checks. http://functionaljava.googlecode.com/svn/artifacts/2.20/javadoc/fj/data/Option.html
My question is how to serialize / deserialize my next code in JSON?
public Option<? extends ClassA> a;
The result of serialization using ObjectMapper is always:
"a" : [ "Option$Some", { "none" : false, "some" : true } ]
and deserialization does not work.
Thanks for any answer.
p / s: I insert my full code as follows:
public class TestOption { @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "@class") @JsonSubTypes({ @JsonSubTypes.Type(value = SoundDog.class, name = "soundDog"), @JsonSubTypes.Type(value = SoundCat.class, name = "soundCat"), }) public static abstract class Sound { abstract String getSound(); } public static class SoundDog extends Sound { @Override String getSound() { return "gau gau"; } } public static class SoundCat extends Sound { @Override String getSound() { return "meo meo"; } } @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type") @JsonSubTypes({ @JsonSubTypes.Type(value = Dog.class, name = "dog"), @JsonSubTypes.Type(value = Cat.class, name = "cat"), }) public static abstract class Animal { public Animal() { } public Animal(String name) { this.name = name; } public String name; public Animal parent; public Option<? extends Sound> sound; } @JsonTypeName("dog") public static class Dog extends Animal { public Dog() { } public Dog(String name) { super(name); } } @JsonTypeName("cat") public static class Cat extends Animal { public Cat() { } public Cat(String name) { super(name); } } public static void main(String... args) throws Exception { TestOption zoo = createZoo(); ObjectMapper mapper = new ObjectMapper(); mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); String json1 = mapper.writerWithDefaultPrettyPrinter() .writeValueAsString(zoo); System.out.println("+++>>>" + json1); zoo = mapper.readValue(json1, TestOption.class); for(Animal animal : zoo.animals){ System.out.println("Animal name = " + animal.name); if(animal.sound != null){ System.out.println("Animal sound = " + animal.sound.some().getSound()); } } String json2 = mapper.writerWithDefaultPrettyPrinter() .writeValueAsString(zoo); System.out.println("Equals: " + json1.equals(json2)); } private static TestOption createZoo() { TestOption zoo = new TestOption(); Dog dog1 = new Dog("Dog1"); dog1.sound = Option.some(new SoundDog()); Dog dog2 = new Dog("Dog2"); dog2.sound = Option.some(new SoundDog()); Cat cat1 = new Cat("Cat1"); cat1.sound = Option.some(new SoundCat()); Cat cat2 = new Cat("Cat2"); dog2.parent = dog1; cat2.parent = cat1; zoo.add(dog1); zoo.add(dog2); zoo.add(cat1); zoo.add(cat2); return zoo; } public void add(Animal animal) { animals.add(animal); } public void setAnimals(List<Animal> list) { this.animals = list; } public List<Animal> getAnimals() { return this.animals; } public List<Animal> animals = new ArrayList<Animal>(); }
Update:
My solution looks something like this:
import java.io.IOException; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.ObjectCodec; import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.JsonDeserializer; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.JsonSerializer; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializerProvider; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import eu.cea.ladis.tools.serializableFJ.Option; public class TestClass { public static class MyJsonSerializer extends JsonSerializer<MyObject> { @Override public void serialize(MyObject value, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonProcessingException { jgen.writeStartObject(); Option<String> myString = value.getMyString(); if(myString.isNone()){ jgen.writeStringField("myString", "null"); } if(myString.isSome()){ jgen.writeStringField("myString", myString.some()); } jgen.writeEndObject(); } } public static class MyJsonDeserializer extends JsonDeserializer<MyObject> { @Override public MyObject deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException { ObjectCodec oc = jp.getCodec(); JsonNode node = oc.readTree(jp); return new MyObject(node.get("myString").asText()); } } @JsonSerialize(using = MyJsonSerializer.class) @JsonDeserialize(using = MyJsonDeserializer.class) public static class MyObject { public Option<String> myString; public MyObject() { super(); myString = Option.some("test string"); } public MyObject(String myString) { super(); if(myString != null){ this.myString = Option.some(myString); }else{ this.myString = Option.none(); } } public Option<String> getMyString() { return myString; } } public static void main(String[] args) throws IOException { MyObject obj = new MyObject(); ObjectMapper objectMapper = new ObjectMapper(); String json1 = objectMapper.writeValueAsString(obj); System.out.println("json1>>"+json1); MyObject obj2 = objectMapper.readValue(json1, MyObject.class); String json2 = objectMapper.writeValueAsString(obj2); System.out.println("json2>>"+json2); System.out.println("Equals: " + json1.equals(json2)); } }