I am trying to use postman and put these values into the database, but I keep getting an exception.
what im trying to deserialize from postman:
{
"end_date": "2443-11-34 12:43:23",
"start_date": "2443-11-34 12:43:23"
}
The exception that I get:
2020-05-20 10:55:04.572 WARN 4452 --- [nio-8080-exec-2] .w.s.m.s.DefaultHandlerExceptionResolver :
Resolved [org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot
deserialize value of type `java.time.Instant` from String "2443-11-34 12:43:23": Failed to deserialize
java.time.Instant: (java.time.format.DateTimeParseException) Text '2443-11-34 12:43:23' could not be
parsed at index 10; nested exception is com.fasterxml.jackson.databind.exc.InvalidFormatException: Cannot
deserialize value of type `java.time.Instant` from String "2443-11-34 12:43:23": Failed to deserialize
java.time.Instant: (java.time.format.DateTimeParseException) Text '2443-11-34 12:43:23' could not be parsed at index 10
at [Source: (PushbackInputStream); line: 3, column: 17] (through reference chain:
com.project.rushhour.model.post.AppointmentPostDTO["end_date"])]
appointment entity:
#Entity
#Data
#NoArgsConstructor
#AllArgsConstructor
public class Appointment extends BaseEntity {
#NotNull
#DateTimeFormat(style = "yyyy-MM-dd HH:mm:ss")
#JsonFormat(shape=JsonFormat.Shape.STRING, pattern="yyyy-MM-dd HH:mm:ss")
#JsonDeserialize(using = JacksonInstantDeserializer.class)
private Instant startDate;
#NotNull
#JsonDeserialize(using = JacksonInstantDeserializer.class)
#DateTimeFormat(style = "yyyy-MM-dd HH:mm:ss")
#JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss")
private Instant endDate;
My appointmentDto class:
#Data
#NoArgsConstructor
#AllArgsConstructor
public abstract class AppointmentDTO extends BaseDTO {
#JsonProperty("start_date")
private Instant startDate;
#JsonProperty("end_date")
private Instant endDate;
My AppointmentGetDTO class that I use
public class AppointmentGetDTO extends AppointmentDTO {
}
I also have all of the jackson dependencies
My custom deserializer that I use:
public class JacksonInstantDeserializer extends StdDeserializer<Instant> {
public JacksonInstantDeserializer() { this(null); }
public JacksonInstantDeserializer(Class<?> clazz) { super(clazz); }
#Override
public Instant deserialize(JsonParser parser, DeserializationContext ctx) throws IOException {
return Instant.parse(parser.getText());
}
}
You should create a CustomDeserializer for your class AppointmentGetDTO and not Instant class.
We need to register the AppointmentDTO class with the Deserializer. Below I have provided relevant code changes. User debugger and create breakpoints in the deserializer to test the conversion logic.
For further reading checkout: jackson-deserialization and this Stackoverflow answer
Read this for alternate approach: JsonComponent
AppointmentDTO:
#Data
#NoArgsConstructor
#AllArgsConstructor
public abstract class AppointmentDTO {
#JsonProperty("start_date")
private Instant startDate;
#JsonProperty("end_date")
private Instant endDate;
}
AppointmentGetDTO:
#JsonDeserialize(using= JacksonInstantDeserializer.class)
public class AppointmentGetDTO extends AppointmentDTO {
public AppointmentGetDTO(Instant s, Instant e) {
super(s,e);
}
}
Custom Deserializer for AppointmentGetDTO
public class JacksonInstantDeserializer extends StdDeserializer<AppointmentGetDTO> {
public JacksonInstantDeserializer() { this(AppointmentDTO.class); }
public JacksonInstantDeserializer(Class<?> clazz) { super(clazz); }
#Override
public AppointmentGetDTO deserialize(JsonParser parser, DeserializationContext ctx) throws IOException {
JsonNode node = parser.getCodec().readTree(parser);
Instant s=null;
Instant e=null;
if(node.get("start_date") != null) {
s=Instant.parse(node.get("start_date").asText());
}
if(node.get("end_date")!=null) {
e=Instant.parse(node.get("end_date").asText());
}
return new AppointmentGetDTO(s,e);
}
}
Then you can create bean of com.fasterxml.jackson.databind.Module like below:
#Bean
public Module dynamoDemoEntityDeserializer() {
SimpleModule module = new SimpleModule();
module.addDeserializer(AppointmentGetDTO.class, new JacksonInstantDeserializer());
return module;
}
Controller Mapping for the request:
#PostMapping
public AppointmentDTO convert(#RequestBody AppointmentGetDTO appointmentDTO) {
System.out.println(appointmentDTO.getStartDate());
System.out.println(appointmentDTO.getEndDate());
return appointmentDTO;
}
request json:
{
"end_date": "2443-11-12T12:43:23Z",
"start_date": "2443-11-12T12:43:23Z"
}
Related
I have a class AusgangsrechnungGeneral which has a property "abrechnungsmonat". It is set from JSON via Jackson which has the same property, but defined as "abrechnungsMonat" - which works fine.
Now I need to deserialize the property from
"abrechnungsMonat" -> "abrechnungsmonat"
but serialize it as
"abrechnungsmonat"
Therefore I implemented follwong code:
#JsonFormat(pattern="yyyy-MM")
#JsonDeserialize(using = YearMonthDeserializer.class)
#JsonSetter("abrechnungsMonat")
private YearMonth abrechnungsmonat;
#JsonGetter("abrechnungsmonat")
public YearMonth getAbrechnungsmonat() {
return this.abrechnungsmonat;
}
For other properties this method works fine, but here I got the following Error:
java.lang.IllegalStateException: Conflicting/ambiguous property name definitions (implicit name 'abrechnungsmonat'): found multiple explicit names: [abrechnungsmonat, abrechnungsMonat], but also implicit accessor: [field com.itf.ghost.propartsyncservice.api.rechnung.propartmodel.AusgangsrechnungGeneral#abrechnungsmonat][visible=true,ignore=false,explicitName=false]
I am using Lombok, but as far as I know Lombok will not generate additional getters if they are already defined. This is the class:
#NoArgsConstructor
#AllArgsConstructor
#Data
#ToString(callSuper = true)
#SuperBuilder
#JsonIgnoreProperties(ignoreUnknown = true)
public class AusgangsrechnungGeneral extends Rechnung {
#JsonSetter("leistungsZeitraum")
private String leistungszeitraum;
#JsonGetter("leistungszeitraum")
public String getLeistugnszeitraum() {
return this.leistungszeitraum;
}
private String filePath;
private Boolean isProberechnung;
#JsonFormat(pattern="yyyy-MM-dd")
#JsonDeserialize(using = LocalDateDeserializer.class)
private LocalDate bezahltAm;
#JsonFormat(pattern="yyyy-MM-dd")
#JsonDeserialize(using = LocalDateDeserializer.class)
private LocalDate zahlungErwartetAm;
#JsonFormat(pattern="yyyy-MM")
#JsonDeserialize(using = YearMonthDeserializer.class)
#JsonSetter("abrechnungsMonat")
private YearMonth abrechnungsmonat;
#JsonGetter("abrechnungsmonat")
public YearMonth getAbrechnungsmonat() {
return this.abrechnungsmonat;
}
#JsonSetter("kundenId")
private Long kunde;
#JsonGetter("kunde")
public Long getKunde() {
return this.kunde;
}
#JsonSetter("abls")
private List<AbrechenbareLeistung> abrechenbareLeistungen;
#JsonGetter("abrechenbareLeistungen")
public List<AbrechenbareLeistung> getAbrechenbareLeistungen() {
return this.abrechenbareLeistungen;
}
}
Solved it with:
#JsonFormat(pattern="yyyy-MM")
#JsonAlias("abrechnungsMonat")
#JsonDeserialize(using = YearMonthDeserializer.class)
#JsonSerialize(using = YearMonthSerializer.class)
private YearMonth abrechnungsmonat;
I need to deserialize the Json to Java Objects in Junit. I have Json file like
{
"studentId":57,
"JoinedDate":"31-12-2019",
"DOB":"08-06-1998"
}
I have class for the same to map
public class Student{
private long studentId ;
private LocalDate JoinedDate;
private LocalDate DOB ;
public long getStudentId() {
return studentId;
}
public void setStudentId(long studentId) {
this.studentId = studentId;
}
public LocalDate getJoinedDate() {
return JoinedDate;
}
public void setJoinedDate(LocalDate joinedDate) {
JoinedDate = joinedDate;
}
public LocalDate getDOB() {
return DOB;
}
public void setDOB(LocalDate dOB) {
DOB = dOB;
}
I need to write centralized builder for Unit testing project similar like this
builder.deserializers(new LocalDateDeserializer(DateTimeFormatter.ofPattern(dateFormat)));
builder.serializers(new LocalDateSerializer(DateTimeFormatter.ofPattern(dateFormat)));
Main Class
#RunWith(SpringRunner.class)
#SpringBootTest(classes = Main.class)
#WebAppConfiguration
public class Main{
#Test
public void contextLoads() {
assertTrue(true);
}
}
Unit testing Project looks like
#RunWith(SpringRunner.class)
#SpringBootTest(classes = Main.class)
#WebAppConfiguration
public class StudentTest{
private ObjectMapper jsonObjectMapper;
#Before
public void setUp() throws IOException {
jsonObjectMapper = new ObjectMapper();
studentJson = IOUtils.toString(getClass().getResourceAsStream(CommonTestConstants.StudentPath+ "/Student.json"));
}
I'm getting a error while mapping the objects -
com.fasterxml.jackson.databind.exc.InvalidFormatException: Cannot deserialize value of type java.time.LocalDate from String "31-12-2019": Failed to deserialize java.time.LocalDate:
Another Error - Sometimes.
com.fasterxml.jackson.databind.JsonMappingException: Text '31-12-2019'
could not be parsed at index 0
I assume LocalDate format mismatch is the issue. Any suggestion to make it centralized way instead of specifying the format above the fields. Any one please advise?
Reference - Spring Boot JacksonTester custom serializer not registered
You just need to specify the date format by default jackson allows format of yyyy-MM-dd
public class Student{
private long studentId ;
#JsonProperty("JoinedDate") #JsonFormat(pattern = "dd/MM/yyyy")
private LocalDate JoinedDate;
#JsonProperty("DOB") #JsonFormat(pattern = "dd/MM/yyyy")
private LocalDate DOB ;
public long getStudentId() {
return studentId;
}
public void setStudentId(long studentId) {
this.studentId = studentId;
}
public LocalDate getJoinedDate() {
return JoinedDate;
}
public void setJoinedDate(LocalDate joinedDate) {
this.JoinedDate = joinedDate;
}
public LocalDate getDOB() {
return DOB;
}
public void setDOB(LocalDate dOB) {
this.DOB = dOB;
}
I hope it helps you
Springboot 1.4.x or above has this interface Jackson2ObjectMapperBuilderCustomizer which allows you to initialize objectMapper.
What we need to do, is override customize method and register deserializers and
serializers.
#SpringBootApplication
public class TestApplication implements Jackson2ObjectMapperBuilderCustomizer {
#Override
public void customize(Jackson2ObjectMapperBuilder jackson2ObjectMapperBuilder) {
// pattern could be anything whatever is required
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy/dd/MM");
LocalDateSerializer localDateDeserializer = new LocalDateSerializer(formatter);
jackson2ObjectMapperBuilder
.failOnEmptyBeans(false)
.deserializersByType(new HashMap<Class<?>, JsonDeserializer<?>>(){{
put(LocalTime.class, localTimeSerializer);
}});
}
}
We can also add seriliazers similar way.
jackson2ObjectMapperBuilder
.failOnEmptyBeans(false)
.serializersByType(new HashMap<Class<?>, JsonSerializer<?>>(){{
put(LocalTime.class, localTimeSerializer);
}});
you can check more details here. Spring Jackson builder
I'm facing an error while deserialize the string to object.
org.opentest4j.MultipleFailuresError: Multiple Failures (2 failures)
com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot
construct instance of java.time.LocalDate (no Creators, like default
construct, exist): no String-argument constructor/factory method to
deserialize from String value ('2020-05-20') at [Source: (String)
JSON
{
"studentId":57,
"JoinedDate":"31-12-2019",
"DOB":"08-06-1998"
}
Model
public class Student{
private long studentId ;
private LocalDate JoinedDate;
private LocalDate DOB ;
public long getStudentId() {
return studentId;
}
public void setStudentId(long studentId) {
this.studentId = studentId;
}
public LocalDate getJoinedDate() {
return JoinedDate;
}
public void setJoinedDate(LocalDate joinedDate) {
JoinedDate = joinedDate;
}
public LocalDate getDOB() {
return DOB;
}
public void setDOB(LocalDate dOB) {
DOB = dOB;
}
Unit Test Class
#RunWith(SpringRunner.class)
#SpringBootTest(classes = Main.class)
#WebAppConfiguration
public class StudentTest{
private Student student;
private ObjectMapper jsonObjectMapper;
#Before
public void setUp() throws IOException {
jsonObjectMapper = new ObjectMapper();
jsonObjectMapper.setDateFormat(new SimpleDateFormat("dd-MM-yyyy"));
studentJson = IOUtils.toString(getClass().getResourceAsStream(CommonTestConstants.StudentPath+ "/Student.json"));
student = jsonObjectMapper.readValue(studentJson , Student.class);
}
Any one please advise
Reference
Cannot construct instance of `java.time.ZonedDateTime` (no Creators, like default construct, exist)
Unable to Deserialize - Jackson LocalDate/Time - JUnit
Include jackson jsr310 module.
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>2.11.0</version>
</dependency>
Register JavaTimeModule
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModule(new JavaTimeModule());
Mark the LocalDate type fields in your java class with following annotations.
#JsonFormat(pattern = "dd-MM-yyyy")
#JsonDeserialize(using = LocalDateDeserializer.class)
Complete code would be:
Main class or junit :
public static void main(String[] args) throws JsonProcessingException {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModule(new JavaTimeModule());
Student student = objectMapper.readValue(YOUR_JSON_STRING, Student.class);
System.out.println(student);
}
Student:
public class Student {
private long studentId;
#JsonProperty("JoinedDate")
#JsonFormat(pattern = "dd-MM-yyyy")
#JsonDeserialize(using = LocalDateDeserializer.class)
private LocalDate JoinedDate;
#JsonFormat(pattern = "dd-MM-yyyy")
#JsonDeserialize(using = LocalDateDeserializer.class)
private LocalDate DOB;
// getters and setters and ToString
}
I'm switching from MongoDB to DynamoDB on a project. Now I'm trying to store this Post object in the db. I'm using the DynamoDBTypeConverter to convert the ZonedDateTime to a String, as DynamoDB doesn't support ZonedDateTime.
That works fine, but when I'm adding a ZonedDateTime field in the Comment object and try to convert it too it doesn't work. I've tried adding a converter to the Comment class, and tried using the converter in the Post class for Comment, but nothing seems to work. Is there a way to convert a field in a nested object for DynamoDB?
com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMappingException: Cannot marshall type class java.time.ZonedDateTime without a custom marshaler or #DynamoDBDocument annotation.
#DynamoDBTable(tableName = "Post")
public class Post {
#DynamoDBHashKey
private String postNumber;
private ZonedDateTime date;
private List<Comment> comments;
#DynamoDBTypeConverted(converter = ZonedDateTimeConverter.class)
#DynamoDBAttribute
public ZonedDateTime getDate() {
return date;
}
#DynamoDBAttribute(attributeName = "comments")
public List<Comment> getComments() {
return comments;
}
static public class ZonedDateTimeConverter implements DynamoDBTypeConverter<String, ZonedDateTime> {
#Override
public String convert(final ZonedDateTime time) {
return time.toString();
}
#Override
public ZonedDateTime unconvert(final String stringValue) {
return ZonedDateTime.parse(stringValue);
}
}
#DynamoDBDocument
public class Comment {
private String commentNumber;
#NotNull
private User user;
private ZonedDateTime date;
#DynamoDBTypeConverted(converter = ZonedDateTimeConverter.class)
#DynamoDBAttribute
public ZonedDateTime getDate(){
return this.date;
}
static public class ZonedDateTimeConverter implements DynamoDBTypeConverter<String, ZonedDateTime> {
#Override
public String convert(final ZonedDateTime time) {
return time.toString();
}
#Override
public ZonedDateTime unconvert(final String stringValue) {
return ZonedDateTime.parse(stringValue);
}
}
I am trying to send put request and i receive the following error,
Failed to read HTTP message: org.springframework.http.converter.HttpMessageNotReadableException: Could not read document: Expected type float, integer, or string.
nested exception is com.fasterxml.jackson.databind.JsonMappingException: Expected type float, integer, or string.
Value in entity: (converter is of type: AttributeConverter, tried to remove it still doesn't work)
#Convert(converter = ZonedDateTimeConverter.class)
#DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME)
#Column(name = "LAST_MODIFIED")
protected ZonedDateTime lastModified;
Merge:
this.entityManager.merge(entity);
this.entityManager.flush();
Using:
jackson-datatype-jsr310
I tried to use JsonSerializer and JsonDeSerializer but the result is the same.
Converter:
#Converter(autoApply = true)
public class ZonedDateTimeConverter implements AttributeConverter<ZonedDateTime, Date> {
#Override
public Date convertToDatabaseColumn(final ZonedDateTime attribute) {
if(attribute == null){
return null;
}
return Date.from(attribute.toInstant());
}
#Override
public ZonedDateTime convertToEntityAttribute(final Date dbData) {
if(dbData == null) {
return null;
}
return ZonedDateTime.ofInstant(dbData.toInstant(), ZoneId.systemDefault());
}
}
Controller:
#Override
public ResponseEntity update(#RequestBody final DTO dto) {
boolean updated = this.service.update(dto);
if(updated){
return new ResponseEntity(HttpStatus.OK);
}
return new ResponseEntity(HttpStatus.NO_CONTENT);
}
The problem was that i put JsonSerializer and JsonDeSerializer on entity not on the DTO after changing