Nikolay
Nikolay

Reputation: 1121

Jackson serialization exception when trying to serialize LocalDateTime

I can't figure why when trying to serialize an object I get an exception which looks related to deserialization. My object has a field which is of joda type LocalDateTime

ObjectMapper mapper = new ObjectMapper();
mapper.writeValueAsString(response)); 

I got the following exception:

org.codehaus.jackson.map.JsonMappingException: java.lang.String cannot be cast to org.joda.time.LocalDateTime

I am trying to serialize. Why it is trying to convert String value to object? I tried to add custom deserializers, but it does not work.

update More of the exception:

org.codehaus.jackson.map.JsonMappingException: java.lang.String cannot be cast to org.joda.time.LocalDateTime (through reference chain: com.my.AccountDetailResponse["registrationDate"])
at org.codehaus.jackson.map.JsonMappingException.wrapWithPath(JsonMappingException.java:218) ~[jackson-mapper-asl-1.9.13.jar:1.9.13]
at org.codehaus.jackson.map.JsonMappingException.wrapWithPath(JsonMappingException.java:183) ~[jackson-mapper-asl-1.9.13.jar:1.9.13]
at org.codehaus.jackson.map.ser.std.SerializerBase.wrapAndThrow(SerializerBase.java:140) ~[jackson-mapper-asl-1.9.13.jar:1.9.13]
at org.codehaus.jackson.map.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:158) ~[jackson-mapper-asl-1.9.13.jar:1.9.13]
at org.codehaus.jackson.map.ser.BeanSerializer.serialize(BeanSerializer.java:112) ~[jackson-mapper-asl-1.9.13.jar:1.9.13]
at org.codehaus.jackson.map.ser.StdSerializerProvider._serializeValue(StdSerializerProvider.java:610) ~[jackson-mapper-asl-1.9.13.jar:1.9.13]
at org.codehaus.jackson.map.ser.StdSerializerProvider.serializeValue(StdSerializerProvider.java:256) ~[jackson-mapper-asl-1.9.13.jar:1.9.13]
at org.codehaus.jackson.map.ObjectMapper._configAndWriteValue(ObjectMapper.java:2575) ~[jackson-mapper-asl-1.9.13.jar:1.9.13]
at org.codehaus.jackson.map.ObjectMapper.writeValueAsString(ObjectMapper.java:2097) ~[jackson-mapper-asl-1.9.13.jar:1.9.13]

tried to add deserializer:

CustomDeserializerFactory deserializerFactory = new CustomDeserializerFactory();
    deserializerFactory.addSpecificMapping(LocalDateTime.class, new   CustomLocalDateTimeDeserializer());
    ObjectMapper mapper = new ObjectMapper();
    mapper.setDeserializerProvider(new StdDeserializerProvider(deserializerFactory));
    try {
        remoteActionDto.setPayload(mapper.writeValueAsString(response));
    } catch (IOException e) {
        logger.error("Can not convert response to json!", e);
       .....
    }

the deserializer itself. I does not convert actually, but only proof of concept:

private static class CustomLocalDateTimeDeserializer extends JsonDeserializer<LocalDateTime> {

    @Override
    public LocalDateTime deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException {
        return new LocalDateTime();
    }
}

Upvotes: 0

Views: 11193

Answers (3)

Nikolay
Nikolay

Reputation: 1121

I found the problem (or actually a colleague of mine did it). It is the most stupid java behaviour I've ever met. The problem was, that the DTO which contained the LocalDateTime field was populated via reflection, and it seems possible to successfully set a value of type String. A class cast exception occurs when you try to use this field (not when it is being set).

public class MyDto {
  // trough reflection, the contained object is a java.lang.String
  private LocalDateTime myDate; 
}

If you ask why this happened - because we haven't configured a converter for LocalDateTime, but for DateTime instead. My colleague used LocalDateTime by mistake and Jackson silently deserialized it as a String

Upvotes: 2

harshit modani
harshit modani

Reputation: 141

Register your mapper with JodaModule module.

mapper.register(new JodaModule())

Or try with JodaMapper:

import com.fasterxml.jackson.datatype.joda.JodaMapper;

public static void main(String args[]){
     DateTime dateTime = new DateTime(12353434);
     JodaMapper mapper = new JodaMapper();
     try {
        serializedString = mapper.writeValueAsString(dateTime);
        System.out.println(serializedString);
    } catch (JsonProcessingException e) {
        e.printStackTrace();
    }
}

Console Output:

12353434

Upvotes: 0

Dan Temple
Dan Temple

Reputation: 2764

I've written a quick test class to check what you've provided. It seems to run fine and output the following:

{"value":[2014,2,24,13,42,44,745]}

Granted, that may not be the exact format you're looking for, but either way, here is the class:

public class JsonSerialization {

    public static void main(final String[] args) {
        try {
            final Response response = new Response();

            final ObjectMapper mapper = new ObjectMapper();
            final String value = mapper.writeValueAsString(response);
            System.out.println(value);
        }
        catch (final Exception e) {
            e.printStackTrace();
        }
    }

    public static class Response {
        LocalDateTime value = new LocalDateTime();
        public LocalDateTime getValue() {
            return this.value;
        }
        public void setValue(final LocalDateTime value) {
            this.value = value;
        }
    }
}        

I guess this raises the questions:

  • Do you have getters and setters for your LocalDateTime property (registrationDate)?
  • Are you sure the error is occurring where you think it is occurring? The exception is just the part about Jackson, where does it say the writeValueAsString method is called within your code?

I know this isn't part of your question, but in 1.9.13 of Jackson, you should register custom (de)serializers like so:

SimpleModule module = new SimpleModule("", new Version(1, 0, 0, "");
module.addDeserializer(LocalDateTime.class, new CustomLocalDateTimeDeserializer());
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(module);

Upvotes: 0

Related Questions