Using Jersey Client 2.28 I am trying to receive a DTO containing the following data:
{
"entityId": "0de46a94-bc95-437f-9eca-dcfd60f7aed3",
"productId": "9c328c45-deba-4b84-8fb4-0d2aea885fc0",
"status": "ACTIVE",
"startDatetime": "2020-05-12T08:54:23Z",
"endDatetime": null,
}
When receiving it, I get the following error:
com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `java.time.Instant` (no Creators, like default construct, exist): no String-argument constructor/factory method to deserialize from String value ('2020-05-12T08:54:23Z')
at [Source: (org.glassfish.jersey.message.internal.ReaderInterceptorExecutor$UnCloseableInputStream); line: 1, column: 190] (through reference chain: com.fundraiser.dto.OfferDto["startDatetime"])
I know I should be able to retrieve this back without a ton of custom serializers or adapters. Upon googling it appears there's been other close issues to this, but none of them resolve my issue:
serialize/deserialize java 8 java.time with Jackson JSON mapper
I've tried adding combinations of these maven imports to get this to work, but nothing:
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jdk8</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
</dependency>
If I add the following jersey media moxy, I do get my object back, but any dates are marshalled as null:
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-moxy</artifactId>
<version>2.28</version>
</dependency>
I am using Spring Boot 2.2.0 and my pom.xml looks like the following:
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.0.RELEASE</version>
</parent>
<groupId>com.test</groupId>
<artifactId>test-webapp</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging>
<name>test-webapp</name>
<url>http://maven.apache.org</url>
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.8</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-client</artifactId>
<version>2.28</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.inject</groupId>
<artifactId>jersey-hk2</artifactId>
<version>2.28</version>
</dependency>
<dependency>
<groupId>com.test</groupId>
<artifactId>test-client</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>2.3.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.3.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
<version>2.3.0.RELEASE</version>
</dependency>
</dependencies>
<properties>
<java.version>11</java.version>
</properties>
<build>
<finalName>test-webapp</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>11</source>
<target>11</target>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
<defaultGoal>install</defaultGoal>
</build>
</project>
Is there something I'm blatantly missing? I just feel like this shouldn't be as big of a problem as it has been.
Code used to retrieve data:
public TestClient() {
this.client = ClientBuilder.newBuilder().register("application/json, */*").build();
}
private WebTarget webTarget() {
return client
.target(baseUri)
.path("api")
.path("v1");
}
private WebTarget entityTarget() {
return webTarget()
.path("entity");
}
public DataDto getEntityById(@NonNull UUID entityId) {
// Error occurs here
return entityTarget()
.path(entityId.toString())
.request(MediaType.APPLICATION_JSON)
.get(DataDto.class);
}
UPDATE: Added Dto class:
package com.test.dto;
import lombok.Data;
import lombok.experimental.Accessors;
import java.time.Instant;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
@Data
@Accessors(chain = true)
public class DataDto {
private UUID entityId;
private UUID productId;
private String status;
private Instant startDatetime;
private Instant endDatetime;
}
Try to register Jackson config provider to serialize jsr310 objects in Jaxrs client, check here.
Currently, I can NOT find an example exact same with your requirements, but Jersey, rest easy, and Apache CXF have their own client registration mechanism, you should consult the details of their documentation.
Update: I just updated one of my Spring/Jersey examples to demo how to resolve this, check the testing codes, register a custom Jackson context resolver to handle the Java 8 Datetime using the Spring configured Jackson ObjectMapper
, then Java 8 date-time object can be serialized/deserialized using IOS format.