Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Tricky(?) JSON, polymorphic deserialization

I want to deserialize a piece of JSON using Jackson 2.x.

There's json that looks like this:

{
     "response":[
      230,
      {
         "id":1627,
         "from_id":4534,
         "attachments":[
            {
               "type":"audio",
               "audio":{
                  "aid":25918,
                  "owner_id":20000,
               }
            },
            {
               "type":"link",
               "link":{
                  "url":"http://lenta.ru",
                  "title":"bla"
               }
            }
         ]
      }
      ...
   ]
}

So I want to use Polymorphic Type Handling to deserialize attachments into List of Attachment's. I have following POJOs with Mixins:

public class Post {
    private final String id;
    private List<? extends Attachment> attachments;
    // ...
}

@JsonIgnoreProperties(ignoreUnknown = true)
public class PostMixin {
    @JsonProperty("id")
    String id;

    @JsonProperty("attachments")
    List<? extends Attachment> attachments;
    // ...
}

public abstract class Attachment {
    public static enum AttachmentType {
        AUDIO, LINK
    }

    private AttachmentType type;
    public AttachmentType getType() {
        return type;
    }
}

// Not sure here if using these annotations propper way
@JsonTypeInfo(use=JsonTypeInfo.Id.NAME,
include=JsonTypeInfo.As.PROPERTY, property = "type", visible = true)
@JsonSubTypes({
    @JsonSubTypes.Type(name="link", value=LinkAttachment.class),
    @JsonSubTypes.Type(name="audio", value=AudioAttachment.class)
})
@JsonIgnoreProperties(ignoreUnknown = true)
public class AttachmentMixin {
    @JsonProperty("type")
    @JsonDeserialize(using = AttachmentTypeDeserializer.class)
    Attachment.AttachmentType type;

    // parse type into enum
    private static class AttachmentTypeDeserializer extends
JsonDeserializer<Attachment.AttachmentType> {
        @Override
        public Attachment.AttachmentType deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException {
            return Attachment.AttachmentType.valueOf(jp.getText().toUpperCase());
        }
    }
}

public class LinkAttachment extends Attachment {
    private String url;
    private String title;

    public String getUrl() {
        return url;
    }
    public String getTitle() {
        return title;
    }
}

@JsonIgnoreProperties(ignoreUnknown = true)
public class LinkAttachmentMixin extends AttachmentMixin {
    @JsonProperty("url")
    String url;

    @JsonProperty("title")
    String title;
}

public class AudioAttachment extends Attachment {
    private String id;
    private String ownerId;

    public String getId() {
        return id;
    }
    public String getOwnerId() {
        return ownerId;
    }
}

@JsonIgnoreProperties(ignoreUnknown = true)
public class AudioAttachmentMixin extends AttachmentMixin {
    @JsonProperty("aid")
    private String id;

    @JsonProperty("owner_id")
    private String ownerId;
}

Created module to register Mixins:

public class MyModule extends SimpleModule {
    public MyModule() {
        super("MyModule");
    }

    @Override
    public void setupModule(SetupContext context) {
        context.setMixInAnnotations(Post.class, PostMixin.class);
        context.setMixInAnnotations(Attachment.class, AttachmentMixin.class);
        context.setMixInAnnotations(LinkAttachment.class, LinkAttachmentMixin.class);
        context.setMixInAnnotations(AudioAttachment.class,AudioAttachmentMixin.class);
    }
}

Initialize ObjectMapper:

objectMapper = new ObjectMapper();
objectMapper.registerModule(new MyModule());

When I try to deserialize JSON I get following exception:

java.lang.IllegalArgumentException: Class my.package.LinkAttachmentMixin is not assignable to my.package.Attachment
(through reference chain: my.package.Post["attachments"])

Is it possible to deserialize this JSON with Jackson Polymorphic Type Handling support? Do I need to write my own deserializers? Can someone give a good sample to start with? Is it possible at all to parse this JSON using annotations only?

like image 354
vkolodrevskiy Avatar asked Nov 11 '22 13:11

vkolodrevskiy


1 Answers

Try putting the @JsonTypeInfo and @JsonSubTypes annotations on your Attachment class instead of on the mixin. You might even be able to eliminate the mixins entirely by annotating the other classes properly. If you go that road then you'll probably have to annotate your VO classes/attributes and the AttachmentType with @JsonCreator.

Here's an article that describes deserialization similar to what you're trying to do. I've found it useful in the past for doing this sort of thing.

like image 117
Erik Gillespie Avatar answered Nov 13 '22 08:11

Erik Gillespie