JSON Java 8 LocalDateTime format using Jackson in Vert.x - java

I am trying to create json object from LocaLDateTime but for some reason it is creating json like so, look for issueAt and expireAt key
json {"userID":0,"deviceID":0,"refreshToken":"93180548-23b3-4d1b-8b5b-a105b7cff7f9","issuedAt":{"year":2021,"monthValue":10,"dayOfMonth":27,"hour":9,"minute":22,"second":31,"nano":0,"month":"OCTOBER","dayOfWeek":"WEDNESDAY","dayOfYear":300,"chronology":{"id":"ISO","calendarType":"iso8601"}},"expiresAt":{"year":2021,"monthValue":10,"dayOfMonth":28,"hour":9,"minute":22,"second":31,"nano":0,"month":"OCTOBER","dayOfWeek":"THURSDAY","dayOfYear":301,"chronology":{"id":"ISO","calendarType":"iso8601"}}}
I want it to be like so
batch: [0,0,29a1bf70-648e-4cb5-aef8-5377cf702875,2021-10-26T12:36:10,2021-10-27T12:36:10] .
My code for creating the 2 dates is below
String randomString = UUID.randomUUID().toString();
Instant myInstant1 = Instant.now().truncatedTo(ChronoUnit.SECONDS);
LocalDateTime issuedAt = LocalDateTime.ofInstant(myInstant1, ZoneId.systemDefault());
System.out.println("issued_at : " + issuedAt);
LocalDateTime expiresAt = issuedAt.plusDays(1);
System.out.println("expires_at: " + expiresAt.plusDays(1));
In the below code is where I get the error when I try to use mapto to add the json object to my class object.
JsonObject json = new JsonObject()
.put("userID", userID)
.put("deviceID", deviceID)
.put("refreshToken", randomString)
.put("issuedAt", issuedAt)
.put("expiresAt", expiresAt);
LOG.info("json {}", json.encode());
RefreshToken refreshTokenObj = json.mapTo(RefreshToken.class); //here I am trying to mapTo my class and I get the error
LOG.info("refreshTokenObj {}", refreshTokenObj);
The error I get is
2021-10-27 09:22:31.133+0330 [vert.x-eventloop-thread-1] ERROR com.galiy.main.MainVerticle - Unhandled:
java.lang.IllegalArgumentException: Cannot construct instance of java.time.LocalDateTime (no Creators, like default constructor, exist): cannot deserialize from Object value (no delegate- or property-based Creator)
at [Source: UNKNOWN; line: -1, column: -1] (through reference chain: com.galiy.security.refreshToken.RefreshToken["issuedAt"])
at com.fasterxml.jackson.databind.ObjectMapper._convert(ObjectMapper.java:4236) ~[jackson-databind-2.11.4.jar:2.11.4]
and my RefreshToken model is like so,
public class RefreshToken {
private Integer id;
private Integer userID;
private Integer deviceID;
private String refreshToken;
private LocalDateTime issuedAt;
private LocalDateTime expiresAt;

I am not familiar with Vert.x. But according to our discussion under the post, I simply add following 2 line of code before mapTo() and got no error.
ObjectMapper objectMapper = DatabindCodec.mapper();
objectMapper.registerModule(new JavaTimeModule());
Console output:
RefreshToken{id=null, userID=0, deviceID=0, refreshToken='9da220ce-bc66-4561-b924-988c7f394f2d', issuedAt=2021-10-27T17:21:28, expiresAt=2021-10-28T17:21:28}
And in my experience, you can also configure ObjectMapper to handle the output format of LocalDateTime as you want while serialization as follows:
objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);

You will need to annotate your LocalDateTime member as follows:
#JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss")
LocalDateTime myTime
Here is the link to full answer that explains all the details: Spring Data JPA - ZonedDateTime format for json serialization

Related

Issue with OffsetDateTime deserialization from json request body Spring-Boot REST API

I'm having a OffsetDateTime field in my POJO:
#NotBlank(message = "startTime cannot be null or empty; ")
#JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSXXX")
#JsonSerialize(using = OffsetDateTimeSerializer.class)
private OffsetDateTime startTime;
When I try to give the request body for the API with this offsetTime JSON field, it shows deserialization error:
: Resolved
[org.springframework.http.converter.HttpMessageNotReadableException:
JSON parse error: Cannot deserialize value of type `java.time.OffsetDateTime`
from String "2020-07-21T12:12:23.000+0200":
Failed to deserialize java.time.OffsetDateTime: (java.time.format.DateTimeParseException)
Text '2020-07-21T12:12:23.000+0200' could not be parsed at index 23;
nested exception is com.fasterxml.jackson.databind.exc.InvalidFormatException:
Cannot deserialize value of type `java.time.OffsetDateTime`
from String "2020-07-21T12:12:23.000+0200":
Failed to deserialize java.time.OffsetDateTime: (java.time.format.DateTimeParseException)
Text '2020-07-21T12:12:23.000+0200' could not be parsed at index 23
Is my input correct and how to deserialize this field from JSON?

Jackson serialize Joda DateTime from simple String

I am trying to extract a value of predefined type (Boolean, Integer, joda.DateTime) from an arbitrary json that is sent as a String.
Eg: {"node1":{"node2":"2019-01-01T05:00:00.000Z"}}} and say I know that the value in this Json is a DateTime and I can extract the value 2019-01-01T05:00:00.000Z from this Json and disabled SerializationFeature.WRITE_DATES_AS_TIMESTAMPS.
When I try to serialize a simple String representation "1972-12-28T12:00:01.000Z" of org.joda.time.DateTime, it fails with JsonParseException: Unexpected character. However serialization will succeed for Booleans or DateTime string inside a TextNode.
I have have registered com.fasterxml.jackson.datatype.joda.JodaModule with my object mapper.
I have tried a few things, see the Junit test below
public class Tester {
public static class Bean {
public void Bean(){}
public DateTime start;
}
#Test
public void testJodaJsonSerialization() throws Exception{
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
objectMapper.registerModule(new JodaModule());
final String INPUT_JSON = "{\"start\" : \"1972-12-28T12:00:01.000Z\"}";
Bean bean = objectMapper.readValue(INPUT_JSON, Bean.class);
assertNotNull(bean.start);
System.out.println(objectMapper.writeValueAsString(bean)); //serializing as part of an object works
String boolAsString = "true";
Boolean aBoolean = objectMapper.readValue(boolAsString, Boolean.class); //works for bool (simple type)
System.out.println(aBoolean);
String dateAsTextNode = objectMapper.writeValueAsString(new TextNode("1972-12-28T12:00:01.000Z")); //works for TextNode
System.out.println("dateAsTextNode: " + dateAsTextNode);
DateTime dateTime = objectMapper.readValue(dateAsTextNode, DateTime.class);
System.out.println(dateTime);
JsonNode jsonRoot = objectMapper.readTree(INPUT_JSON);
String datetimeAsString = jsonRoot.get("start").asText();
objectMapper.readValue(objectMapper.writeValueAsString(new TextNode(datetimeAsString)), DateTime.class); //this workaround will work
objectMapper.readValue(objectMapper.writeValueAsString(new TextNode(boolAsString)), Boolean.class);
String dateAsString = "1972-12-28T12:00:01.000Z";
objectMapper.readValue(dateAsString, DateTime.class); //but this fails
}
}
I expect String serialization to work just like it does on the TextNode
Your String
String dateAsString = "1972-12-28T12:00:01.000Z";
contains the content
1972-12-28T12:00:01.000Z
which is not valid JSON, so Jackson cannot parse it.
It would be valid JSON if it contained leading quotes, so
String dateAsString = "\"1972-12-28T12:00:01.000Z\"";
and then parsing would succeed.
You can configure the pattern of the date format on the ObjectMapper level:
Value dateFormat = Value.forShape(Shape.STRING)
.withPattern("MM/dd/yyyy HH:mm:ss")
.withTimeZone(TimeZone.getTimeZone("UTC"));
ObjectMapper mapper = new ObjectMapper();
mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false)
.registerModule(new Jdk8Module())
.registerModule(new JavaTimeModule())
.configOverride(DateTime.class).setFormat(dateFormat);

Jackson Data Binding for LocalDate[] using annotation

I am converting a JSON file into Java object using Jackson with Java 8 Module. But while converting JSON array to LocalDate[] application is throwing an exception.
How to convert below JSON array to LocalDate[] using annotations?
JSON
{
"skip": [
"01/01/2019",
"26/01/2019"
]
}
Code
#JsonFormat(pattern = "dd/MM/yyyy")
#JsonSerialize(using = LocalDateSerializer.class)
#JsonDeserialize(using = LocalDateDeserializer.class)
private LocalDate[] skip;
Exception
com.fasterxml.jackson.databind.exc.MismatchedInputException: Unexpected token (VALUE_STRING) within Array, expected VALUE_NUMBER_INT
at [Source: (ByteArrayInputStream); line: 25, column: 3] (through reference chain: com.saalamsaifi.springwfrlroster.model.Team["skip"])
at com.fasterxml.jackson.databind.exc.MismatchedInputException.from(MismatchedInputException.java:63)
at com.fasterxml.jackson.databind.DeserializationContext.reportInputMismatch(DeserializationContext.java:1343)
at com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer.deserialize(LocalDateDeserializer.java:110)
at com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer.deserialize(LocalDateDeserializer.java:38)
at com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.java:127)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:288)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:151)
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4013)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3070)
Since skip is of type array, LocalDateSerializer, LocalDateDeserializer and JsonFormat do not work out of the box - they are implemented to expect direct value tokens and not arrays.
You can implement your own serializer/deserializers. A naive deserializer I implemented to deserialize your example is the following:
public class CustomLocalDateArrayDeserializer extends JsonDeserializer<LocalDate[]> {
private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd/MM/yyyy");
#Override
public LocalDate[] deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
ArrayList<LocalDate> list = new ArrayList<>();
JsonToken currentToken = p.getCurrentToken();
if (currentToken != JsonToken.START_ARRAY) {
throw new JsonMappingException(p, "Not an array!");
}
currentToken = p.nextToken();
while (currentToken != JsonToken.END_ARRAY) {
if (currentToken != JsonToken.VALUE_STRING) {
throw new JsonMappingException(p, "Not a string element!");
}
LocalDate localDate = LocalDate.parse(p.getValueAsString(), formatter);
list.add(localDate);
currentToken = p.nextToken();
}
return list.toArray(new LocalDate[0]);
}
}
And I changed the field annotation to be #JsonDeserialize(using = CustomLocalDateArrayDeserializer.class).
You can work on it to iterate & improve over it, make it read&respect #JsonFormat annotation and so on, if you think it is worth the effort.
I suspect looking at your code and your json model it is trying to convert to an array using a deserializer that is defined for one object. It simple terms you are trying to convert a single item to an array which it cant parse. You could Try a list of LocalDate instead. Something Like:
List<LocalDate> skip;
You might even need to create your own Deserializer based on the date serializer.
Just first glance: are actually json objects in your json array or just Strings as you showed? This should be something like this:
{
"skip": [
"key1":"01/01/2019",
"key2":"26/01/2019"
]
}

Cassandra date insert from Java Spring Project

To the type date in cassandra database I would like to insert a value.
I tried with types java.util.Date and com.datastax.driver.core.LocalDate.
Both ways don't work for me.
For LocalDate error:
"JSON parse error: Can not construct instance of com.datastax.driver.core.LocalDate: no String-argument constructor/factory method to deserialize from String value (''); nested exception is com.fasterxml.jackson.databind.JsonMappingException: Can not construct instance of com.datastax.driver.core.LocalDate: no String-argument constructor/factory method to deserialize from String value ('')\n at [Source: java.io.PushbackInputStream#4d549b00; line: 10, column: 25] (through reference chain: com.comarch.programs.dtos.ProgramDto[\"prgStartDate\"])",
Date error:
"Expected 4 byte long for date (8); nested exception is com.datastax.driver.core.exceptions.InvalidQueryException: Expected 4 byte long for date (8)"
You can do the following way:
private Date accessDate;
#Transient
private Date activeDate;
public Date getActiveDate() {
return activeDate;
}
public void setActiveDate(Date activeDate) {
SimpleDateFormat sp1 = new SimpleDateFormat("yyyyy-MM-dd hh:mm:ss+0000");
String strDate = sp1.format(activeDate);
try {
this.activeDate = sp1.parse(strDate);
setAccessDate(new java.sql.Timestamp(this.activeDate.getTime()));
} catch (ParseException e) {
e.printStackTrace();
}
}
Use a transient data to format the date accordingly and set the date using java.sql.Timestamp

Can not construct instance of javax.xml.datatype.XMLGregorianCalendar from String value

I'm trying to take an XML String and deserialize it into an object. I keep getting this exception though:
com.fasterxml.jackson.databind.exc.InvalidFormatException: Can not construct instance of javax.xml.datatype.XMLGregorianCalendar from String value '22:32:00': not a valid representation (error: Failed to parse Date value '22:32:00': Unparseable date: "22:32:00")
When it gets to this line:
xmlMapper.readValue(xml, clazz);
My XML contains:
<MyXML>
<Event>
<Time>22:32:00</Time>
</Event
</MyXML>
My object class member variable is:
#XmlElement(name = "Time", required = true)
#XmlSchemaType(name = "time")
#JsonProperty("Time")
#JsonFormat(pattern = "HH:mm:ss", timezone = "GMT+0100")
protected XMLGregorianCalendar time;
Is there anything wrong with this configuration that would cause the above exception?

Categories

Resources