簡體   English   中英

Spring Boot - Jersey 客戶端 - Jackson 無法構造 `java.time.Instant` 的實例

[英]Spring Boot - Jersey Client - Jackson Cannot construct instance of `java.time.Instant`

使用 Jersey Client 2.28 我試圖接收包含以下數據的 DTO:

{
    "entityId": "0de46a94-bc95-437f-9eca-dcfd60f7aed3",
    "productId": "9c328c45-deba-4b84-8fb4-0d2aea885fc0",
    "status": "ACTIVE",
    "startDatetime": "2020-05-12T08:54:23Z",
    "endDatetime": null,
}

收到后,我收到以下錯誤:

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"])

我知道我應該能夠在沒有大量自定義序列化程序或適配器的情況下檢索它。 在谷歌上搜索后,似乎還有其他接近的問題,但沒有一個能解決我的問題:

使用 Jackson JSON 映射器序列化/反序列化 java 8 java.time

JSON 解析錯誤:無法構造 java.time.LocalDate 的實例:沒有從字符串值反序列化的字符串參數構造函數/工廠方法

我已經嘗試添加這些 maven 導入的組合來使其工作,但沒有:

<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>

如果我添加以下 jersey media moxy,我會取回我的對象​​,但任何日期都被編組為 null:

<dependency>
  <groupId>org.glassfish.jersey.media</groupId>
  <artifactId>jersey-media-moxy</artifactId>
  <version>2.28</version>
</dependency>

我使用的是 Spring Boot 2.2.0,我的 pom.xml 如下所示:

<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>

有什么我明顯缺少的東西嗎? 我只是覺得這不應該是一個大問題。

用於檢索數據的代碼:


 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);
    }

更新:添加了 Dto 類:

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;
}
  • 首先,問題中共享的 json 不是有效的 json。 刪除,"endDatetime": null
  • @NoArgsConstructor注釋添加到您的DataDto類。
  • 注冊 ObjectMapper 以禁用Instant作為時間戳的序列化/反序列化,默認情況下會這樣做。

對我有用的示例代碼。 我知道你是通過客戶做的,但我認為這應該對你有幫助。 創建時將自定義對象映射器傳遞給客戶端,或者將 JSON 作為字符串獲取並手動轉換。

public class MapperInstant {

    public static void main(String[] args) throws Exception {
        String s = "{\n" +
                "    \"entityId\": \"0de46a94-bc95-437f-9eca-dcfd60f7aed3\",\n" +
                "    \"productId\": \"9c328c45-deba-4b84-8fb4-0d2aea885fc0\",\n" +
                "    \"status\": \"ACTIVE\",\n" +
                "    \"startDatetime\": \"2020-05-12T08:54:23Z\",\n" +
                "    \"endDatetime\": null\n" +
                "}";

        ObjectMapper objectMapper = new ObjectMapper()
                .findAndRegisterModules()
                .disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);

        DataDto dataDto = objectMapper.readValue(s, DataDto.class);
        System.out.println(dataDto);
    }

    @Data
    @NoArgsConstructor
    @Accessors(chain = true)
    public static class DataDto {
        private UUID entityId;
        private UUID productId;
        private String status;
        private Instant startDatetime;
        private Instant endDatetime;
    }
}

嘗試注冊 Jackson 配置提供程序以在 Jaxrs 客戶端序列化 jsr310 對象,請查看此處

目前,我找不到與您的要求完全相同的示例,但是請放心,Apache CXF 有自己的客戶端注冊機制,您應該查閱其文檔的詳細信息。

更新:我剛剛更新了我的 Spring/Jersey 示例之一來演示如何解決此問題,檢查測試代碼,注冊自定義 Jackson 上下文解析器以使用 Spring 配置的 Jackson ObjectMapper處理 Java 8 日期時間,然后是 Java 8 日期時間對象可以使用 IOS 格式進行序列化/反序列化。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM