Можно ли настроить Jackson для обрезки ведущего/конечного пробела из всех свойств строки?
Пример JSON (обратите внимание, что строка имеет завершающие пробелы):
{ "aNumber": 0, "aString": "string " }
В идеале десериализованный экземпляр имеет свойство aString со значением "строка" (т.е. без конечных пробелов). Это похоже на то, что, вероятно, поддерживается, но я не могу его найти (например, в DeserializationConfig.Feature).
Мы используем Spring MVC 3.x, поэтому решение на основе Spring также будет в порядке.
Я попытался настроить Spring WebDataBinder на основе предложения в сообщении , но, похоже, он не работает при использовании конвертера сообщений Jackson
@InitBinder
public void initBinder( WebDataBinder binder )
{
binder.registerCustomEditor( String.class, new StringTrimmerEditor( " \t\r\n\f", true ) );
}
Ответы
Ответ 1
С помощью настраиваемого десериализатора вы можете сделать следующее:
<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
Простое решение для пользователей 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 - добавить beans типа com.fasterxml.jackson.databind.Module в ваш контекст. Они будут зарегистрированы в каждом bean типа ObjectMapper, обеспечивая глобальный механизм внесения пользовательских модулей при добавлении новых функций в ваше приложение.
http://docs.spring.io/spring-boot/docs/current/reference/html/howto-spring-mvc.html#howto-customize-the-jackson-objectmapper
если вы используете не с помощью загрузки Spring, вам необходимо зарегистрировать StringTrimModule самостоятельно (вам не нужно комментировать его с помощью @Component)
<bean class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean">
<property name="modulesToInstall" value="com.example.StringTrimModule"/>
</bean
Ответ 3
Проблема аннотации @JsonDeserialize заключается в том, что вы всегда должны помнить, чтобы поставить ее на сеттер.
Чтобы сделать его глобально "раз и навсегда" с помощью 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>
Ответ 4
Для Spring Boot, нам просто нужно создать собственный десериализатор как задокументированный в руководстве.
Ниже приведен мой код 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
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);