Reputation: 16043
I'm making a web app using Jackson & Jersey. I've made Response POJOs for the APIs hosted. I've made a custom Jackson serializer for a date field as below.
class A{
LocalDateTime localDateTime = LocalDateTime.now();
@JsonSerialize(using = JacksonSerializers.DateSecondsFromEpochUTCSerializer.class)
public LocalDateTime getLocalDateTime() {
return localDateTime;
}
public void setLocalDateTime(LocalDateTime localDateTime) {
this.localDateTime = localDateTime;
}
}
And the Serializer is as below:
public class JacksonSerializers {
@Component
public static class DateSecondsFromEpochUTCSerializer extends JsonSerializer<LocalDateTime> {
@Override
public void serialize(LocalDateTime localDateTime, JsonGenerator gen, SerializerProvider provider)
throws IOException, JsonProcessingException {
gen.writeNumber(localDateTime.toEpochSecond(ZoneOffset.UTC));
}
}
The above code is working fine when the API is called and the response contains the date in the epoch format.
However, The above serialization is not working when I'm trying to make a JSON of the class using GSON lib. I'm getting the below incorrect output:
System.out.print(new Gson().toJson(new A()));
gives
{"localDateTime":{"date":{"year":2017,"month":1,"day":31},"time":{"hour":12,"minute":55,"second":53,"nano":481000000}}}
But I want 1485847871
. Basically, I want to serialize LocalDateTime in epoch time in both flows. I'm trying to do now with GSON but it is not a hardcore requirement. Any elegant solution to achieve both results would do.
Upvotes: 0
Views: 1742
Reputation: 16043
Solution which worked for me:
new ObjectMapper().writeValueAsString(new A())
Upvotes: 0
Reputation: 21115
If you're still fine with Gson, and not require Jackson to be introduced since it's a totally different library, you can use a custom Gson type adapter:
final class LocalDateTimeTypeAdapter
extends TypeAdapter<LocalDateTime> {
private static final TypeAdapter<LocalDateTime> localDateTimeTypeAdapter = new LocalDateTimeTypeAdapter();
private LocalDateTimeTypeAdapter() {
}
static TypeAdapter<LocalDateTime> getLocalDateTimeTypeAdapter() {
return localDateTimeTypeAdapter;
}
@Override
@SuppressWarnings("resource")
public void write(final JsonWriter out, final LocalDateTime value)
throws IOException {
out.value(value.toEpochSecond(UTC));
}
@Override
public LocalDateTime read(final JsonReader in)
throws IOException {
return Instant.ofEpochSecond(in.nextLong()).atZone(UTC).toLocalDateTime();
}
}
This is similar to Gson the JsonSerializer
/JsonDeserializer
pair, but it's more efficient since the latter require JSON trees to be built in memory, whilst type adapters work in streaming fashion and may generate values not accumulating an intermediate state much. Then just configure your Gson
instance:
final Gson gson = new GsonBuilder()
.registerTypeAdapter(LocalDateTime.class, getLocalDateTimeTypeAdapter())
.create();
final String json = gson.toJson(new A());
out.println(json);
final A a = gson.fromJson(json, A.class);
out.println(a.localDateTime);
And it would produce something like:
{"localDateTime":1485871467}
2017-01-31T14:04:27
both for serialization and deserialization.
Upvotes: 1
Reputation: 7157
It's possible to create a unified serializer that you can use for both Jackson and GSON. Something along the lines of this:
public class DateSecondsFromEpochUTCSerializer
extends com.fasterxml.jackson.databind.JsonSerializer<LocalDateTime>
implements com.google.gson.JsonSerializer<LocalDateTime> {
@Override
public void serialize(LocalDateTime localDateTime, JsonGenerator gen, SerializerProvider provider) throws IOException {
gen.writeNumber(convert(localDateTime));
}
@Override
public JsonElement serialize(LocalDateTime ldt, Type type, JsonSerializationContext jsonSerializationContext) {
return new JsonPrimitive(convert(ldt));
}
private long convert(LocalDateTime ldt) {
return ldt.toEpochSecond(ZoneOffset.UTC);
}
}
Install it in your GSON instance like this:
Gson gson = new GsonBuilder()
.registerTypeAdapter(LocalDateTime.class, new DateSecondsFromEpochUTCSerializer())
.create();
System.out.println(gson.toJson(LocalDateTime.now())); // Epoch
Upvotes: 1