Created
October 17, 2017 23:05
-
-
Save varren/f97c902efc0f34967af651529cc51902 to your computer and use it in GitHub Desktop.
jacksonpolymorphicdeserialization https://stackoverflow.com/questions/28993035/jacksonpolymorphicdeserialization-jsonmappingexception
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import com.fasterxml.jackson.annotation.*; | |
import com.fasterxml.jackson.databind.*; | |
import lombok.Data; | |
import lombok.ToString; | |
import java.io.IOException; | |
import java.util.Arrays; | |
import java.util.List; | |
import java.util.Map; | |
import java.util.Objects; | |
/** | |
* Created by varren on 17.10.17. | |
*/ | |
public class OptionOne { | |
public static void main(String[] args) throws IOException { | |
ObjectMapper mapper = new ObjectMapper(); | |
test(mapper); | |
} | |
private static void test(ObjectMapper mapper) throws IOException { | |
ComboParameter p = new ComboParameter(); | |
p.setRegEx("*"); | |
p.setValues(Arrays.asList("1","2","3")); | |
A a = new A(); | |
a.setOtherField("other"); | |
a.setParameter(p); | |
String json = mapper.writeValueAsString(a); | |
System.out.println("From: "+ json); | |
A aNew = mapper.readValue(json,A.class); | |
System.out.println("To : "+ aNew); | |
System.out.println("From == To: "+ Objects.equals(a, aNew)); | |
} | |
@Data | |
@JsonSubTypes({ | |
@JsonSubTypes.Type(value = IntegerParameter.class, name = "integerParam"), | |
@JsonSubTypes.Type(value = ComboParameter.class, name = "comboParam") | |
}) | |
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.WRAPPER_OBJECT) | |
public static abstract class Parameter { | |
String regEx; | |
} | |
@Data | |
@ToString(callSuper=true) | |
@JsonTypeName("integerParam") | |
public static class IntegerParameter extends Parameter {} | |
@Data | |
@ToString(callSuper=true) | |
@JsonTypeName("comboParam") | |
public static class ComboParameter extends Parameter { | |
List<String> values; | |
} | |
@Data | |
public static class A { | |
String otherField; | |
@JsonIgnore | |
Parameter parameter; | |
private static ObjectMapper mapper = new ObjectMapper(); | |
@JsonAnyGetter | |
private Map<String, Object> parameterAsMap(){ | |
return mapper.convertValue(parameter, Map.class); | |
} | |
@JsonAnySetter | |
private void parameterFromMap(String key, JsonNode value) { | |
try { | |
parameter = mapper.readValue(String.format("{\"%s\":%s}", key,value), | |
Parameter.class); | |
} catch (IOException e) { | |
e.printStackTrace(); | |
} | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import com.fasterxml.jackson.annotation.*; | |
import com.fasterxml.jackson.core.JsonGenerator; | |
import com.fasterxml.jackson.core.JsonParser; | |
import com.fasterxml.jackson.core.TreeNode; | |
import com.fasterxml.jackson.databind.*; | |
import com.fasterxml.jackson.databind.module.SimpleModule; | |
import lombok.Data; | |
import lombok.ToString; | |
import java.io.IOException; | |
import java.util.Arrays; | |
import java.util.List; | |
import java.util.Map; | |
import java.util.Objects; | |
/** | |
* Created by varren on 17.10.17. | |
*/ | |
public class OptionTwo { | |
public static void main(String[] args) throws IOException { | |
ObjectMapper mapper = new ObjectMapper(); | |
SimpleModule module = new SimpleModule(); | |
module.addSerializer(A.class, new ASerializer()); | |
module.addDeserializer(A.class, new ADeserializer()); | |
mapper.registerModule(module); | |
mapper.disable(SerializationFeature.FAIL_ON_UNWRAPPED_TYPE_IDENTIFIERS); | |
test(mapper); | |
} | |
private static void test(ObjectMapper mapper) throws IOException { | |
ComboParameter p = new ComboParameter(); | |
p.setRegEx("*"); | |
p.setValues(Arrays.asList("1", "2", "3")); | |
A a = new A(); | |
a.setOtherField("other"); | |
a.setParameter(p); | |
String json = mapper.writeValueAsString(a); | |
System.out.println("From: " + json); | |
A aNew = mapper.readValue(json, A.class); | |
System.out.println("To : " + aNew); | |
System.out.println("From == To: " + Objects.equals(a, aNew)); | |
} | |
@Data | |
@JsonSubTypes({ | |
@JsonSubTypes.Type(value = IntegerParameter.class, name = "integerParam"), | |
@JsonSubTypes.Type(value = ComboParameter.class, name = "comboParam") | |
}) | |
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.WRAPPER_OBJECT) | |
public static abstract class Parameter { | |
String regEx; | |
} | |
@Data | |
@ToString(callSuper = true) | |
@JsonTypeName("integerParam") | |
public static class IntegerParameter extends Parameter { | |
} | |
@Data | |
@ToString(callSuper = true) | |
@JsonTypeName("comboParam") | |
public static class ComboParameter extends Parameter { | |
List<String> values; | |
} | |
@Data | |
public static class A { | |
String otherField; | |
Parameter parameter; | |
} | |
public static class ASerializer extends JsonSerializer<A> { | |
private static ObjectMapper m = new ObjectMapper(); | |
@Override | |
public void serialize(A value, JsonGenerator gen, | |
SerializerProvider serializers) throws IOException { | |
Map defaults = m.convertValue(value, Map.class); | |
Map params = m.convertValue(value.getParameter(), Map.class); | |
defaults.putAll(params); | |
gen.writeObject(defaults); | |
} | |
} | |
public static class ADeserializer extends JsonDeserializer<A> { | |
private static ObjectMapper m = new ObjectMapper(); | |
private static String[] subtipes = {"integerParam", "comboParam"}; | |
public ADeserializer() { | |
m.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); | |
} | |
@Override | |
public A deserialize(JsonParser p, DeserializationContext ctxt) | |
throws IOException { | |
TreeNode node = m.readTree(p); | |
A a = m.convertValue(node, A.class); | |
// hardcoded , probably can be done dynamically | |
for (String key : subtipes) { | |
TreeNode value = node.get(key); | |
if (value != null) { | |
String json = String.format("{\"%s\":%s}", key, value); | |
a.setParameter(m.readValue(json, Parameter.class)); | |
break; | |
} | |
} | |
return a; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment