104

I have a spring webservice that returns a json response. I'm using the example given here to create the service: http://www.mkyong.com/spring-mvc/spring-3-mvc-and-json-example/

The format the json is returned in is: {"name":null,"staffName":["kfc-kampar","smith"]}

I want to remove any null objects from the returned response so it looks like this: {"staffName":["kfc-kampar","smith"]}

I've found similar questions asked here but I've been able to get a solution working e.g.

Configuring ObjectMapper in Spring

How to configure MappingJacksonHttpMessageConverter while using spring annotation-based configuration?

configuring the jacksonObjectMapper not working in spring mvc 3

how to configure spring mvc 3 to not return "null" object in json response?

Spring configure @ResponseBody JSON format

Jackson+Spring3.0.5 custom object mapper

From reading through these and other sources, I figured the cleanest way to achieve what I wanted was to use Spring 3.1 and the message-converters that can be configured within the mvc-annotation. My updated spring config file is:

<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
    http://www.springframework.org/schema/beans     
    http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
    http://www.springframework.org/schema/context 
    http://www.springframework.org/schema/context/spring-context-3.1.xsd
    http://www.springframework.org/schema/mvc
    http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd">

<context:component-scan base-package="com.mkyong.common.controller" />

<mvc:annotation-driven>
    <mvc:message-converters>
        <bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
            <property name="prefixJson" value="true" />
            <property name="supportedMediaTypes" value="application/json" />
            <property name="objectMapper">
                <bean class="org.codehaus.jackson.map.ObjectMapper">
                    <property name="serializationInclusion" value="NON_NULL"/>
                </bean>
            </property>
        </bean>
    </mvc:message-converters>
</mvc:annotation-driven>

The service class is the same as given on the mkyong.com site, except I commented out the setting of the Shop name variable so it's null i.e.

@Controller
@RequestMapping("/kfc/brands")
public class JSONController {
    @RequestMapping(value="{name}", method = RequestMethod.GET)
    @ResponseStatus(HttpStatus.OK) 
    public @ResponseBody Shop getShopInJSON(@PathVariable String name) {
        Shop shop = new Shop();
        //shop.setName(name);
        shop.setStaffName(new String[]{name, "cronin"});
        return shop;
    }
}

The Jackson jars I'm using are jackson-mapper-asl 1.9.0 and jackson-core-asl 1.9.0. These are the only new jars I've added to the pom as provided as part of the spring-json project I downloaded from mkyong.com.

The project builds successfully, but when I invoke the service through the browser I still get the same thing i.e. {"name":null,"staffName":["kfc-kampar","smith"]}

Can anyone tell me where I'm going wrong with my configuration?

I've tried several other options, but the only way I've been able to return the json in the correct format is to add the Object mapper to the JSONController and have the "getShopInJSON" method return a string i.e.

public @ResponseBody String getShopInJSON(@PathVariable String name) throws JsonGenerationException, JsonMappingException, IOException {
    ObjectMapper mapper = new ObjectMapper();
    mapper.setSerializationInclusion(JsonSerialize.Inclusion.NON_NULL);

    Shop shop = new Shop();
    //shop.setName(name);
    shop.setStaffName(new String[]{name, "cronin"});
    String test = mapper.writeValueAsString(shop);
    return test;
}

Now if I invoke the service I get the expected i.e. {"staffName":["kfc-kampar","cronin"]}

I've also been able to get it to work using the @JsonIgnore annotation, but this solution isn't suitable for me.

I don't understand why it's working in code but not in the configuration, so any help would be fantastic.

2
  • 1
    For me It seemed spring is not using the mapper object that defined in the contex file, i checked with debug spring is calling setSerializationInclusion() method for mapper object defined in xml Commented Oct 3, 2012 at 12:32
  • 1
    Ya that's how I understand it also. The object mapper appears to be configured correctly, it's just not being used in the spring container. Commented Oct 3, 2012 at 13:57

11 Answers 11

149

Since Jackson 2.0 you can use JsonInclude

@JsonInclude(Include.NON_NULL)
public class Shop {
    //...
}
Sign up to request clarification or add additional context in comments.

Comments

127

Since Jackson is being used, you have to configure that as a Jackson property. In the case of Spring Boot REST services, you have to configure it in application.properties or application.yml:

spring.jackson.default-property-inclusion = NON_NULL

source

6 Comments

unfortunatelly, a moderator deleted my answer claiming those were repeated questions. But he's a Python guy and perhaps couldn't see those were different Java Spring questions (one for Spring MVC, other for Spring REST). He deleted the one in the most important question. BTW, there's no way to tailer. The answers are the same. The library is the same (Jackson). I'll try again, to help community.
The property name has changed to spring.jackson.default-property-inclusion=NON_NULL. Works fine!
Cool, this one I was looking for. No need to change all POJOs and have it at one place. Thank you for saving my time!
This is quite possibly the best answer I have seen on SO for some time.
this actually removes the key completely, how about replacing it with an empty string?
|
15
@JsonSerialize(include=JsonSerialize.Inclusion.NON_EMPTY)
public class Shop {
    //...
}

for jackson 2.0 or later use @JsonInclude(Include.NON_NULL)

This will remove both empty and null Objects.

1 Comment

@Deprecated // since 2.0, marked deprecated in 2.6
11

Setting the spring.jackson.default-property-inclusion=non_null option is the simplest solution and it works well.

However, be careful if you implement WebMvcConfigurer somewhere in your code, then the property solution will not work and you will have to setup NON_NULL serialization in the code as the following:

@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
    // some of your config here...

    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
        MappingJackson2HttpMessageConverter jsonConverter = new MappingJackson2HttpMessageConverter(objectMapper);
        converters.add(jsonConverter);
    }
}

1 Comment

Thanks for mentioning the impact on the property when WebMvcConfigurer is implemented. It solved my issue.
5

If you are using Jackson 2, the message-converters tag is:

<mvc:annotation-driven>
    <mvc:message-converters>
        <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
            <property name="prefixJson" value="true"/>
            <property name="supportedMediaTypes" value="application/json"/>
            <property name="objectMapper">
                <bean class="com.fasterxml.jackson.databind.ObjectMapper">
                    <property name="serializationInclusion" value="NON_NULL"/>
                </bean>
            </property>
        </bean>
    </mvc:message-converters>
</mvc:annotation-driven>

Comments

5

Since version 1.6 we have new annotation JsonSerialize (in version 1.9.9 for example).

Example:

@JsonSerialize(include=Inclusion.NON_NULL)
public class Test{
...
}

Default value is ALWAYS.

In old versions you can use JsonWriteNullProperties, which is deprecated in new versions. Example:

@JsonWriteNullProperties(false)
public class Test{
    ...
}

1 Comment

@JsonSerialize(include=Inclusion.NON_NULL) deprecated
5

As of Jackson 2.0, @JsonSerialize(include = xxx) has been deprecated in favour of @JsonInclude

Comments

4

For all you non-xml config folks:

ObjectMapper objMapper = new ObjectMapper().setSerializationInclusion(JsonInclude.Include.NON_NULL);
HttpMessageConverter msgConverter = new MappingJackson2HttpMessageConverter(objMapper);
restTemplate.setMessageConverters(Collections.singletonList(msgConverter));

Comments

1

You can use JsonWriteNullProperties for older versions of Jackson.

For Jackson 1.9+, use JsonSerialize.include.

Comments

0

I've found a solution through configuring the Spring container, but it's still not exactly what I wanted.

I rolled back to Spring 3.0.5, removed and in it's place I changed my config file to:

    <bean
    class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
    <property name="messageConverters">
        <list>
            <bean
                class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
                <property name="objectMapper" ref="jacksonObjectMapper" />
            </bean>
        </list>
    </property>
</bean>


<bean id="jacksonObjectMapper" class="org.codehaus.jackson.map.ObjectMapper" />
<bean id="jacksonSerializationConfig" class="org.codehaus.jackson.map.SerializationConfig"
    factory-bean="jacksonObjectMapper" factory-method="getSerializationConfig" />
<bean
    class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
    <property name="targetObject" ref="jacksonSerializationConfig" />
    <property name="targetMethod" value="setSerializationInclusion" />
    <property name="arguments">
        <list>
            <value type="org.codehaus.jackson.map.annotate.JsonSerialize.Inclusion">NON_NULL</value>
        </list>
    </property>
</bean>

This is of course similar to responses given in other questions e.g.

configuring the jacksonObjectMapper not working in spring mvc 3

The important thing to note is that mvc:annotation-driven and AnnotationMethodHandlerAdapter cannot be used in the same context.

I'm still unable to get it working with Spring 3.1 and mvc:annotation-driven though. A solution that uses mvc:annotation-driven and all the benefits that accompany it would be far better I think. If anyone could show me how to do this, that would be great.

Comments

0

You can also use configuration class with object mapper Bean. So in your response in API you will see only not null values

@Configuration
public class ObjectMapperConfiguration {

    @Bean
    public Jackson2ObjectMapperBuilderCustomizer getObjectMapper() {
        return builder -> builder.serializationInclusion(JsonInclude.Include.NON_NULL);
    }
}

1 Comment

Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.