Jackson serialize and Deserialize DateTime From/To WCF DateTime

Bilgehan :

I use Jackson to serialise and deserialise object. I have .NET WCF DateTime JSON format with Time Zone. And Jackson can't deserialise JSON to object. I found some solutions, but is there any Jackson embedded or suggested solution how to do that?

Example dates:

  • "/Date(12345678989+0000)/"
  • "/Date(12345678989-0000)/"

See also: How to parse .net DateTime received as json string into java's Date object

Michał Ziober :

To handle date time in format generated by .NET's JavaScriptSerializer in form /Date(number of ticks)/ you need to implement custom deserialiser. To understand what are "ticks" lets take a look at documentation:

Date object, represented in JSON as "/Date(number of ticks)/". The number of ticks is a positive or negative long value that indicates the number of ticks (milliseconds) that have elapsed since midnight 01 January, 1970 UTC.

The maximum supported date value is MaxValue (12/31/9999 11:59:59 PM) and the minimum supported date value is MinValue (1/1/0001 12:00:00 AM).

I assume, that in your case you have an offset provided as well, like in examples.

Using Java 8 Time package and above knowledge we can implement custom deserialiser as below plus example usage:

import com.fasterxml.jackson.core.JsonParser;
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.Instant;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class JsonPathApp {

    public static void main(String[] args) throws Exception {
        String inputJson = "{\"date\":\"/Date(1583001930882+0100)/\"}";

        ObjectMapper mapper = new ObjectMapper();
        Epoch epoch = mapper.readValue(inputJson, Epoch.class);
        System.out.println(epoch.getDate());
    }
}

class Epoch {

    @JsonDeserialize(using = JavaScriptDateDeserializer.class)
    private OffsetDateTime date;

    public OffsetDateTime getDate() {
        return date;
    }

    public void setDate(OffsetDateTime date) {
        this.date = date;
    }
}

class JavaScriptDateDeserializer extends JsonDeserializer<OffsetDateTime> {

    private final Pattern JAVASCRIPT_DATE = Pattern.compile("/Date\\((-?\\d+)([+-]\\d+)\\)/");

    @Override
    public OffsetDateTime deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
        String value = p.getValueAsString();
        Matcher matcher = JAVASCRIPT_DATE.matcher(value);
        if (matcher.matches()) {
            String epoch = matcher.group(1);
            String offset = matcher.group(2);

            Instant instant = Instant.ofEpochMilli(Long.parseLong(epoch));

            return OffsetDateTime.ofInstant(instant, ZoneOffset.of(offset));
        }

        return null;
    }
}

Above code prints:

2020-02-29T19:45:30.882+01:00

Serialiser could look like below:

class JavaScriptDateSerializer extends JsonSerializer<OffsetDateTime> {

    @Override
    public void serialize(OffsetDateTime value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
        StringBuilder builder = new StringBuilder(32);
        builder.append("/Date(");
        builder.append(value.toInstant().toEpochMilli());
        if (!value.getOffset().equals(ZoneOffset.UTC)) {
            builder.append(value.getOffset().toString());
        }
        builder.append(")/");

        gen.writeString(builder.toString());
    }
}

You need to handle Time Zone properly, if you always send/receive date in UTC you can skip this part.

See also:

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=19533&siteId=1