I am giving up. I have looked through all possible SO pages but I can not get it to work.
I have a class ConfigKeyVal
like this:
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@JsonIgnoreProperties(ignoreUnknown = true)
public class ConfigKeyValue {
private String name;
private NssConfigDto value;
}
Where Config
class looks like this:
@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;
}
I am trying to deserialize JSON array of ConfigKeyVal
(top one) objects directly into the ArrayList of mine.
public class ConfigKeyValueList extends ArrayList<ConfigKeyValue> {
public ConfigKeyValueList() {
super();
}
}
Like this:
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();
}
I have tried using mapper.registerModule(new JavaTimeModule());
but that did not help. Do I have to write my own deserializer for this or is there a valid tool and I am doing it all wrong?
The error I am getting is: 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?))
I am using those jackson dependencies in my gradle file:
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'
EDIT: This is how JSON looks like
[
{
"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"
}
}
}
}
]
First of all, I don't recommend serializing dates like that. I strongly encourage you to stick to the standards and use ISO 8601 , which is endorsed by the RFC 3339 and by the xkcd 1179 :
If you use Spring Data MongoDB , you can use MongoCustomConversions
to handle the conversion from Date
and LocalDateTime
for you:
@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());
}
}
}
Then you can use LocalDateTime
your in your beans and let Jackson and the JavaTimeModule
handle the serialization/deserialization:
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);
If you don't have control over the JSON, then you'll need a custom deserializer . The implementation can be like:
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);
}
}
Then annotate your fields to use the deserializer defined above:
@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;
}
And finally parse your JSON document:
ObjectMapper mapper = new ObjectMapper();
TypeReference<List<ConfigKeyValue>> typeRef = new TypeReference<>() {};
List<ConfigKeyValue> list = mapper.readValue(json, typeRef);
You have to add the module to your 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;
}
Since the last versions of jackson the module is JavaTimeModule, It used to be JSR310Module
Edit: It should be used for both serialisation/deserialisation, what you mis is maybe mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
The JSON format should be in ISO:
{
"name": "kek2",
"value": {
"name": "kek2",
"source": "source",
"destination": "dest",
"cycle": 1,
"fixedTime": "2018-07-17T15:10:55"
...
Jackson doesn't have a way to deserialize a LocalDateTime object from any JSON string value.
Change LocalDateTime object to "String".
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.