Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Parse to a Subclass by default with Jackson

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.

like image 352
Tomás Duhourq Avatar asked Dec 16 '14 13:12

Tomás Duhourq


1 Answers

@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.

like image 178
Ilya Ovesnov Avatar answered Oct 22 '22 06:10

Ilya Ovesnov