[英]Why Jackson ObjectMapper give me this error converting JSON field into a Date object? Can not deserialize value of type java.util.Date from String
[英]How to parse properly Date string to java.util.Date when deserializing JSON to Java POJO with Jackson ObjectMapper
我正在实现一个应用程序,它以 json 格式从 certin 端点获取数据,并尝试将 tem 反序列化为 Java 对象,但我在解析 JSON 中的日期时遇到问题。这是日期在 JSON 中的样子:“/ Date(1633122000000+0300)/" 我在谷歌中找不到如何成功解析这种格式的信息。
{
"Date": "/Date(1633122000000+0300)/",
"Filled": 0,
"Needed": 0,
"Paid": 0
}
这是我用来将数据反序列化为使用 Jackson ObjectMapper 的 pojo:
import java.util.Date;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class TimeByDateSheet {
@JsonProperty("Date")
@JsonFormat(timezone = "GMT+03:00")
@JsonDeserialize(using = DateDeserializer.class, as=Date.class)
private Date date;
@JsonProperty("Filled")
private Long filled;
@JsonProperty("Needed")
private Long needed;
@JsonProperty("Paid")
private Integer paid;
}
这是我的 DateDeserializer:
@SuppressWarnings("serial")
public class DateDeserializer extends JsonDeserializer<Date> {
@Override
public Date deserialize(JsonParser jsonParser, DeserializationContext context)
throws IOException, JsonProcessingException {
SimpleDateFormat simpleDateFormat =
new SimpleDateFormat("yyyy-MM-dd HH:mm:ss zzz", Locale.getDefault());
String dateStr = jsonParser.getText();
Date date;
try{
date = simpleDateFormat.parse(dateStr);
}catch(ParseException e){
throw new RuntimeException(e);
}
return date;
}
}
但它不能正常工作。 我收到以下异常:
连接到目标VM,地址:'127.0.0.1:52760',传输:'socket' SLF4J:加载类“org.slf4j.impl.StaticLoggerBinder”失败。 SLF4J:默认为无操作 (NOP) 记录器实现 SLF4J:有关更多详细信息,请参阅http://www.slf4j.org/codes.html#StaticLoggerBinder 。 线程“main”中的异常 com.fasterxml.jackson.databind.JsonMappingException: java.text.ParseException: Unparseable date: "/Date(1633035600000+0300)/"(通过引用链:java.util.ArrayList[0]-> com.dataart.forecasts.pojo.timebydate.TimeByDateSheet["Date"]) 在 com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:392) 在 com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException) .java:351) 在 com.fasterxml.jackson.databind.deser.BeanDeserializerBase.wrapAndThrow(BeanDeserializerBase.java:1821) 在 com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:315) 在fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:176) 在 com.fasterxml.jackson.databind.deser.std.CollectionDeserializer._deserializeFromArray(CollectionDeserializer.java:355) 在 com.fasterxml.datajackson deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:24 4) 在 com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:28) 在 com.fasterxml.jackson.databind.deser.DefaultDeserializationContext.readRootValue(DefaultDeserializationContext.java:322) 在 com. .jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4675) 在 com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3630) 在 com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java) :3613) 在 com.dataart.forecasts.DataProcessor.deserializeTimeByDateSheetsList(DataProcessor.java:198) 在 com.dataart.forecasts.ForecastReportApplication.main(ForecastReportApplication.java:50) 由:java.lang.RuntimeException: java.text. ParseException:无法解析的日期:“/Date(1633035600000+0300)/” at com.dataart.forecasts.DateDeserializer.deserialize(DateDeserializer.java:28) at com.dataart.forecasts.DateDeserializer.deserialize(Date16Deserializer) at com.dataart.forecasts.DateDeserializer.deserialize(DateDeserializer.java:28) com.fasterxml.jackson.databind.deser.impl.MethodPro perty.deserializeAndSet(MethodProperty.java:129) at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:313) ... 10个以上引起:java.text.ParseException:无法解析的日期:“/ Date(1633035600000+0300)/" at java.base/java.text.DateFormat.parse(DateFormat.java:395) at com.dataart.forecasts.DateDeserializer.deserialize(DateDeserializer.java:26) ... 13 更多
有人可以帮我吗,请。 我在互联网上搜索了很多,但找不到解决方案。 先感谢您! :)
对于这个答案,我假设:
Instant
或OffsetDateTime
类型(而不是Date
)。 对于带有偏移量(例如+0300
JSON,将变量声明为OffsetDateTime
。 然后使用以下解串器。
public class OdtDeserializer extends JsonDeserializer<OffsetDateTime> {
private static final DateTimeFormatter JSON_DATE_FORMATTER = new DateTimeFormatterBuilder()
.appendLiteral("/Date(")
.appendValue(ChronoField.INSTANT_SECONDS)
.appendValue(ChronoField.MILLI_OF_SECOND, 3)
.appendOffset("+HHMM", "Z")
.appendLiteral(")/")
.toFormatter();
@Override
public OffsetDateTime deserialize(JsonParser jsonParser, DeserializationContext context)
throws IOException {
String dateStr = jsonParser.getText();
return OffsetDateTime.parse(dateStr, JSON_DATE_FORMATTER);
}
}
对于没有偏移量的 JSON,如/Date(1636510000000)/
声明您的变量Instant
。 使用类似的解串器。 忽略格式化程序的偏移量。 解析为Instant
— 语法有点不同。
public class InstantDeserializerWIthoutOffset extends JsonDeserializer<Instant> {
private static final DateTimeFormatter JSON_DATE_FORMATTER = new DateTimeFormatterBuilder()
.appendLiteral("/Date(")
.appendValue(ChronoField.INSTANT_SECONDS)
.appendValue(ChronoField.MILLI_OF_SECOND, 3)
.appendLiteral(")/")
.toFormatter();
@Override
public Instant deserialize(JsonParser jsonParser, DeserializationContext context)
throws IOException {
String dateStr = jsonParser.getText();
return JSON_DATE_FORMATTER.parse(dateStr, Instant::from);
}
}
对于可能带有或不带有偏移量的 JSON仍然使用Instant
并且只需修改后一个反序列化器的格式化程序以包含一个可选的偏移量:
private static final DateTimeFormatter JSON_DATE_FORMATTER = new DateTimeFormatterBuilder()
.appendLiteral("/Date(")
.appendValue(ChronoField.INSTANT_SECONDS)
.appendValue(ChronoField.MILLI_OF_SECOND, 3)
.optionalStart()
.appendOffset("+HHMM", "Z")
.optionalEnd()
.appendLiteral(")/")
.toFormatter();
如果您无法修改您的 POJO 类并且需要使用Date
,请通过更改声明并返回一个Date
来将我的Instant
deserializer 修改为Date
反序列化器,如下所示:
String dateStr = jsonParser.getText();
Instant inst = JSON_DATE_FORMATTER.parse(dateStr, Instant::from);
return Date.from(inst);
捕获两者的最终解决方案:/Date(1633035600000+0300)/ 和 /Date(-62135596800000)/(后者也出现在其中一个 JSON 中的一个位置)。 谢谢@DavidConrad
@Override
public Date deserialize(JsonParser jsonParser, DeserializationContext context) throws IOException, JsonProcessingException {
String dateString = jsonParser.getText();
Pattern pattern = Pattern.compile("/Date\\((-)?(\\d+)([+-]\\d+)?\\)/");
Matcher matcher = pattern.matcher(dateString);
if (!matcher.find()) {
throw new RuntimeException("Invalid format: " + dateString);
}
String timestamp = matcher.group(2);
String offset = matcher.group(3);
Instant instant = Instant.ofEpochMilli(Long.parseLong(timestamp));
if (nonNull(offset)) {
ZonedDateTime zdt = instant.atZone(ZoneId.of(offset));
instant = zdt.toInstant();
}
return Date.from(instant);
}
生成 JSON 似乎存在问题。 我真的不认为你想要这样格式化日期。 现在,您有一些奇怪的文本围绕着以毫秒为单位的 unix 时间戳,后跟区域偏移量。 您还使用了旧的、 java.time
Date 和 SimpleDateFormat 类,而不是较新的java.time
API。 但是,可以反序列化您的日期格式。 这是一种方法:
public class DateDeserializer extends JsonDeserializer<Date> {
@Override
public Date deserialize(JsonParser jsonParser, DeserializationContext context)
throws IOException, JsonProcessingException {
Pattern pattern = Pattern.compile("/Date\\((\\d+)([+-]\\d+)\\)/");
Matcher matcher = pattern.matcher(jsonParser.getText());
if (matcher.find()) {
String timestamp = matcher.group(1);
String offset = matcher.group(2);
Instant instant = Instant.ofEpochMilli(Long.parseLong(timestamp));
ZonedDateTime zdt = instant.atZone(ZoneId.of(offset));
instant = zdt.toInstant();
return Date.from(instant);
} else {
throw new RuntimeException("Invalid format: " + jsonParser.getText());
}
}
}
@DavidConrad 谢谢,我会尝试您的解决方案。 顺便说一句,现在我做了一个对我有用的解决方法:
@Override
public Date deserialize(JsonParser jsonParser, DeserializationContext context) throws IOException, JsonProcessingException {
SimpleDateFormat dateFormattter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String dateStr = jsonParser.getText();
String timeZone = dateStr.substring(dateStr.indexOf("+") + 1, dateStr.indexOf(")"));
String timeZoneShift = String.format("%s:%s",
timeZone.substring(0, timeZone.length()/2),
timeZone.substring(timeZone.length()/2));
dateFormattter.setTimeZone(TimeZone.getTimeZone(String.format("GMT+%s", timeZoneShift)));
Long millis = 0L;
if (dateStr.contains("+") && !dateStr.contains("-")) {
millis = Long.parseLong(dateStr.substring(dateStr.indexOf("(") + 1, dateStr.indexOf("+")));
} else if (dateStr.contains("+") && !dateStr.contains("-")) {
millis = Long.parseLong(dateStr.substring(dateStr.indexOf("(") + 1, dateStr.indexOf(")")));
}
Date date = new Date(millis);
String stringDate= dateFormattter.format(date);
try {
date = dateFormattter.parse(stringDate);
} catch (ParseException e) {
throw new RuntimeException(e);
}
return date;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.