杰克逊可以配置为从所有字符串属性修剪前导/尾随空格?

pen*_*old 39 java json spring-mvc jackson

示例JSON(请注意该字符串具有尾随空格):

{ "aNumber": 0, "aString": "string   " }
Run Code Online (Sandbox Code Playgroud)

理想情况下,反序列化的实例将具有值为"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 ) );
}
Run Code Online (Sandbox Code Playgroud)

Mac*_*zuk 20

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();
            }
        });
    }
}
Run Code Online (Sandbox Code Playgroud)

另一种自定义Jackson的方法是将com.fasterxml.jackson.databind.Module类型的bean添加到您的上下文中.它们将在ObjectMapper类型的每个bean中注册,为您的应用程序添加新功能时提供全局机制来贡献自定义模块.

http://docs.spring.io/spring-boot/docs/current/reference/html/howto-spring-mvc.html#howto-customize-the-jackson-objectmapper

如果你没有使用spring boot,你必须自己注册StringTrimModule(你不需要用@Component注释它)

<bean class="org.springframework.http.converter.json.Jackson2Objec??tMapperFactoryBean">
    <property name="modulesToInstall" value="com.example.StringTrimModule"/>
</bean
Run Code Online (Sandbox Code Playgroud)

  • 标准字符串反序列化器的作用不仅仅是调用 jsonParser.getValueAsString()。另外,您不需要创建一个模块并使用@Component注册它,您只需编写一个反序列化器并向其添加@JsonComponent即可: `@JsonComponent class TrimStringDeserializer extends StringDeserializer { @Override String deserialize(JsonParser jsonParser, DeserializationContext ctx)抛出 IOException { String text = super.deserialize(jsonParser, ctx) return text != null ? text.trim() : 文本 } }` (3认同)

DCK*_*ing 18

使用自定义反序列化器,您可以执行以下操作:

 <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();
     }
 }
Run Code Online (Sandbox Code Playgroud)

这个解决方案确实暗示这个bean属性将始终以这种方式序列化,并且您必须以这种方式注释要反序列化的每个属性.

  • @DCKing:为什么不通过模块接口全局注册您的自定义解串器?当 Jackson 仅用于 RESTful Web 服务时,我想不出在典型的 Spring 应用程序中会产生任何不良后果,你能吗? (3认同)

wal*_*alv 15

@JsonDeserialize注释的问题是你必须始终记得把它放在setter上.为了使用Spring MVC全局"永远",我做了下一步:

pom.xml中:

<dependency>
   <groupId>com.fasterxml.jackson.core</groupId>
   <artifactId>jackson-databind</artifactId>
   <version>2.3.3</version>
</dependency>
Run Code Online (Sandbox Code Playgroud)

创建自定义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());
                }
            });
        }
    }
Run Code Online (Sandbox Code Playgroud)

更新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>
Run Code Online (Sandbox Code Playgroud)


Eug*_*yuk 12

我认为最好扩展默认的 StringDeserializer,因为它已经处理了第三方库可以使用的一些特定情况(参见此处此处)。您可以在下面找到 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;
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 很好的答案,“trim()”可以用 Java 11 [`strip()`](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/ lang/String.html#strip()) 根据 `Character.isWhitespace()` 涵盖了所有可能的空白类型。 (2认同)

ada*_*shr 7

对于 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
    }
}
Run Code Online (Sandbox Code Playgroud)


van*_*102 6

com.fasterxml.jackson.dataformat

pom.xml

   <dependency>
      <groupId>com.fasterxml.jackson.dataformat</groupId>
      <artifactId>jackson-dataformat-csv</artifactId>
      <version>2.5.3</version>
    </dependency>
Run Code Online (Sandbox Code Playgroud)

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);
Run Code Online (Sandbox Code Playgroud)