{"id":1138,"date":"2013-09-10T07:59:15","date_gmt":"2013-09-10T06:59:15","guid":{"rendered":"http:\/\/www.thomaskeller.biz\/blog\/?p=1138"},"modified":"2021-12-01T12:57:59","modified_gmt":"2021-12-01T11:57:59","slug":"custom-polymorphic-type-handling-with-jackson","status":"publish","type":"post","link":"https:\/\/www.thomaskeller.biz\/blog\/2013\/09\/10\/custom-polymorphic-type-handling-with-jackson\/","title":{"rendered":"Custom polymorphic type handling with Jackson"},"content":{"rendered":"\n<p>Adding support for polymorphic types in Jackson is easy and <a rel=\"noreferrer noopener\" data-ss1638359459=\"1\" href=\"http:\/\/wiki.fasterxml.com\/JacksonPolymorphicDeserialization\" data-type=\"URL\" data-id=\"http:\/\/wiki.fasterxml.com\/JacksonPolymorphicDeserialization\" target=\"_blank\">well-documented here<\/a>. But what if neither the Class-based nor the property-based (<code>@JsonSubType<\/code>) default type ID resolvers are fitting your use case?<\/p>\n\n\n\n<p>Enter custom type ID resolvers! In my case a server returned an identifier for a <code>Command<\/code> that I wanted to match one-to-one on a specific &#8220;Sub-Command&#8221; class without having to configure each of these identifiers in a <code>@JsonSubType<\/code> configuration. Furthermore each of these sub-commands should live in the <code>.command<\/code> package beneath the base command class. So here is what I came up with:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>@JsonTypeInfo(\n    use = JsonTypeInfo.Id.CUSTOM, \n    include = JsonTypeInfo.As.PROPERTY,\n    property = \"command\"\n)\n@JsonTypeIdResolver(CommandTypeIdResolver.class)\npublic abstract class Command {\n    \/\/ common properties here\n}<\/code><\/pre>\n\n\n\n<p>The important part beside the additional <code>@JsonTypeIdResolver<\/code> annotation is the <code>use<\/code> argument that is set to <code>JsonTypeInfo.Id.CUSTOM<\/code>. Normally you&#8217;d use <code>JsonTypeInfo.Id.CLASS<\/code> or <code>JsonTypeInfo.Id.NAME<\/code>. Lets see how the <code>CommandTypeIdResolver<\/code> is implemented:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>public class CommandTypeIdResolver implements TypeIdResolver {\n    private static final String COMMAND_PACKAGE = Command.class.getPackage().getName() + \".command\";\n    private JavaType mBaseType;\n    @Override\n    public void init(JavaType baseType) {\n        mBaseType = baseType;\n    }\n\n    @Override\n    public Id getMechanism() {\n        return Id.CUSTOM;\n    }\n\n    @Override\n    public String idFromValue(Object obj) {\n        return idFromValueAndType(obj, obj.getClass());\n    }\n\n    @Override\n    public String idFromBaseType() {\n        return idFromValueAndType(null, mBaseType.getRawClass());\n    }\n\n    @Override\n    public String idFromValueAndType(Object obj, Class clazz) {\n        String name = clazz.getName();\n        if (name.startsWith(COMMAND_PACKAGE)) {\n            return name.substring(COMMAND_PACKAGE.length() + 1);\n        }\n        throw new IllegalStateException(\"class \" + clazz + \" is not in the package \" + COMMAND_PACKAGE);\n    }\n\n    @Override\n    public JavaType typeFromId(String type) {\n        Class&lt;?> clazz;\n        String clazzName = COMMAND_PACKAGE + \".\" + type;\n        try {\n            clazz = ClassUtil.findClass(clazzName);\n        } catch (ClassNotFoundException e) {\n            throw new IllegalStateException(\"cannot find class '\" + clazzName + \"'\");\n        }\n        return TypeFactory.defaultInstance().constructSpecializedType(mBaseType, clazz);\n    }\n}<\/code><\/pre>\n\n\n\n<p>The two most important methods here are <code>idFromValueAndType<\/code> and <code>typeFromId<\/code>. For the first I get the class name of the class to serialize and check whether it is in the right package (the <code>.command<\/code> package beneath the package where the <code>Command<\/code> class resides). If this is the case, I strip-off the package path and return that to the serializer. For the latter method I go the other way around: I try to load the class with Jackson&#8217;s <code>ClassUtil<\/code>s by using the class name I got from the deserializer and prepend the expected package name in front of it. And thats already it!<\/p>\n\n\n\n<p>Thanks to the nice folks at the <a href=\"http:\/\/xircles.codehaus.org\/lists\/user@jackson.codehaus.org\" data-type=\"URL\" data-id=\"http:\/\/xircles.codehaus.org\/lists\/user@jackson.codehaus.org\" target=\"_blank\" rel=\"noreferrer noopener\">Jackson User Mailing List<\/a> for pointing me into the right direction!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Adding support for polymorphic types in Jackson is easy and well-documented here. But what if neither the Class-based nor the property-based (@JsonSubType) default type ID resolvers are fitting your use case? Enter custom type ID resolvers! In my case a server returned an identifier for a Command that I wanted to match one-to-one on a &hellip; <a href=\"https:\/\/www.thomaskeller.biz\/blog\/2013\/09\/10\/custom-polymorphic-type-handling-with-jackson\/\" class=\"more-link\">Continue reading <span class=\"screen-reader-text\">Custom polymorphic type handling with Jackson<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-1138","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/www.thomaskeller.biz\/blog\/wp-json\/wp\/v2\/posts\/1138","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.thomaskeller.biz\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.thomaskeller.biz\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.thomaskeller.biz\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.thomaskeller.biz\/blog\/wp-json\/wp\/v2\/comments?post=1138"}],"version-history":[{"count":7,"href":"https:\/\/www.thomaskeller.biz\/blog\/wp-json\/wp\/v2\/posts\/1138\/revisions"}],"predecessor-version":[{"id":1426,"href":"https:\/\/www.thomaskeller.biz\/blog\/wp-json\/wp\/v2\/posts\/1138\/revisions\/1426"}],"wp:attachment":[{"href":"https:\/\/www.thomaskeller.biz\/blog\/wp-json\/wp\/v2\/media?parent=1138"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.thomaskeller.biz\/blog\/wp-json\/wp\/v2\/categories?post=1138"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.thomaskeller.biz\/blog\/wp-json\/wp\/v2\/tags?post=1138"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}