Question

I have a class defined as:

@JsonRootName(value = "component")
public class ComponentBean{
//...private variables....getters....settters....default constructor not shown for brevity

I use Springs java-based configuration for configuring my ObjectMapper as such:

@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
... other config not shown for brevity

    @Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> pArgumentResolvers) {
    pArgumentResolvers.add(this.getCurrentUserHandlerMethodArgumentResolver());
}

    @Bean
public ObjectMapper getJackson2ObjectMapperFactoryBean() {
    final Jackson2ObjectMapperFactoryBean mapper = new Jackson2ObjectMapperFactoryBean();

    mapper.setIndentOutput(true);
    mapper.setSimpleDateFormat("MM/dd/yyyy HH:mm:ss");

    mapper.setFeaturesToEnable(DeserializationFeature.UNWRAP_ROOT_VALUE);
    mapper.setFeaturesToDisable(SerializationFeature.INDENT_OUTPUT);
    mapper.setFeaturesToEnable(SerializationFeature.WRAP_ROOT_VALUE);

    final Map<Class<?>, JsonDeserializer<?>> deserializers = new HashMap<Class<?>, JsonDeserializer<?>>();
    deserializers.put(...) // customer deserializers -- ComponentBean is not one of them

    mapper.setDeserializersByType(deserializers);
    mapper.afterPropertiesSet();

    final ObjectMapper objectMapper = mapper.getObject();
    objectMapper.registerModule(new JodaModule()); // register custom joda time serializer

    return objectMapper;
}

@Bean
public MappingJackson2HttpMessageConverter getMappingJackson2HttpMessageConverter() {
    final MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
    converter.setObjectMapper(this.getJackson2ObjectMapperFactoryBean());

    return converter;
}

Configured with java, upon trying to create a new ComponentBean from my application I receive the exception:

Caused by: com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "component" (class com.package.components.ComponentBean), not marked as ignorable (11 known properties: ....all my the properties of the ComponentBean not shown....])

Now, this works they way I previously had it configured using an xml-based configuration, but I switched over to use java-based configuration -- this seems to be the only portion of my configuration I can't get to work properly.

My xml-based config is this:

    <mvc:annotation-driven>
    <mvc:argument-resolvers>
        <bean class="com.aoins.sales.user.CurrentUserHandlerMethodArgumentResolver" />
    </mvc:argument-resolvers>
    <mvc:message-converters>
        <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
            <property name="objectMapper" ref="objectMapper" />
        </bean>
    </mvc:message-converters>
</mvc:annotation-driven>

<bean id="objectMapper" class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean"
    p:indentOutput="true" p:simpleDateFormat="MM/dd/yyyy HH:mm:ss">
    <property name="featuresToEnable">
        <array>
            <util:constant static-field="com.fasterxml.jackson.databind.DeserializationFeature.UNWRAP_ROOT_VALUE" />
        </array>
    </property>
    <property name="featuresToDisable">
        <array>
            <util:constant static-field="com.fasterxml.jackson.databind.SerializationFeature.INDENT_OUTPUT" />
        </array>
    </property>
    <!-- Add deserializers that require autowiring -->
    <property name="deserializersByType">
        <map key-type="java.lang.Class">
            <entry key="...">
                <bean class="..." />
            </entry>
        </map>
    </property>
</bean>

My question is how to get this working properly with a java-based configuration. Am I missing an annotation for spring to recognize the json root? Is there another annotation I need to add for my ObjectMapper, additional settings, or do I just need to create a custom deserializer for my ComponentBean (I am trying to avoid creating a custom deserializer for ComponentBean because using the @JsonRootName should work)?

Some things to note, I do not want to ignore any of these properties because I need to use them all.

Was it helpful?

Solution

Figured it out. Turns out there was a method provided by the WeMvcConfigurer that I needed to override in order to resolve my message, otherwise default resolvers are used which was not my intention. Looking at the original xml we see:

    <mvc:message-converters>
    <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
        <property name="objectMapper" ref="objectMapper" />
    </bean>
</mvc:message-converters>

I correctly configured the MappingJackson2HttpMessageConverter as a Bean, but didn't pay close enough attention to what the xml was adding it to; the message-converter. Adding the following to my java-based configuration solved the problem.

    @Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
    converters.add(this.getMappingJackson2HttpMessageConverter());
}

Hope this help someone else, however, it was a simple overlook on my part. I guess that is one thing you always have to remember with Spring, they really remove a lot of old boilerplate code and that stung me this time.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top