示例JSON(请注意该字符串具有尾随空格):
{ "aNumber": 0, "aString": "string " }
理想情况下,反序列化的实例将具有 aString 属性,其值为“string”(即没有尾随空格)。这似乎是可能支持的东西,但我找不到它(例如在 DeserializationConfig.Feature 中)。
我们正在使用Spring MVC 3.x,因此基于Spring的解决方案也可以。
我尝试根据forum post中的建议配置Spring的WebDataBinder,但在使用Jackson消息转换器时它似乎不起作用:
@InitBinder
public void initBinder( WebDataBinder binder )
{
binder.registerCustomEditor( String.class, new StringTrimmerEditor( " \t\r\n\f", true ) );
}
答案 0 :(得分:18)
Spring Boot用户的简单解决方案,只需将walv的SimpleModule扩展添加到您的应用程序上下文中:
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();
}
});
}
}
自定义Jackson的另一种方法是将com.fasterxml.jackson.databind.Module类型的bean添加到您的上下文中。它们将在ObjectMapper类型的每个bean中注册,为您的应用程序添加新功能时提供全局机制来提供自定义模块。
如果你不使用spring boot,你必须自己注册StringTrimModule(你不需要用@Component注释)
<bean class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean">
<property name="modulesToInstall" value="com.example.StringTrimModule"/>
</bean
答案 1 :(得分:15)
使用custom deserializer,您可以执行以下操作:
<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();
}
}
这个解决方案确实暗示这个bean属性将始终以这种方式序列化,并且您必须以这种方式注释要反序列化的每个属性。
答案 2 :(得分:13)
注释@JsonDeserialize的问题是你必须始终记得把它放在setter上。 为了使用Spring MVC全局“永远”,我做了下一步:
的pom.xml:
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.3.3</version>
</dependency>
创建自定义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());
}
});
}
}
更新Spring的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>
答案 3 :(得分:6)
我认为最好扩展默认的StringDeserializer,因为它已经处理了第三方库可以使用的某些特定情况(请参见here和here)。您可以在下面找到Spring Boot的配置。这仅适用于Jackson 2.9.0及更高版本,因为从2.9.0版本开始,StringDeserializer不再是最终版本。如果您的Jackson版本低于2.9.0,则仍可以将StringDeserializer的内容复制到代码中以处理上述情况。
@JsonComponent
public class StringDeserializer extends com.fasterxml.jackson.databind.deser.std.StringDeserializer {
@Override
public String deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
String value = super.deserialize(p, ctxt);
return value != null ? value.trim() : null;
}
}
答案 4 :(得分:3)
对于Spring Boot,我们只需要创建一个自定义反序列化器documented in the manual。
以下是我的Groovy代码,但可以随意使其适用于Java。
import com.fasterxml.jackson.core.JsonParser
import com.fasterxml.jackson.databind.DeserializationContext
import com.fasterxml.jackson.databind.JsonDeserializer
import org.springframework.boot.jackson.JsonComponent
import static com.fasterxml.jackson.core.JsonToken.VALUE_STRING
@JsonComponent
class TrimmingJsonDeserializer extends JsonDeserializer<String> {
@Override
String deserialize(JsonParser parser, DeserializationContext context) {
parser.hasToken(VALUE_STRING) ? parser.text?.trim() : null
}
}
答案 5 :(得分:2)
com.fasterxml.jackson.dataformat
pom.xml
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-csv</artifactId>
<version>2.5.3</version>
</dependency>
CsvUtil.java
CsvSchema bootstrapSchema = CsvSchema.emptySchema().withHeader().sortedBy();
CsvMapper mapper = new CsvMapper();
mapper.enable(CsvParser.Feature.TRIM_SPACES);
InputStream inputStream = ResourceUtils.getURL(fileName).openStream();
MappingIterator<T> readValues =
mapper.readerFor(type).with(bootstrapSchema).readValues(inputStream);