Reputation: 143
In the below example, I have a primary class - A and its subclass - B. Both can be used as a property in the general class X.
public class A
{
@JsonProperty("primary_key")
public final String primaryKey;
@JsonCreator
A(@JsonProperty("primary_key") String primaryKey)
{
this.primaryKey = primaryKey;
}
}
public class B extends A
{
@JsonProperty("secondary_key")
public final String secondaryKey;
@JsonCreator
B(@JsonProperty("primary_key") String primaryKey, @JsonProperty("secondary_key") String secondaryKey)
{
super(primaryKey);
this.secondaryKey = secondaryKey;
}
}
public class X
{
@JsonProperty("keys")
public final A keys;
@JsonCreator
X(@JsonProperty("keys") A keys)
{
this.keys = keys;
}
}
How can I use Jackson Polymorphic feature in order to correctly deserialize the below given json into their respective classes:
JSON A :
{ "keys" :{
"primary_key" : "abc"
}
}
JSON B :
{ "keys" : {
"primary_key" : "abc",
"secondary_key" : "xyz"
}
}
Expected Result: Map keys object to Class A for JSON A and Class B for JSON B.
Please suggest alternative suggestions too.
Upvotes: 3
Views: 12928
Reputation: 14731
It feels like a pretty common problem and there is no easy annotations way to solve it (Or maybe i just cant find one):
Deserializing polymorphic types with Jackson
One thing you can do is to add custom deserializer to your object mapper. Here is nice demo of this approach: https://stackoverflow.com/a/19464580/1032167
Here is demo related to your example:
import com.fasterxml.jackson.annotation.*;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.ObjectCodec;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.module.SimpleModule;
import java.io.IOException;
public class Main4 {
private static final String jsonA = "{ \"keys\" : { \"primary_key\" : \"abc\" } }";
private static final String jsonB =
"{ \"keys\" : { \"primary_key\" : \"abc\", \"secondary_key\" : \"xyz\" } }";
public static void main(String[] args) throws IOException {
ObjectMapper mapper = new ObjectMapper();
SimpleModule idAsRefModule = new SimpleModule("ID-to-ref");
idAsRefModule.addDeserializer(A.class, new AJsonDeserializer());
mapper.registerModule(idAsRefModule);
X tl = mapper.readValue(jsonA, X.class);
System.out.println(tl);
X t2 = mapper.readValue(jsonB, X.class);
System.out.println(t2);
}
public static class AJsonDeserializer extends JsonDeserializer<A>{
@Override
public A deserialize(JsonParser jp, DeserializationContext dc)
throws IOException {
ObjectCodec codec = jp.getCodec();
JsonNode node = codec.readTree(jp);
if (node.has("secondary_key")) {
return codec.treeToValue(node, B.class);
}
return new A(node.findValue("primary_key").asText());
}
}
public static class A
{
@JsonProperty("primary_key")
public final String primaryKey;
@JsonCreator
A(@JsonProperty("primary_key") String primaryKey)
{
this.primaryKey = primaryKey;
}
@Override
public String toString() {
return "A{" +
"primaryKey='" + primaryKey + '\'' +
'}';
}
}
public static class B extends A
{
@JsonProperty("secondary_key")
public final String secondaryKey;
@JsonCreator
B(@JsonProperty("primary_key") String primaryKey,
@JsonProperty("secondary_key") String secondaryKey)
{
super(primaryKey);
this.secondaryKey = secondaryKey;
}
@Override
public String toString() {
return "B{" +
"primaryKey='" + primaryKey + '\'' +
"secondaryKey='" + secondaryKey + '\'' +
'}';
}
}
public static class X
{
@JsonProperty("keys")
public final A keys;
@JsonCreator
X(@JsonProperty("keys") A keys)
{
this.keys = keys;
}
@Override
public String toString() {
return "X{" +
"keys=" + keys +
'}';
}
}
}
But you will have to create one more super class if you want to use default A deserializer or look here how you can solve this: https://stackoverflow.com/a/18405958/1032167
Upvotes: 1
Reputation: 4392
If I understoon correctly, simply passing the values will work, without any config. I believe this is what you are looking for:
public class Test {
private static final String JSON = "{\"keys\":{\"primary_key\":\"abc\",\"secondary_key\":\"xyz\"}}";
public static void main(String[] args) throws IOException {
ObjectMapper mapper = new ObjectMapper();
X x = mapper.readValue(JSON, X.class);
System.out.println(mapper.writeValueAsString(x));
}
}
class A {
private String primary_key;
public String getPrimary_key() {
return primary_key;
}
public void setPrimary_key(String primary_key) {
this.primary_key = primary_key;
}
}
class B extends A {
private String secondary_key;
public String getSecondary_key() {
return secondary_key;
}
public void setSecondary_key(String secondary_key) {
this.secondary_key = secondary_key;
}
}
class X {
private B keys;
public B getKeys() {
return keys;
}
public void setKeys(B keys) {
this.keys = keys;
}
}
Output will be:
{"keys":{"primary_key":"abc","secondary_key":"xyz"}}
In case this is not what you expect, please provide another explanation and I will edit the answer as needed.
Upvotes: 0