1

Consider the following example:

I have a json string = {"timestamp":1504111920} which needs to be converted to CodeTimestamp class. The timestamp present in above json string is in epoch second.

CodeTimestamp class:

@Getter
@Setter
@NoArgsConstructor
class CodeTimestamp {
    private Date timestamp;
}

By directly using fasterxml jackson mapper, I'll not be able to get the correct date since it assumes timestamp to be in epoch millisecond. So, I would need to write a custom deserializer.

However, I cannot edit/modify CodeTimestamp class. Is there any way to write JsonDeserializer in mixin?

I'm facing issues while deserializing. Following is the code:

public abstract class StreamRecordMixIn {

        @JsonDeserialize(using = UnixTimestampDeserializer.class)
        private Date approximateCreationDateTime;
}

    public class UnixTimestampDeserializer extends JsonDeserializer<Date> {

        @Override
        public Date deserialize(JsonParser parser, DeserializationContext context) 
                throws IOException, JsonProcessingException {
            String unixTimestamp = parser.getText().trim();
            return new Date(TimeUnit.SECONDS.toMillis(Long.valueOf(unixTimestamp)));
        }
    }

Code to initialize and use object mapper:

ObjectMapper objectMapper = new ObjectMapper();

objectMapper.configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES, true);
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

objectMapper.addMixIn(CodeTimestamp.class, StreamRecordMixIn.class);

CodeTimestamp codeTimeStamp = objectMapper.readValue(payload, CodeTimestamp.class);

Error:

Caused by: java.lang.IllegalArgumentException: Class com.test.TestConverter$UnixTimestampDeserializer has no default (no arg) constructor at com.fasterxml.jackson.databind.util.ClassUtil.createInstance(ClassUtil.java:378) at com.fasterxml.jackson.databind.deser.DefaultDeserializationContext.deserializerInstance(DefaultDeserializationContext.java:218) at com.fasterxml.jackson.databind.deser.BasicDeserializerFactory.findDeserializerFromAnnotation(BasicDeserializerFactory.java:1735) at com.fasterxml.jackson.databind.deser.BeanDeserializerFactory.constructSettableProperty(BeanDeserializerFactory.java:730) at com.fasterxml.jackson.databind.deser.BeanDeserializerFactory.addBeanProps(BeanDeserializerFactory.java:507) at com.fasterxml.jackson.databind.deser.BeanDeserializerFactory.buildBeanDeserializer(BeanDeserializerFactory.java:229) at com.fasterxml.jackson.databind.deser.BeanDeserializerFactory.createBeanDeserializer(BeanDeserializerFactory.java:142) at com.fasterxml.jackson.databind.deser.DeserializerCache._createDeserializer2(DeserializerCache.java:403) at com.fasterxml.jackson.databind.deser.DeserializerCache._createDeserializer(DeserializerCache.java:352) at com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCache2(DeserializerCache.java:264) ... 23 more

  • Possible duplicate of [How do I deserialize timestamps that are in seconds with Jackson?](https://stackoverflow.com/questions/20635698/how-do-i-deserialize-timestamps-that-are-in-seconds-with-jackson) – Naman Aug 31 '17 at 04:29
  • *Is there any way to write JsonDeserializer in mixin?* Sure, what's the problem? – shmosel Aug 31 '17 at 04:30
  • @nullpointer the solution provided uses annotations over the actual class. Not sure the same can be done in mixin. I've updated the question for more clarity. – SIDDHARTH J MEHTA Aug 31 '17 at 05:55
  • 1
    Sure, that's basically the point of mixins. Your problem is that `UnixTimestampDeserializer` is not static. – shmosel Aug 31 '17 at 06:09
  • thanks @shmosel, this worked. Thanks a ton!! – SIDDHARTH J MEHTA Aug 31 '17 at 06:12

1 Answers1

1

The mistake here is custom deserializer not declared as static. So if I used it as mentioned below, it works.

public static class UnixTimestampDeserializer extends JsonDeserializer<Date> {

    @Override
    public Date deserialize(JsonParser parser, DeserializationContext context) 
            throws IOException, JsonProcessingException {
        String unixTimestamp = parser.getText().trim();
        return new Date(TimeUnit.SECONDS.toMillis(Long.valueOf(unixTimestamp)));
    }
}