java Jackson是否可以配置为从所有字符串属性中删除前导/尾随空格?

zqdjd7g9  于 2022-12-02  发布在  Java
关注(0)|答案(7)|浏览(149)

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

{ "aNumber": 0, "aString": "string   " }

理想情况下,反序列化的示例应该有一个值为**“string”aString**属性(即没有尾随空格)。这似乎是可能支持的东西,但我找不到它(例如在 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 ) );
}
lhcgjxsq

lhcgjxsq1#

对于Sping 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中,从而在向应用程序添加新特性时提供一种全局机制来提供定制模块。
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
vwkv1x7d

vwkv1x7d2#

使用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属性将始终以这种方式序列化,并且您必须对希望以这种方式反序列化的每个属性进行注解。

3gtaxfhh

3gtaxfhh3#

我认为最好扩展默认StringDeserializer,因为它已经处理了一些特定情况(请参阅此处和此处),可供第三方库使用。下面您可以找到Sping Boot 的配置。这仅适用于Jackson2.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;
    }
}
uklbhaso

uklbhaso4#

注解@JsonDeserialize的问题是你必须始终记住把它放在setter上。为了用SpringMVC使它全局“一劳永逸”,我做了下面的步骤:
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>
zvms9eto

zvms9eto5#

对于 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
    }
}
niwlg2el

niwlg2el6#

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);
qnyhuwrf

qnyhuwrf7#

我向你提出以下建议:
首先,创建一个要修剪的模块,并将其放入类中:

import java.io.IOException;

import org.springframework.stereotype.Component;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.deser.std.StdScalarDeserializer;
import com.fasterxml.jackson.databind.module.SimpleModule;

@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 {
                return jsonParser.getValueAsString().trim();
            }
        });
    }
}

然后,创建一个类来配置Jackson并添加模块:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.ObjectMapper;

/**
 * Class used to configure Jackson
 */
@Configuration
public class JacksonConfiguration {

    @Bean
    public ObjectMapper objectMapper() {
        ObjectMapper mapper = new ObjectMapper();
        mapper.registerModule(new StringTrimModule());
        return mapper;
    }
}

就这样了

相关问题