Spring + Jackson + joda时间:如何指定序列化/反序列化格式? [英] Spring + Jackson + joda time: how to specify the serialization/deserialization format?

查看:274
本文介绍了Spring + Jackson + joda时间:如何指定序列化/反序列化格式?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

  public static class ARestRequestParam 
{
String name;
LocalDate日期; // joda类型
}

我想从下面的JSON反序列化是由jackson处理的。



{name:abc,date:20131217}

我想以任何类型的yyyyMMdd格式反序列化任何类的LocalDate字段,不需要重复格式字符串,也不需要添加任何setter方法,没有任何XML配置。 (也就是说,注释和Java代码是可取的)
怎么可以做到呢?

另外,我也想知道序列化部分。也就是LocalDate - >yyyyMMdd。



我看过以下内容:



但我不知道哪一个是适用的,哪一个最新。



顺便说一下,我使用Spring Boot。
$ b

更新

好吧,我已经设法编写反序列化部分的工作代码。
如下所示:



$ @ $ $ $ b $ EnableWebMvc
公共类WebMvcConfiguration扩展了WebMvcConfigurerAdapter
{
@Override
public void configureMessageConverters(
List< HttpMessageConverter<>>转换器)
{
converters.add(jacksonConverter() );

$ b $Be
public MappingJackson2HttpMessageConverter jacksonConverter()
{
MappingJackson2HttpMessageConverter转换器= $ b $新建MappingJackson2HttpMessageConverter();

ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new ApiJodaModule());
converter.setObjectMapper(mapper);

返回转换器;

$ b @SuppressWarnings(serial)
private class ApiJodaModule extends SimpleModule
{
public ApiJodaModule()
{
addDeserializer(LocalDate.class,新的ApiLocalDateDeserializer());


$ b @SuppressWarnings(serial)
private static class ApiLocalDateDeserializer
extends StdScalarDeserializer< LocalDate>
{
private static DateTimeFormatter formatter =
DateTimeFormat.forPattern(yyyyMMdd);

public ApiLocalDateDeserializer(){super(LocalDate.class); }
$ b $ @Override
public LocalDate反序列化(JsonParser jp,DeserializationContext ctxt)
抛出IOException,JsonProcessingException
{
if(jp.getCurrentToken()= = JsonToken.VALUE_STRING)
{
String s = jp.getText()。trim();
if(s.length()== 0)
return null;
返回LocalDate.parse(s,formatter);

throw ctxt.wrongTokenException(jp,JsonToken.NOT_AVAILABLE,
expected JSON Array,String or Number);





我必须实现解串器我自己,因为jackson-datatype-joda中的反序列化器的日期时间格式不能改变。所以,由于我自己实现了解串器,所以不需要jackson-datatype-joda。 (虽然我已经复制了它的代码)

这段代码是否正确?

这是最新的解决方案吗?

有没有其他更简单的方法?

任何建议将不胜感激。


$ b 更新

删除了两个方法:configureMessageConverters(),jacksonConverter ()

将以下方法添加到WebMvcConfiguration类中:




public模块apiJodaModule()
{
返回新的ApiJodaModule();
}

但现在不行。看来apiJodaModule()被忽略。

如何让它工作?

(看来我不应该有一个拥有@EnableWebMvc的类来使用这个特性。)



我使用的版本是org.springframework.boot:spring-boot-starter-web:0.5.0.M6。
$ b $最后的工作版本如下所示:(我之前在类中使用的其他配置有@EnableWebMvc )

正如Dave Syer所说,这只会在BUILD-SNAPSHOT版本上起作用,至少现在是这样。

  public class WebMvcConfiguration 
{
@Bean
public WebMvcConfigurerAdapter apiWebMvcConfiguration()
{
return new ApiWebMvcConfiguration();


$ Be $ b $ public UserInterceptor userInterceptor()
{
return new UserInterceptor();

$ b $ public class ApiWebMvcConfiguration extends WebMvcConfigurerAdapter
{
@Override
public void addInterceptors(InterceptorRegistry registry)
{
registry .addInterceptor(userInterceptor())
.addPathPatterns(/ api / user / **);

$ b @Override
public void addResourceHandlers(ResourceHandlerRegistry registry)
{
registry.addResourceHandler(/ **)
。 addResourceLocations(/)
.setCachePeriod(0);


$ b $Be
public Module apiJodaModule()
{
return new ApiJodaModule();

$ b @SuppressWarnings(serial)
private static class ApiJodaModule extends SimpleModule
{
public ApiJodaModule()
{
addDeserializer(LocalDate.class,新的ApiLocalDateDeserializer());
}

private static final class ApiLocalDateDeserializer
extends StdScalarDeserializer< LocalDate>
{
public ApiLocalDateDeserializer(){super(LocalDate.class); }
$ b $ @Override
public LocalDate反序列化(JsonParser jp,
DeserializationContext ctxt)
抛出IOException异常,JsonProcessingException异常
{
if(jp。 getCurrentToken()== JsonToken.VALUE_STRING)
{
String s = jp.getText()。trim();
if(s.length()== 0)
return null;
返回LocalDate.parse(s,localDateFormatter);
}
throw ctxt.mappingException(LocalDate.class);



private static DateTimeFormatter localDateFormatter =
DateTimeFormat.forPattern(yyyyMMdd);


$ / code $


解决方案

代码是可以的,但是如果在Spring Boot应用程序中使用 @EnableWebMvc ,则关闭框架中的默认设置,所以也许应该避免这种情况。另外,你现在在你的MVC处理器适配器中只有一个 HttpMessageConverter 。如果你使用Spring Boot的快照,你应该能够简单地定义 Module 类型的 @Bean 否则会自动,所以我会建议这样做。


I have the following class:

public static class ARestRequestParam
{
    String name;
    LocalDate date;  // joda type
}

And I want it to be deserialized from the following JSON which is processed by jackson.

{ name:"abc", date:"20131217" }

Actually, I want to deserialize any LocalDate field in any class with "yyyyMMdd" format, without duplicating the format string, without adding any setter method, without any XML configuration. (That is, annotation and Java code is preferable) How can it be done?

Also, I also want to know the serialization part. that is, LocalDate -> "yyyyMMdd".

I've seen followings:

But I don't know which is applicable, and which is most up-to-date.

BTW, I use Spring Boot.

UPDATE

Ok, I have managed to write working code for the deserialization part. It is as follows:

@Configuration
@EnableWebMvc
public class WebMvcConfiguration extends WebMvcConfigurerAdapter
{
    @Override
    public void configureMessageConverters(
        List<HttpMessageConverter<?>> converters)
    {
        converters.add(jacksonConverter());
    }

    @Bean
    public MappingJackson2HttpMessageConverter jacksonConverter()
    {
        MappingJackson2HttpMessageConverter converter =
            new MappingJackson2HttpMessageConverter();

        ObjectMapper mapper = new ObjectMapper();
        mapper.registerModule(new ApiJodaModule());
        converter.setObjectMapper(mapper);

        return converter;
    }

    @SuppressWarnings("serial")
    private class ApiJodaModule extends SimpleModule
    {
        public ApiJodaModule()
        {
            addDeserializer(LocalDate.class, new ApiLocalDateDeserializer());
        }
    }

    @SuppressWarnings("serial")
    private static class ApiLocalDateDeserializer
        extends StdScalarDeserializer<LocalDate>
    {
        private static DateTimeFormatter formatter =
            DateTimeFormat.forPattern("yyyyMMdd");

        public ApiLocalDateDeserializer() { super(LocalDate.class); }

        @Override
        public LocalDate deserialize(JsonParser jp, DeserializationContext ctxt)
            throws IOException, JsonProcessingException
        {
            if (jp.getCurrentToken() == JsonToken.VALUE_STRING)
            {
                String s = jp.getText().trim();
                if (s.length() == 0)
                    return null;
                return LocalDate.parse(s, formatter);
            }
            throw ctxt.wrongTokenException(jp, JsonToken.NOT_AVAILABLE,
                "expected JSON Array, String or Number");
        }
    }
}

I had to implement the deserializer myself, since the datetime format for the deserializer in jackson-datatype-joda cannot be altered. So, since I've implemented the deserializer myself, jackson-datatype-joda is not needed. (although I've copied pieces of its code)

Is this code Ok?
Is this up-to-date solution?
Is there any other easier way?
Any suggestion would be greatly appreciated.

UPDATE

Following Dave Syer's suggestion, I modified the source above as follows:

Removed 2 methods: configureMessageConverters(), jacksonConverter()
Added following method into WebMvcConfiguration class:

@Bean
public Module apiJodaModule()
{
    return new ApiJodaModule();
}

But now it does not work. It seems apiJodaModule() is ignored.
How can I make it work?
(It seems that I should not have a class that has @EnableWebMvc to use that feature.)

The version I use is org.springframework.boot:spring-boot-starter-web:0.5.0.M6.

UPDATE

Final working version is as follows: (with other configurations I've done previously in the class that had @EnableWebMvc)
As Dave Syer mentioned, this will only work on BUILD-SNAPSHOT version, at least for now.

@Configuration
public class WebMvcConfiguration
{
    @Bean
    public WebMvcConfigurerAdapter apiWebMvcConfiguration()
    {
        return new ApiWebMvcConfiguration();
    }

    @Bean
    public UserInterceptor userInterceptor()
    {
        return new UserInterceptor();
    }

    public class ApiWebMvcConfiguration extends WebMvcConfigurerAdapter
    {
        @Override
        public void addInterceptors(InterceptorRegistry registry)
        {
            registry.addInterceptor(userInterceptor())
                .addPathPatterns("/api/user/**");
        }

        @Override
        public void addResourceHandlers(ResourceHandlerRegistry registry)
        {
            registry.addResourceHandler("/**")
                .addResourceLocations("/")
                .setCachePeriod(0);
        }
    }

    @Bean
    public Module apiJodaModule()
    {
        return new ApiJodaModule();
    }

    @SuppressWarnings("serial")
    private static class ApiJodaModule extends SimpleModule
    {
        public ApiJodaModule()
        {
            addDeserializer(LocalDate.class, new ApiLocalDateDeserializer());
        }

        private static final class ApiLocalDateDeserializer
            extends StdScalarDeserializer<LocalDate>
        {
            public ApiLocalDateDeserializer() { super(LocalDate.class); }

            @Override
            public LocalDate deserialize(JsonParser jp,
                DeserializationContext ctxt)
                throws IOException, JsonProcessingException
            {
                if (jp.getCurrentToken() == JsonToken.VALUE_STRING)
                {
                    String s = jp.getText().trim();
                    if (s.length() == 0)
                        return null;
                    return LocalDate.parse(s, localDateFormatter);
                }
                throw ctxt.mappingException(LocalDate.class);
            }
        }

        private static DateTimeFormatter localDateFormatter =
            DateTimeFormat.forPattern("yyyyMMdd");
    }
}

解决方案

Your code is OK, but if you use @EnableWebMvc in a Spring Boot app you switch off the default settings in the framework, so maybe you should avoid that. Also, you now have only one HttpMessageConverter in your MVC handler adapter. If you use a snapshot of Spring Boot you ought to be able to simply define a @Bean of type Module and everything else would be automatic, so I would recommend doing it that way.

这篇关于Spring + Jackson + joda时间:如何指定序列化/反序列化格式?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆