LocalDate
Вам необходимо внедрить пользовательский десериализатор и аннотировать данное поле с помощью JsonDeserialize
аннотации. Для ниже POJO
модель:
class Pojo {
@JsonDeserialize(using = LocalDateJsonDeserializer.class)
private LocalDate date;
private String name;
private Message message;
// getters, setters
}
class Message {
private String product;
private int price;
// getters, setters
}
Простая реализация десериализатора может выглядеть так:
class LocalDateJsonDeserializer extends JsonDeserializer<LocalDate> {
@Override
public LocalDate deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
if (p.currentToken() == JsonToken.START_OBJECT) {
MapType mapType = ctxt.getTypeFactory().constructMapType(Map.class, String.class, Integer.class);
JsonDeserializer<Object> mapDeserializer = ctxt.findRootValueDeserializer(mapType);
Map<String, Integer> date = (Map<String, Integer>) mapDeserializer.deserialize(p, ctxt);
return LocalDate.of(date.get("year"), date.get("month"), date.get("day"));
} else if (p.currentToken() == JsonToken.VALUE_NUMBER_INT) {
// You need to be really careful here. Date format is ambiguous
// You should test it for all months and days
String date = p.getValueAsString();
int year = Integer.parseInt(date.substring(0, 4));
// much better to use always two digits for month: `03` instead `3`
int month = Integer.parseInt(date.substring(4, 5));
int day = Integer.parseInt(date.substring(5, 7));
return LocalDate.of(year, month, day);
} else if (p.currentToken() == JsonToken.VALUE_NULL) {
return null;
}
return null;
}
}
Простое использование:
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import java.io.IOException;
import java.time.LocalDate;
import java.util.HashMap;
import java.util.Map;
public class Test {
public static void main(String[] args) throws Exception {
String json1 = "json 1 ...";
String json2 = "json 2....";
ObjectMapper mapper = new ObjectMapper();
System.out.println(mapper.readValue(json1, Pojo.class));
System.out.println(mapper.readValue(json2, Pojo.class));
}
}
печать:
Pojo{date=2017-03-12, name='Jon', message=Message{product='orange', price=2000}}
Pojo{date=2017-03-12, name='Jon', message=Message{product='orange', price=2000}}
Конечно, вам нужно обрабатывать все угловые случаи и улучшать обработку ошибок, но, как правило, мы должны обрабатывать значения, которые могут иметь разные форматы: JSON object
, JSON array
, primitives
.
LocalDateTime
Для LocalDateTime
оно должно выглядеть аналогичным образом. Нам нужно создать POJO
модель:
class Pojo {
@JsonDeserialize(using = LocalDateTimeJsonDeserializer.class)
private LocalDateTime time;
private String name;
private Message message;
// getters, setters, toString
}
Пользовательский десериализатор может выглядеть следующим образом:
class LocalDateTimeJsonDeserializer extends JsonDeserializer<LocalDateTime> {
@Override
public LocalDateTime deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
if (p.currentToken() == JsonToken.START_OBJECT) {
MapType mapType = ctxt.getTypeFactory().constructMapType(Map.class, String.class, Object.class);
JsonDeserializer<Object> mapDeserializer = ctxt.findRootValueDeserializer(mapType);
Map<String, Object> node = (Map<String, Object>) mapDeserializer.deserialize(p, ctxt);
Map<String, Integer> date = (Map<String, Integer>) node.get("date");
Map<String, Integer> time = (Map<String, Integer>) node.get("time");
LocalDate localDate = LocalDate.of(date.get("year"), date.get("month"), date.get("day"));
LocalTime localTime = LocalTime.of(time.get("hour"), time.get("minute"), time.get("second"), time.get("nano"));
return LocalDateTime.of(localDate, localTime);
} else if (p.currentToken() == JsonToken.VALUE_NUMBER_INT) {
// You need to be really careful here. Date format is ambiguous
// You should test it for all months and days
String date = p.getValueAsString();
// parse date string
// ...
return LocalDateTime.now();
} else if (p.currentToken() == JsonToken.VALUE_NULL) {
return null;
}
return null;
}
}
Пример десериализации выглядит так же, как и для LocalDate
. Для полезной нагрузки ниже JSON
:
{
"time": {
"date": {
"year": 2019,
"month": 3,
"day": 29
},
"time": {
"hour": 13,
"minute": 21,
"second": 20,
"nano": 620000000
}
},
"name": "Jon",
"message": {
"product": "orange",
"price": 2000
}
}
должно быть напечатано:
Pojo{time=2019-03-29T13:21:20.620, name='Jon', message=Message{product='orange', price=2000}}
Также обратите внимание на модуль JavaTimeModule
, который охватывает все классы java.time.*
и позволяет сериализовать и десериализовать стандартным образом,