Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Jackson Jaxb Annotation Precedence - @JsonProperty overriding @XmlTransient

Tags:

json

jaxb

jackson

I am using Jackson (2.1.1) for JSON serialization/deserialization. I have an existing class with JAXB annotations. Most of these annotations are correct and can be used as-is with jackson. I am using mix-ins to slightly alter the deserialization/serialization of these classes.

In my ObjectMapper constructor I do the following:

setAnnotationIntrospector(AnnotationIntrospector.pair(
                 new JacksonAnnotationIntrospector(), 
                 new JaxbAnnotationIntrospector(getTypeFactory())));

Based on the above, the Jackson annotations have precedence over Jaxb, because of the order of the introspectors. This is based on the Jackson Jaxb docs. For fields that I want ignored, adding @JsonIgnore to the field in the mix-in is working fine. There are a couple of fields that are marked as @XmlTransient in the existing classes that I do not want ignored. I have tried add @JsonProperty to the field in the mix-in, but it doesn't seem to work.

Here is the original class:

public class Foo {
    @XmlTransient public String getBar() {...}
    public String getBaz() {...}
}

Here is the mix-in:

public interface FooMixIn {
    @JsonIgnore String getBaz(); //ignore the baz property
    @JsonProperty String getBar(); //override @XmlTransient with @JsonProperty
}

Any idea how to resolve this without modifying the original class?

I also tested adding @JsonProperty to the members instead of using mix-ins:

public class Foo {
    @JsonProperty @XmlTransient public String getBar() {...}
    @JsonIgnore public String getBaz() {...}
}

I seem to get the same behavior as I did with the mix-in. Unless @XmlTransient is removed, the property is ignored.

like image 548
kldavis4 Avatar asked Dec 28 '12 21:12

kldavis4


1 Answers

The issue is that the AnnotationIntrospectorPair.hasIgnoreMarker() method basically ignores the @JsonProperty if either introspector detects an ignore marker:

    public boolean hasIgnoreMarker(AnnotatedMember m) {
        return _primary.hasIgnoreMarker(m) || _secondary.hasIgnoreMarker(m);
    }

ref: github

A workaround is to subclass the JaxbAnnotationIntrospector to get the desired behavior:

public class CustomJaxbAnnotationIntrospector extends JaxbAnnotationIntrospector {
    public CustomJaxbAnnotationIntrospector(TypeFactory typeFactory) {
        super(typeFactory);
    }

    @Override
    public boolean hasIgnoreMarker(AnnotatedMember m) {
        if ( m.hasAnnotation(JsonProperty.class) ) {
            return false;
        } else {
            return super.hasIgnoreMarker(m);
        }
    }
}

Then just use the CustomJaxbAnnotationIntrospector in the AnnotationIntrospectorPair.

like image 92
kldavis4 Avatar answered Oct 19 '22 12:10

kldavis4