Tuesday, June 20, 2017

Could not read JSON: Can not construct instance of java.util.Date

I have a Rest service which takes a parameter "timestamp"of Date type. I am getting following exception when I make request to this service:

Following is my sample request :

{
"status" : "EMPLOYEE_ADDED",
"timestamp" : "2015-11-04T15:53Z"
}

16:30:37.105 [[ACTIVE] ExecuteThread: '0' for queue: 'weblogic.kernel.Default (self-tuning)'] DEBUG o.s.w.s.m.m.a.ExceptionHandlerExceptionResolver -
Resolving exception from handler [public org.springframework.http.HttpEntity<com.test.Response>
com.test.rest.controller.TestRestController.updateStatus(com.test.model.StatusRequest)]:
org.springframework.http.converter.HttpMessageNotReadableException:
Could not read JSON: Can not construct instance of java.util.Date from String value '2015-11-04T15:53Z': not a valid representation (error: Failed
to parse Date value '2015-11-04T15:53Z': Can not parse date "2015-11-04T15:53Z": not compatible with any of standard forms ("yyyy-MM-dd'T'HH:mm:ss.SSSZ", "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", "EEE, dd MMM yyyy HH:mm:ss zzz", "yyyy-MM-dd"))


Solution:

This kind of exception is thrown when passed value can not be parsed to target type. We can override the serilization and deserialization behavior by using @JsonSerialize and @JsonDeserialize annotations.

I created a custom Serializer and Deserializer class and used it with @JsonSerialize and @JsonDeserialize annotation as shown below. I added these annotation in StatusRequest class which the request object for my rest service:

import java.util.Date;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.custom.DateTimeJsonDeserializer;
import com.custom.DateTimeJsonSerializer;

public class StatusRequest {

         private Date timestamp;

        /**
* @return the timestamp
*/
@JsonSerialize(using = DateTimeJsonSerializer.class)
public Date getTimestamp() {
return timestamp;
}

/**
* @param timestamp the timestamp to set
*/
@JsonDeserialize(using = DateTimeJsonDeserializer.class)
public void setTimestamp(Date timestamp) {
this.timestamp = timestamp;
}

}


  • Custom Deserializer :

package com.custom;

import java.io.IOException;
import java.text.ParseException;
import java.util.Date;
import java.util.TimeZone;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.util.ISO8601DateFormat;

/**
 * JSON Deserializer to parse dates in ISO-8601 standard date/time format.
 *
 * @author Sanjay Ingole
 */
public class DateTimeJsonDeserializer extends JsonDeserializer<Date> {
private static final Logger LOG = LoggerFactory.getLogger(DateTimeJsonDeserializer.class);

/** UTC (GMT) timezone. */
private static final TimeZone UTC = TimeZone.getTimeZone("UTC");

/**
* Constructor.
*/
public DateTimeJsonDeserializer() {
super();
}

@Override
public Date deserialize(JsonParser p, DeserializationContext ctxt) throws IOException,
JsonProcessingException {
String value = p.getValueAsString();
if (StringUtils.isEmpty(value)) {
return null;
}
try {
ISO8601DateFormat formatter = new ISO8601DateFormat();
formatter.setTimeZone(UTC);

return formatter.parse(value.trim());
} catch (ParseException ex) {
LOG.error("deserialize: An exception occurred", ex);
throw new JsonMappingException("Unable to parse value [" + value
+ "] as a ISO8601 date", ex);
}
}

}

  • Custom Serializer :
package com.custom;

import java.io.IOException;
import java.util.Date;
import java.util.TimeZone;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.util.ISO8601DateFormat;

/**
 * JSON Serializer to output dates in ISO-8601 standard date/time format.
 *
 * @author Sanjay Ingole
 */
public class DateTimeJsonSerializer extends JsonSerializer<Date> {
/** UTC (GMT) timezone. */
private static final TimeZone UTC = TimeZone.getTimeZone("UTC");

/**
* Constructor.
*/
public DateTimeJsonSerializer() {
super();
}

@Override
public void serialize(Date value, JsonGenerator gen, SerializerProvider serializers)
throws IOException, JsonProcessingException {

String formattedDate;

if (value == null) {
formattedDate = "";
} else {
ISO8601DateFormat formatter = new ISO8601DateFormat();
formatter.setTimeZone(UTC);
formattedDate = formatter.format(value);
}

gen.writeString(formattedDate);
}

}


1 comment:

  1. org.springframework.http.converter.HttpMessageNotReadableException: Could not read JSON: Unable to parse value [2003-03-14 16:33:54.643] as a ISO8601 date (through reference chain: com.ctl.vane.rest.ca.services.model.KADetails["dateModified"]); nested exception is com.fasterxml.jackson.databind.JsonMappingException: Unable to parse value [2003-03-14 16:33:54.643] as a ISO8601 date (through reference chain: com.ctl.vane.rest.ca.services.model.KADetails["dateModified"]),

    After adding jsonserialize and deserialize unable to get the ouput

    ReplyDelete