date格式映射到JSON Jackson
我有一个来自API的date格式是这样的:
"start_time": "2015-10-1 3:00 PM GMT+1:00"
这是YYYY-DD-MM HH:MM am / pm GMT时间戳。 我将这个值映射到POJO中的Datevariables。 显然,它显示转换错误。
我想知道2件事情:
- 我需要用什么格式来与jackson进行转换? date是一个很好的字段types呢?
- 一般来说,有没有办法在variables被Jackson映射到Object成员之前处理variables呢? 就像改变格式,计算等等
我需要用什么格式来与jackson进行转换? date是一个很好的字段types呢?
Date
是一个很好的字段types。 你可以很容易地使用ObjectMapper.setDateFormat
来进行JSONparsing:
DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm az"); myObjectMapper.setDateFormat(df);
一般来说,有没有办法在variables被Jackson映射到Object成员之前处理variables呢? 就像改变格式,计算等等
是。 你有几个选项,包括实现一个自定义的JsonDeserializer
,例如扩展JsonDeserializer<Date>
。 这是一个好的开始。
自从Jackson v2.0以来,您可以直接在Object成员上使用@JsonFormat注解;
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm az") private Date date;
当然, 有一种称为序列化和反序列化的自动化方式 ,你也可以用pb2q中提到的特定注释( @JsonSerialize , @JsonDeserialize )来定义它。
你可以同时使用java.util.Date和java.util.Calendar,也可以使用JodaTime。
@JsonFormat注解在我的 反序列化过程中 并不适用于我 (它已经将时区调整为不同的值)(序列化工作完美):
@JsonFormat(locale = "hu", shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm", timezone = "CET") @JsonFormat(locale = "hu", shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm", timezone = "Europe/Budapest")
如果需要预测结果,则需要使用自定义序列化器和自定义反序列化器,而不是使用@JsonFormat注释。 我已经find真正的好教程和解决scheme在这里http://www.baeldung.com/jackson-serialize-dates
有date字段的例子,但我需要日历字段,所以这里是我的实现 :
序列化程序类:
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())); } } }
解串器类:
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); } } }
以及上述类的用法 :
public class CalendarEntry { @JsonSerialize(using = CustomCalendarSerializer.class) @JsonDeserialize(using = CustomCalendarDeserializer.class) private Calendar calendar; // ... additional things ... }
使用这个实现,序列化和反序列化过程的执行连续产生原始值。
只使用@JsonFormat注解,反序列化给出了不同的结果,我想是因为库内部的时区默认设置你不能用注释参数(这是我的经验与jackson库2.5.3和2.6.3版本)改变。
这是一个很好的例子,在类的字段上放置注解: http : //java.dzone.com/articles/how-serialize-javautildate
现在他们有一个date处理的wiki页面: http : //wiki.fasterxml.com/JacksonFAQDateHandling
build立在@ miklov-kriven的非常有用的答案,我希望这两个额外的考虑点有助于某人:
(1)我觉得把串行器和反序列化器作为静态内部类放在同一个类中是个不错的主意。 注意,使用ThreadLocal来实现SimpleDateFormat的线程安全。
public class DateConverter { private static final ThreadLocal<SimpleDateFormat> sdf = ThreadLocal.<SimpleDateFormat>withInitial( () -> {return new SimpleDateFormat("yyyy-MM-dd HH:mm az");}); 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的默认序列化,即所有types为Date的类成员都将由Jackson序列化使用这个自定义序列化没有明确的注释在每个领域。 如果你正在使用Spring Boot,例如一个方法来做到这一点如下:
@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; } }
如果任何人在使用java.sql.Date的自定义date格式时遇到问题,这是最简单的解决scheme:
ObjectMapper mapper = new ObjectMapper(); SimpleModule module = new SimpleModule(); module.addSerializer(java.sql.Date.class, new DateSerializer()); mapper.registerModule(module);
(这个SO-answer救了我很多麻烦: https : //stackoverflow.com/a/35212795/3149048 )
Jackson默认为java.sql.Date使用SqlDateSerializer,但是目前这个序列化程序并没有考虑dateformat,请参阅https://github.com/FasterXML/jackson-databind/issues/1407 。 解决方法是为java.sql.Date注册不同的序列化程序,如代码示例中所示。