Failed to parse "Date" from JSON - java

I have the following JSON string in REST response:
"09:41:50 CET"
For the corresponding POJO mapper class has a Date type for this field. So I've tried Jackson and GSON to map JSON to Java Object, but both failed with the following messages:
GSON: java.text.ParseException: Failed to parse date ["09:41:50 CET"]: Invalid number: 09:4
Jackson: InvalidFormatException: Cannot deserialize value of type `java.util.Date` from
String "09:41:50 CET": not a valid representation
Sadly I cannot modify in the POJO class the type to string or anything else, because I get those POJO classes from mvn dependency.

Try with this:
public static void main(String[] args) throws ParseException {
String jsonStr = "{ \"date\" : \"09:41:50 CET\" }";
Gson gson = new GsonBuilder().setDateFormat("HH:mm:ss").create();
JsonElement element = gson.fromJson (jsonStr, JsonElement.class);
OnlyDate date =gson.fromJson(element, new TypeToken<OnlyDate>(){}.getType());
System.out.println(date.getDate());
}
My example DTO is:
public class OnlyDate implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
#SerializedName("date")
private Date date ;
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
}
You have to specify the dateFormat of your gson Element

Not sure what kind of rest you have however if you are using spring rest you can do it by implementing custom Converter check the example at https://www.baeldung.com/spring-mvc-custom-data-binder.

Since Jackson v2.0, you can use #JsonFormat annotation directly on Object members;
#JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "HH:mm:ss", timezone="CET")
private Date date;

Related

Gson Removing Timestamp From Date while Conversion

I am using to convert JSON String to POJO Class using Gson. In Pojo the attribute are of java.util.Date type. While gson maps Json String to Pojo objects it is removing timestamp.
Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd'T'HH:mm:ss.S'Z'").create();
ClassBaseModel baseModel = gson.fromJson(request, ClassBaseModel.class);
Attribute Original Value in String Json is - "orderDate": "2021-12-01T07:16:31Z"
After It is converted into POJO - 2021-12-01
Expected is - 2021-12-01T07:16:31Z
I am not sure what wrong I am doing. Can somebody please point out.
While Deserializing you have to register deserializer type in gson using registerTypeAdapter
Here is how I have tried to do so, and also
Request class:
class OrderInfoRequest {
String orderDate;
public OrderInfoRequest(String orderDate) {
this.orderDate = orderDate;
}
}
Main Mapper class
class OrderInfo {
OffsetDateTime orderDate;
public OffsetDateTime getOrderDate() {
return orderDate;
}
public void setOrderDate(OffsetDateTime orderDate) {
this.orderDate = orderDate;
}
#Override
public String toString() {
return "OrderInfo{" +
"orderDate=" + orderDate +
'}';
}
}
Sample code
public class DateMain {
public static void main(String[] args) {
OrderInfoRequest orderInfoRequest = new OrderInfoRequest("2021-12-01T07:16:31Z");
Gson gson = new GsonBuilder()
.registerTypeAdapter(OffsetDateTime.class, (JsonDeserializer<OffsetDateTime>) (json, typeOfT, context) -> OffsetDateTime.parse(json.getAsString(), DateTimeFormatter.ISO_OFFSET_DATE_TIME))
.create();
String requestJson = gson.toJson(orderInfoRequest);
System.out.println("Request json");
System.out.println(requestJson);
OrderInfo orderInfo = gson.fromJson(requestJson, OrderInfo.class);
System.out.println("After parsing pojo");
System.out.println(orderInfo);
System.out.println("printing full date: " + orderInfo.orderDate.format(DateTimeFormatter.ofPattern("yyyy/MM/dd, hh:mm")));
}
}
Also as told by #Jens avoid using java.util.Date class from today onwards if you haven't.

How to deserialize date '2017-01-01T00:00:59.000UTC'

Trying to deserialize date with specific pattern from json file.
Object which I want to receive from json file:
#Data
public class MyClass {
#DateTimeFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss.SSS'UTC'")
#JsonDeserialize(using = LocalDateTimeDeserializer.class)
private LocalDateTime date;
}
Json file:
{
"date" : "2017-01-01T00:00:59.000UTC"
}
Code example how I want to receive it:
ObjectMapper mapper = new ObjectMapper();
MyClass clazz = mapper.readValue(new File("MyFile.json"), MyClass.class);
Actual result:
com.fasterxml.jackson.databind.exc.InvalidFormatException:
Cannot deserialize value of type `java.time.LocalDateTime` from String "2017-01-01T00:00:59.000UTC":
Failed to deserialize java.time.LocalDateTime: (java.time.format.DateTimeParseException)
Text '2017-01-01T00:00:59.000UTC' could not be parsed, unparsed text found at index 23
at [Source: (File); line: 2, column: 11] (through reference chain: com.example.MyClass["date"])
How to deserialize current date pattern?
The date format that you are using is incorrect.
Instead of: yyyy-MM-dd'T'HH:mm:ss.SSS'UTC'
it should be: yyyy-MM-dd'T'HH:mm:ss.SSSz
Secondly, you need to use #JsonFormat to specify the date format.
#JsonFormat which is defined in jackson-databind package gives you more control on how to format Date and Calendar values according to SimpleDateFormat.
By using this, the POJO MyClass would look something like this:
#Data
public class MyClass {
#JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSz", timezone = "UTC")
#JsonDeserialize(using = LocalDateTimeDeserializer.class)
private LocalDateTime date;
}
Now, if you try to deserialize using:
ObjectMapper mapper = new ObjectMapper();
MyClass clazz = mapper.readValue(new File("MyFile.json"), MyClass.class);
System.out.println(myClass);
Then the process would go through, producing a result something like this:
MyClass{date=2017-01-01T00:00:59.000}
Your date is in incorrect format (with UTC as text simply appended), but you can solve it by custom formatter.
public class Test {
public static void main(String[] args) throws JsonProcessingException {
ObjectMapper objectMapper = new ObjectMapper();
MyClass localDateTime = objectMapper.readValue("{\"date\":\"2017-01-01T00:00:59.000UTC\"}", MyClass.class);
System.out.println(localDateTime.date);
}
#Data
public static class MyClass {
#JsonDeserialize(using = CustomDeserializer.class)
private LocalDateTime date;
}
public static class CustomDeserializer extends LocalDateTimeDeserializer {
public CustomDeserializer() {
super(DateTimeFormatter.ISO_LOCAL_DATE_TIME);
}
protected CustomDeserializer(LocalDateTimeDeserializer base, Boolean leniency) {
super(base, leniency);
}
#Override
public LocalDateTime deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException {
String substring = jsonParser.getText().substring(0, jsonParser.getText().indexOf("U"));
return LocalDateTime.parse(substring, _formatter);
}
}
}
Try removing #JsonDeserialize. (In any case, you are trying to deserialize your date into LocalDateTime but it has time zone info, you would need to try ZonedDateTime or OffsetDateTime). And change the line
#DateTimeFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss.SSS'UTC'")
to
#JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSZ")
Here is the link to the question that has a full answer for you: Spring Data JPA - ZonedDateTime format for json serialization

How to send/receive a date object to be in a different format in JSON and not in timestamp?

I have the following POJO which I use to send out as messages to rabbitmq:
public class MyMessage {
private String id;
private String name;
private Date createdDt;
#JsonCreator
public MyMessage(
#JsonProperty("id") String id,
#JsonProperty("name") String name,
#JsonProperty("createdDt") Date createdDt
) {
this.id = id;
this.name = name;
this.createdDt = createdDt;
}
}
The problem with this is that when I send it using rabbitTemplate.convertAndSend(), the createdDt will be in unix timestamp in the JSON message. I need the createdDt in the JSON after serialised to be in the format of dd-MM-yyyy HH:mm:ss.
I don't want to change the createdDt property in MyMessage class to be a string in that formatted date because I may want to use the POJO else where in the code and having the date as a string is not convenient later. It also doesn't sound "right" to have the date in string just for the purpose of having it in a particular format.
When I'm receiving the message back, I also need to deserialise that string date in the format of dd-MM-yyyy HH:mm:ss back into a Date object.
How can I keep the createdDt as a Date object while sending the date in a different format when serialised and then have the string deserialised back as a date object?
If you must use java.util.Date then just add the following annotation onto the createdDt field
#JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "dd-MM-yyyy HH:mm:ss")
private Date createdDt;
I recommend not using java.util.Date but preferring the Java 8+ Time API. In that case you can import Jackson's built-in support via module com.fasterxml.jackson.datatype:jackson-datatype-jsr310 and ...
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new JavaTimeModule());
... will, by default, render LocalDateTime as an ISO 8601 string.
Ref: https://fasterxml.github.io/jackson-datatype-jsr310/javadoc/2.7/com/fasterxml/jackson/datatype/jsr310/JavaTimeModule.html
With that specific requirements regarding serialzation/deserialization of the field I would suggest using custom serializer/deserializer.
public class CustomDateSerializer extends StdSerializer<Date> {
 
    #Override
    public void serialize(Date value, JsonGenerator generator, SerializerProvider provider)
throws IOException, JsonProcessingException {
        // your implementation
    }
}
public class CustomDateDeserializer extends StdDeserializer<Item> {
#Override
public Date deserialize(JsonParser jp, DeserializationContext ctxt)
throws IOException, JsonProcessingException {
// your implementation
}
}
Then you can simply mark createdDt like this:
public class MyMessage {
private String id;
private String name;
private Date createdDt;
#JsonCreator
public MyMessage(
#JsonProperty("id") String id,
#JsonProperty("name") String name,
#JsonProperty("createdDt") #JsonDeserialize(using = CustomDateDeserializer.class) #JsonSerialize(using = CustomDateSerializer.class) Date createdDt
) {
this.id = id;
this.name = name;
this.createdDt = createdDt;
}
}
This way you instruct Jackson to use your specific serializer/deserializer on a specific field.
If you would like to make the configuration to be applied on ObjectMapper level you can achieve it with module registration like that:
SimpleModule myModule = new SimpleModule();
myModule.addSerializer(Date.class, new CustomDateSerializer());
myModule.addDeserializer(Date.class, new CustomDateDeserializer());
objectMapper.registerModule(myModule);

Spring, parsing string to LocalDateTime

I've got model and field like this:
#Element(name = "TIMESTAMP")
#DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME)
private LocalDateTime date;
In response I received:
<TIMESTAMP>2016-05-04T13:13:42.000</TIMESTAMP>
but during parsing xml to model I have error:
"message": "org.simpleframework.xml.core.PersistenceException: Constructor not matched for class java.time.LocalDateTime",
I also tried with:
#Element(name = "TIMESTAMP")
#DateTimeFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss.SSS")
private LocalDateTime date;
and this still doesn't work. Any Idea ? I am using springframework.xml lib.
The problem is by default simplexml lib doesn't know how to serialize/deserialize new Java8 date types.
In order to succeed you need to use custom converter.
Example entity (see the special #Convert annotation)
public class Entity {
#Element(name = "TIMESTAMP")
#Convert(LocalDateTimeConverter.class)
private LocalDateTime date;
// omitted
}
Special converter
public class LocalDateTimeConverter implements Converter<LocalDateTime> {
public LocalDateTime read(InputNode node) throws Exception {
String name = node.getValue();
return LocalDateTime.parse(name, DateTimeFormatter.ISO_LOCAL_DATE_TIME);
}
public void write(OutputNode node, LocalDateTime input) {
String value = input.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME);
node.setValue(value);
}
}
Usage
Strategy strategy = new AnnotationStrategy();
Persister persister = new Persister(strategy);
Entity serializedEntity = persister.read(Entity.class, xmlInputStream);
Full source is available on GitHub

Convert Date String (Unix format) to Java Date using Gson API's

I am trying to convert json string date time into java date object using Gson Api's where my json string date is in unix format ("CreatedOn":"/Date(1421909004755+0530)/"). My java code for the same is
MyJsonbuilder.java is having code
GsonBuilder gsonBuilder = new GsonBuilder();
Gson gson = gsonBuilder.create();
LogService book = gson.fromJson(dbDocument, LogService.class);
BasicDBObjectBuilder bs = new BasicDBObjectBuilder();
bs.append("CreatedOn", book.getCreatedOn());
where LogService.Java having getter and setter.
public Date getCreatedOn() {
return CreatedOn;
}
public void setCreatedOn(Date CreatedOn) {
this.CreatedOn = CreatedOn;
}
But gson API's are not able to take this date format which I am sending, but taking current date. Whereas if I change getter and setter from Date into String, it works fine.

Categories