2

I have a use-case where I need to maintain two sets of JSON output, one with pretty names for the JSON property and one without. So I decided to customize my ObjectMapper so that it ignores the @JsonProperty("pretty name") annotation on the fields and uses the field property names. In this case would like the following JSON output

{"result":{"data":[{"totalUsers":12345,"totalBooks":883}]}}

The JSON output with pretty names would like like follows

{"result":{"data":[{"Total Users":12345,"Total Books":883}]}}

My ObjectMapper configuration code looks like

ObjectMapper mapper = new ObjectMapper();
mapper.setSerializationInclusion(Include.NON_EMPTY);
mapper.setSerializationInclusion(Include.NON_NULL);
mapper.configure(MapperFeature.USE_WRAPPER_NAME_AS_PROPERTY_NAME, true);
mapper.configure(SerializationFeature.WRAP_ROOT_VALUE, true);
mapper.configure(MapperFeature.USE_ANNOTATIONS, false);
mapper.setVisibility(PropertyAccessor.FIELD, Visibility.NONE)
        .setVisibility(PropertyAccessor.GETTER, Visibility.ANY);

I have looked at a few other answers on SO which didn't work for me. I get an NPE. Please see the following stacktrace

java.lang.NullPointerException
at com.fasterxml.jackson.databind.introspect.POJOPropertiesCollector._renameWithWrappers(POJOPropertiesCollector.java:728)
at com.fasterxml.jackson.databind.introspect.POJOPropertiesCollector.collect(POJOPropertiesCollector.java:264)
at com.fasterxml.jackson.databind.introspect.BasicClassIntrospector.collectProperties(BasicClassIntrospector.java:142)
at com.fasterxml.jackson.databind.introspect.BasicClassIntrospector.forSerialization(BasicClassIntrospector.java:68)
at com.fasterxml.jackson.databind.introspect.BasicClassIntrospector.forSerialization(BasicClassIntrospector.java:11)
at com.fasterxml.jackson.databind.SerializationConfig.introspect(SerializationConfig.java:490)
at com.fasterxml.jackson.databind.ser.BeanSerializerFactory.createSerializer(BeanSerializerFactory.java:131)
at com.fasterxml.jackson.databind.ser.SerializerFactory.createSerializer(SerializerFactory.java:53)
at com.fasterxml.jackson.databind.SerializerProvider._createUntypedSerializer(SerializerProvider.java:935)
at com.fasterxml.jackson.databind.SerializerProvider._createAndCacheUntypedSerializer(SerializerProvider.java:892)
at com.fasterxml.jackson.databind.SerializerProvider.findValueSerializer(SerializerProvider.java:429)
at com.fasterxml.jackson.databind.SerializerProvider.findTypedValueSerializer(SerializerProvider.java:520)
at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:99)
at com.fasterxml.jackson.databind.ObjectWriter.writeValue(ObjectWriter.java:457)
at com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider.writeTo(JacksonJsonProvider.java:583)
at org.apache.cxf.jaxrs.utils.JAXRSUtils.writeMessageBody(JAXRSUtils.java:1173)
at org.apache.cxf.jaxrs.interceptor.JAXRSOutInterceptor.serializeMessage(JAXRSOutInterceptor.java:259)
at org.apache.cxf.jaxrs.interceptor.JAXRSOutInterceptor.processResponse(JAXRSOutInterceptor.java:155)
at org.apache.cxf.jaxrs.interceptor.JAXRSOutInterceptor.handleMessage(JAXRSOutInterceptor.java:86)
at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:271)
at org.apache.cxf.interceptor.OutgoingChainInterceptor.handleMessage(OutgoingChainInterceptor.java:77)
at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:271)
at org.apache.cxf.transport.ChainInitiationObserver.onMessage(ChainInitiationObserver.java:121)
at org.apache.cxf.transport.http.AbstractHTTPDestination.invoke(AbstractHTTPDestination.java:238)
at org.apache.cxf.transport.servlet.ServletController.invokeDestination(ServletController.java:222)
at org.apache.cxf.transport.servlet.ServletController.invoke(ServletController.java:163)
at org.apache.cxf.transport.servlet.ServletController.invoke(ServletController.java:137)
at org.apache.cxf.transport.servlet.CXFNonSpringServlet.invoke(CXFNonSpringServlet.java:158)
at org.apache.cxf.transport.servlet.AbstractHTTPServlet.handleRequest(AbstractHTTPServlet.java:239)
at org.apache.cxf.transport.servlet.AbstractHTTPServlet.doGet(AbstractHTTPServlet.java:164)

The problem is in this line of code in at

com.fasterxml.jackson.databind.introspect.POJOPropertiesCollector._renameWithWrappers(POJOPropertiesCollector.java:728) 

where _annotationIntrospector is null

PropertyName wrapperName = _annotationIntrospector.findWrapperName(member);

Not quite sore what should I do to acheieve my goal. Any advice? Thanks.

andthereitgoes
  • 263
  • 1
  • 6
  • 15
  • 1
    Just a thought: Did you consider to use mixin-annotations for the pretty printed JSON instead? (Maybe I find time tomorrow to look into your actual problem.) – nutlike Mar 06 '13 at 19:42
  • I did a short test and obviously `mapper.configure(MapperFeature.USE_ANNOTATIONS, false);` clashes with `mapper.configure(MapperFeature.USE_WRAPPER_NAME_AS_PROPERTY_NAME, true);` and `mapper.setVisibility(PropertyAccessor.FIELD, Visibility.NONE).setVisibility(PropertyAccessor.GETTER, Visibility.ANY);`. Right now I cannot think of an easy way to fix that without messing around with Jackson's library. For another approach to solve your use-case look into my previous post. – nutlike Mar 08 '13 at 09:08
  • @nutlike- Thanks. No I have not tried mixin-annotations, but will give them a go. – andthereitgoes Mar 08 '13 at 15:30
  • Added a small example as answer, I hope it helps you to get started. – nutlike Mar 08 '13 at 15:44

1 Answers1

3

Small example to show a solution for your use-case with mixins:

class Data {
    int totalUsers;
    int totalBooks;
}

class DataMixin {
    @JsonProperty("Total Users")
    int totalUsers;
    @JsonProperty("Total Books")
    int totalBooks;
}

Jackson 2.0 - 2.4 (deprecated in 2.5)

ObjectMapper mapper = new ObjectMapper();
if (pretty) {
    mapper.addMixInAnnotations(Data.class, DataMixin.class);
}

Jackson 2.5+

ObjectMapper mapper = new ObjectMapper();
if (pretty) {
    mapper.addMixin(Data.class, DataMixin.class);
}
Thunderforge
  • 19,637
  • 18
  • 83
  • 130
nutlike
  • 4,835
  • 1
  • 25
  • 33
  • 1
    Interestingly when I tried to use the example given on http://wiki.fasterxml.com/JacksonMixInAnnotations for this i.e setting it in a Module and using a SetUpContext. It didn't work for me. But I tried something simillar to the example you posted and it worked i.e not using the Module and just using mapper.addMixInAnnotations – andthereitgoes Mar 08 '13 at 17:42
  • Remember that you have to register the Module for Jackson to see it, i.e., use `objectMapper.registerModule(new MyMixInModule());` – Ted M. Young Jul 24 '13 at 17:38