Parse to a Subclass by default with Jackson
Asked Answered
R

1

20

I have a class called Product and some subclasses extending it. Now in my annotations I have many types, like this:

@JsonTypeInfo(use=JsonTypeInfo.Id.NAME, include=JsonTypeInfo.As.WRAPPER_OBJECT)
@JsonSubTypes({@Type(value=RoomProduct.class, name="RoomProduct"),
           @Type(value=GroundProduct.class, name="GroundProduct"),
           })

And then the definition of my Product class. What I want to do is if Jackson cannot detect that the field is not complying with any of these structures, to return an

UnknownProduct

How can I do that with Jackson @Type annotation? It should be something like putting blank in name or some flag in value which I don't really know (I have tried creating the UnknownProduct which extends Product and putting nothing in the name value with no success.

Ridicule answered 16/12, 2014 at 13:55 Comment(0)
M
47

@JsonTypeInfo has an option to specify default implementation class but after some debugging I found that 'defaultImpl' is broken for the WrapperObject. Configuration:

@JsonTypeInfo(use=JsonTypeInfo.Id.NAME, include= JsonTypeInfo.As.WRAPPER_OBJECT, defaultImpl = UnknownProduct.class)

Jackson implementation (AsWrapperTypeDeserializer):

public AsWrapperTypeDeserializer(JavaType bt, TypeIdResolver idRes,
        String typePropertyName, boolean typeIdVisible, Class<?> defaultImpl)
{
    super(bt, idRes, typePropertyName, typeIdVisible, null);
}

Note that 'defaultImpl' is passed but it is ignored and configured default class will NOT be used. I didn't find the logged ticket for this problem in jackson's Jira.

This is a problem ONLY for the WRAPPER_OBJECT, defaultImpl is working fine for other formats. But it will change JSON format. If you can change it -- you can use EXTERNAL_PROPERTY for example with default implementation:

@JsonTypeInfo(use=JsonTypeInfo.Id.NAME, include= JsonTypeInfo.As.EXTERNAL_PROPERTY, property = "type", defaultImpl = UnknownProduct.class)

Another solution: If you have to use WRAPPER_OBJECT then you can configure Jackson not to fail when it find unknown SubType:

objectMapper.configure(DeserializationFeature.FAIL_ON_INVALID_SUBTYPE, false);

It is not completely the same what you are asking but in that case your product will be null. Probably you can treat null as unknown product.

Update I've filed a Jackson bug: https://github.com/FasterXML/jackson-databind/issues/656

Update This ticket was resolved for 2.3 and 2.4 jackson and hopefully soon you should be able to use it when jars will be re-installed into the maven repository or in a new version.

Maible answered 17/12, 2014 at 8:36 Comment(7)
Not quite what I was looking for, though I tried it and still got the JsonMappingException. I know there is a defaultImpl that you can set in the @JsonTypeInfo, but I can't get it to work, my header is: @JsonTypeInfo(use=JsonTypeInfo.Id.NAME,include=JsonTypeInfo.As.WRAPPER_OBJECT,defaultImpl=UnknownProduct.class). Thanks Ilya!Yugoslav
It is working on my test application: no JsonMappingException and Project is resolved as null. If you post Product, RoomProduct, GroundProduct and the class where you do serializayion/deserialization -- I can take a lookMaible
I've found that WRAPPER_OBJECT has a bug which ignore the defaultImpl class. Please review the updated solution.Maible
@StaxMan This is a ticket that I have created today in Jackson Jira. Not sure what you wanted to say.Maible
Ah sorry, did not notice your updates above (had an old version open) that say what I meant. :)Anstus
Excellent work Illya! So, we just have to wait for the release, aye?Yugoslav
@TomD based on the previous releases I would say that you will have to wait about a month till you get the fix: search.maven.org/… (you can see it by dates). That fix will be in 2.4.5 version. Or if you don't want to wait -- use different inclusion typeMaible

© 2022 - 2024 — McMap. All rights reserved.