[英]Deserializing JSON to Object with LocalDateTime field
我放棄了 我已經瀏覽了所有可能的SO頁面,但是無法正常工作。
我有一個這樣的ConfigKeyVal
類:
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@JsonIgnoreProperties(ignoreUnknown = true)
public class ConfigKeyValue {
private String name;
private NssConfigDto value;
}
Config
類如下所示:
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@JsonIgnoreProperties(ignoreUnknown = true)
public class Config {
private String name;
private String source;
private String destination;
private int cycle;
private LocalDateTime fixedTime;
private LocalDateTime submitDate;
}
我正在嘗試將ConfigKeyVal
(頂級)對象的JSON數組直接反序列化到我的ArrayList中。
public class ConfigKeyValueList extends ArrayList<ConfigKeyValue> {
public ConfigKeyValueList() {
super();
}
}
像這樣:
final Data values = result.results().get("attributes"); // this is an array of ConfigKeyValue objects
ObjectMapper mapper = new ObjectMapper();
ConfigKeyValueList configKeyValueList = new ConfigKeyValueList();
try {
configKeyValueList = mapper.readValue(values.asText(), ConfigKeyValueList.class);
} catch (IOException e) {
e.printStackTrace();
}
我已經嘗試使用mapper.registerModule(new JavaTimeModule());
但這沒有幫助。 我是否需要為此編寫自己的解串器,或者是否有有效的工具,但我做錯了所有事情?
我收到的錯誤是: com.fasterxml.jackson.databind.JsonMappingException: Can not construct instance of java.time.LocalDateTime: no suitable constructor found, can not deserialize from Object value (missing default constructor or creator, or perhaps need to add/enable type information?))
我在gradle文件中使用了那些jackson依賴項:
compile group: 'com.fasterxml.jackson.module', name: 'jackson-module-parameter-names', version: '2.9.6'
compile group: 'com.fasterxml.jackson.datatype', name: 'jackson-datatype-jdk8', version: '2.9.6'
compile group: 'com.fasterxml.jackson.datatype', name: 'jackson-datatype-jsr310', version: '2.9.6'
編輯:這就是JSON的樣子
[
{
"name": "kek1",
"value": {
"name": "kek1",
"source": "source",
"destination": "dest",
"cycle": 1,
"fixedTime": {
"year": 2017,
"month": "APRIL",
"dayOfYear": 95,
"dayOfWeek": "WEDNESDAY",
"dayOfMonth": 5,
"monthValue": 4,
"hour": 4,
"minute": 20,
"second": 0,
"nano": 0,
"chronology": {
"id": "ISO",
"calendarType": "iso8601"
}
},
"submitDate": {
"year": 2017,
"month": "APRIL",
"dayOfYear": 95,
"dayOfWeek": "WEDNESDAY",
"dayOfMonth": 5,
"monthValue": 4,
"hour": 4,
"minute": 20,
"second": 0,
"nano": 0,
"chronology": {
"id": "ISO",
"calendarType": "iso8601"
}
}
}
},
{
"name": "kek2",
"value": {
"name": "kek2",
"source": "source",
"destination": "dest",
"cycle": 1,
"fixedTime": {
"year": 2017,
"month": "APRIL",
"dayOfYear": 93,
"dayOfWeek": "MONDAY",
"dayOfMonth": 3,
"monthValue": 4,
"hour": 5,
"minute": 10,
"second": 0,
"nano": 0,
"chronology": {
"id": "ISO",
"calendarType": "iso8601"
}
},
"submitDate": {
"year": 2017,
"month": "APRIL",
"dayOfYear": 93,
"dayOfWeek": "MONDAY",
"dayOfMonth": 3,
"monthValue": 4,
"hour": 5,
"minute": 10,
"second": 0,
"nano": 0,
"chronology": {
"id": "ISO",
"calendarType": "iso8601"
}
}
}
}
]
首先,我不建議像這樣序列化日期。 我強烈建議您堅持使用標准,並使用RFC 3339和xkcd 1179認可的ISO 8601 :
如果使用Spring Data MongoDB ,則可以使用MongoCustomConversions
為您處理從Date
和LocalDateTime
進行的轉換:
@Configuration
public class MongoConfiguration {
@Bean
public MongoCustomConversions customConversions() {
List<Converter<?, ?>> converters = new ArrayList<>();
converters.add(new DateToLocalDateTimeConverter());
converters.add(new LocalDateTimeToDateConverter());
return new MongoCustomConversions(converters);
}
class DateToLocalDateTimeConverter implements Converter<Date, LocalDateTime> {
@Override
public LocalDateTime convert(Date source) {
return source == null ? null :
LocalDateTime.ofInstant(source.toInstant(), ZoneId.systemDefault());
}
}
class LocalDateTimeToDateConverter implements Converter<LocalDateTime, Date> {
@Override
public Date convert(LocalDateTime source) {
return source == null ? null : Date.from(source.toInstant());
}
}
}
然后,您可以在bean中使用LocalDateTime
,讓Jackson和JavaTimeModule
處理序列化/反序列化:
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new JavaTimeModule());
mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
// Serialize
List<ConfigKeyValue> list = null;
String json = mapper.writeValueAsString(list);
// Deserialize
TypeReference<List<ConfigKeyValue>> typeRef = new TypeReference<>() {};
list = mapper.readValue(json, typeRef);
如果您無法控制JSON,則需要一個自定義解串器 。 實現可以像這樣:
public class CustomLocalDateTimeDeserializer extends JsonDeserializer<LocalDateTime> {
@Override
public LocalDateTime deserialize(JsonParser jp, DeserializationContext ctxt)
throws IOException {
JsonNode tree = jp.getCodec().readTree(jp);
int year = tree.get("year").asInt();
int month = tree.get("monthValue").asInt();
int dayOfMonth = tree.get("dayOfMonth").asInt();
int hour = tree.get("hour").asInt();
int minute = tree.get("minute").asInt();
int second = tree.get("second").asInt();
int nano = tree.get("nano").asInt();
return LocalDateTime.of(year, month, dayOfMonth, hour, minute, second, nano);
}
}
然后注釋您的字段以使用上面定義的反序列化器:
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@JsonIgnoreProperties(ignoreUnknown = true)
public class Config {
// Other fields
@JsonDeserialize(using = CustomLocalDateTimeDeserializer.class)
private LocalDateTime fixedTime;
@JsonDeserialize(using = CustomLocalDateTimeDeserializer.class)
private LocalDateTime submitDate;
}
最后解析您的JSON文檔:
ObjectMapper mapper = new ObjectMapper();
TypeReference<List<ConfigKeyValue>> typeRef = new TypeReference<>() {};
List<ConfigKeyValue> list = mapper.readValue(json, typeRef);
您必須將模塊添加到您的ObjectMapper
private ObjectMapper getMapper() {
ObjectMapper mapper = new ObjectMapper();
mapper.configure(SerializationFeature.INDENT_OUTPUT,false);
mapper.setSerializationInclusion(Include.NON_NULL);
mapper.registerModule(new JavaTimeModule());
mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
return mapper;
}
由於傑克遜的最新版本是JavaTimeModule,所以以前是JSR310Module
編輯:應該同時用於序列化/反序列化,您可能會誤解的是mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS,false);。
JSON格式應為ISO:
{
"name": "kek2",
"value": {
"name": "kek2",
"source": "source",
"destination": "dest",
"cycle": 1,
"fixedTime": "2018-07-17T15:10:55"
...
Jackson沒有辦法從任何JSON字符串值反序列化LocalDateTime對象。
將LocalDateTime對象更改為“ String”。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.