Date format Mapping to JSON Jackson
我有一个来自API的日期格式,如下所示:
1 | "start_time":"2015-10-1 3:00 PM GMT+1:00" |
这是YYYY-DD-MM HH:MM am / pm GMT时间戳。
我将此值映射到POJO中的Date变量。 显然,它显示转换错误。
我想知道两件事:
从Jackson v2.0开始,你可以直接在Object成员上使用@JsonFormat注释;
What is the formatting I need to use to carry out conversion with Jackson? Is Date a good field type for this?
1 2 |
In general, is there a way to process the variables before they get mapped to Object members by Jackson? Something like, changing the format, calculations, etc.
是。您有几个选项,包括实现自定义
当然,有一种称为序列化和反序列化的自动方式,您可以使用pb2q中提到的特定注释(@ JsonSerialize,@ JsonDeserialize)来定义它。
您可以同时使用java.util.Date和java.util.Calendar
......也可能是JodaTime。
在反序列化过程中,@ JsonFormat注释对我不起作用(它已将时区调整为不同的值)(序列化工作完美):
1 2 3 |
如果您想要预测结果,则需要使用自定义序列化器和自定义反序列化器而不是@JsonFormat注释。我在http://www.baeldung.com/jackson-serialize-dates找到了真正好的教程和解决方案
日期字段有一些示例,但我需要日历字段,所以这是我的实现:
序列化程序类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | public class CustomCalendarSerializer extends JsonSerializer<Calendar> { public static final SimpleDateFormat FORMATTER = new SimpleDateFormat("yyyy-MM-dd HH:mm"); public static final Locale LOCALE_HUNGARIAN = new Locale("hu","HU"); public static final TimeZone LOCAL_TIME_ZONE = TimeZone.getTimeZone("Europe/Budapest"); @Override public void serialize(Calendar value, JsonGenerator gen, SerializerProvider arg2) throws IOException, JsonProcessingException { if (value == null) { gen.writeNull(); } else { gen.writeString(FORMATTER.format(value.getTime())); } } } |
反序列化器类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | public class CustomCalendarDeserializer extends JsonDeserializer<Calendar> { @Override public Calendar deserialize(JsonParser jsonparser, DeserializationContext context) throws IOException, JsonProcessingException { String dateAsString = jsonparser.getText(); try { Date date = CustomCalendarSerializer.FORMATTER.parse(dateAsString); Calendar calendar = Calendar.getInstance( CustomCalendarSerializer.LOCAL_TIME_ZONE, CustomCalendarSerializer.LOCALE_HUNGARIAN ); calendar.setTime(date); return calendar; } catch (ParseException e) { throw new RuntimeException(e); } } } |
以及上述类的用法:
1 2 3 4 5 6 7 8 | public class CalendarEntry { @JsonSerialize(using = CustomCalendarSerializer.class) @JsonDeserialize(using = CustomCalendarDeserializer.class) private Calendar calendar; // ... additional things ... } |
使用此实现,序列化和反序列化过程的执行连续产生原始值。
只使用@JsonFormat注释反序列化给出了不同的结果我认为因为库内部时区默认设置你不能用注释参数改变(这是我对Jackson库2.5.3和2.6.3版本的体验)。
这是使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | package bj.demo; import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.context.event.ApplicationReadyEvent; import org.springframework.context.ApplicationListener; import java.text.SimpleDateFormat; /** * Created by [email protected] at 2018/5/4 10:22 */ @SpringBootApplication public class BarApp implements ApplicationListener<ApplicationReadyEvent> { public static void main(String[] args) { SpringApplication.run(BarApp.class, args); } @Autowired private ObjectMapper objectMapper; @Override public void onApplicationEvent(ApplicationReadyEvent applicationReadyEvent) { objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX")); } } |
为我工作SpringBoot。
1 2 3 4 | import com.alibaba.fastjson.annotation.JSONField; @JSONField(format ="yyyy-MM-dd HH:mm:ss") private Date createTime; |
输出:
1 2 3 | { "createTime":"2019-06-14 13:07:21" } |
我想指出,在另一个答案中描述的设置
但是对于
在我的情况下,为什么格式化程序不起作用并不是很明显,因为在应该序列化的模型中,字段实际上是
这是可能的,因为
1 |
所以这实际上是有效的
因此,如果您想知道为什么您的日期字段格式不正确,请确保该对象确实是
这里还提到了为什么不添加处理
This would then be breaking change, and I don't think that is warranted. If we were starting from scratch I would agree with the change, but as things are not so much.
如果有人在使用java.sql.Date的自定义日期格式时遇到问题,这是最简单的解决方案:
1 2 3 4 | ObjectMapper mapper = new ObjectMapper(); SimpleModule module = new SimpleModule(); module.addSerializer(java.sql.Date.class, new DateSerializer()); mapper.registerModule(module); |
(这个答案给我带来了很多麻烦:https://stackoverflow.com/a/35212795/3149048)
Jackson默认使用SqlDateSerializer作为java.sql.Date,但是目前,此序列化程序不考虑dateformat,请参阅此问题:https://github.com/FasterXML/jackson-databind/issues/1407。
解决方法是为java.sql.Date注册不同的序列化程序,如代码示例所示。
在@ miklov-kriven的非常有用的答案的基础上,我希望这两个额外的考虑点对某人有用:
(1)我发现在同一个类中包含序列化器和反序列化器作为静态内部类是个不错的主意。注意,使用ThreadLocal来实现SimpleDateFormat的线程安全性。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | public class DateConverter { private static final ThreadLocal<SimpleDateFormat> sdf = ThreadLocal.<SimpleDateFormat>withInitial( () -> {return new SimpleDateFormat("yyyy-MM-dd HH:mm a z");}); public static class Serialize extends JsonSerializer<Date> { @Override public void serialize(Date value, JsonGenerator jgen SerializerProvider provider) throws Exception { if (value == null) { jgen.writeNull(); } else { jgen.writeString(sdf.get().format(value)); } } } public static class Deserialize extends JsonDeserializer<Date> { @Overrride public Date deserialize(JsonParser jp, DeserializationContext ctxt) throws Exception { String dateAsString = jp.getText(); try { if (Strings.isNullOrEmpty(dateAsString)) { return null; } else { return new Date(sdf.get().parse(dateAsString).getTime()); } } catch (ParseException pe) { throw new RuntimeException(pe); } } } } |
(2)作为在每个单独的类成员上使用@JsonSerialize和@JsonDeserialize注释的替代方法,您还可以考虑通过在应用程序级别应用自定义序列化来覆盖Jackson的默认序列化,即所有类型为Date的类成员将由Jackson序列化使用此自定义序列化而不在每个字段上显式注释。例如,如果您使用Spring Boot,则执行此操作的方法如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | @SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } @Bean public Module customModule() { SimpleModule module = new SimpleModule(); module.addSerializer(Date.class, new DateConverter.Serialize()); module.addDeserializer(Date.class, new Dateconverter.Deserialize()); return module; } } |