Подтвердить что ты не робот

Можно ли настроить 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 ) );
}
4b9b3361

Ответ 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.Jackson2Objec‌​tMapperFactoryBean">
    <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);