Can Jackson be configured to trim leading/trailing whitespace from all string properties?
Easy solution for Spring Boot users, just add that walv's SimpleModule extension to your application context:
package com.example;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.deser.std.StdScalarDeserializer;
import com.fasterxml.jackson.databind.module.SimpleModule;
import org.springframework.stereotype.Component;
import java.io.IOException;
@Component
public class StringTrimModule extends SimpleModule {
public StringTrimModule() {
addDeserializer(String.class, new StdScalarDeserializer<String>(String.class) {
@Override
public String deserialize(JsonParser jsonParser, DeserializationContext ctx) throws IOException,
JsonProcessingException {
return jsonParser.getValueAsString().trim();
}
});
}
}
Another way to customize Jackson is to add beans of type com.fasterxml.jackson.databind.Module to your context. They will be registered with every bean of type ObjectMapper, providing a global mechanism for contributing custom modules when you add new features to your application.
http://docs.spring.io/spring-boot/docs/current/reference/html/howto-spring-mvc.html#howto-customize-the-jackson-objectmapper
if you are not using spring boot, you have to register the StringTrimModule yourself (you do not need to annotate it with @Component)
<bean class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean">
<property name="modulesToInstall" value="com.example.StringTrimModule"/>
</bean
With a custom deserializer, you could do the following:
<your bean>
@JsonDeserialize(using=WhiteSpaceRemovalSerializer.class)
public void setAString(String aString) {
// body
}
<somewhere>
public class WhiteSpaceRemovalDeserializer extends JsonDeserializer<String> {
@Override
public String deserialize(JsonParser jp, DeserializationContext ctxt) {
// This is where you can deserialize your value the way you want.
// Don't know if the following expression is correct, this is just an idea.
return jp.getCurrentToken().asText().trim();
}
}
This solution does imply that this bean attribute will always be serialized this way, and you will have to annotate every attribute that you want to be deserialized this way.
The problem of annotation @JsonDeserialize is that you must always remember to put it on the setter. To make it globally "once and forever" with Spring MVC, I did next steps:
pom.xml:
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.3.3</version>
</dependency>
Create custom ObjectMapper:
package com.mycompany;
import java.io.IOException;
import org.apache.commons.lang3.StringUtils;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.deser.std.StdScalarDeserializer;
import com.fasterxml.jackson.databind.module.SimpleModule;
public class MyObjectMapper extends ObjectMapper {
public MyObjectMapper() {
registerModule(new MyModule());
}
}
class MyModule extends SimpleModule {
public MyModule() {
addDeserializer(String.class, new StdScalarDeserializer<String> (String.class) {
@Override
public String deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException,
JsonProcessingException {
return StringUtils.trim(jp.getValueAsString());
}
});
}
}
Update Spring's servlet-context.xml:
<bean id="objectMapper" class="com.mycompany.MyObjectMapper" />
<mvc:annotation-driven>
<mvc:message-converters>
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="objectMapper" ref="objectMapper" />
</bean>
</mvc:message-converters>
</mvc:annotation-driven>