1

我正在 Spring Boot 中构建一组微服务。我有一个与数据库接口的服务,并且有一系列其他应用程序可以访问的 RESTful 端点。这些表实体中有许多是复杂对象并作为 JSON 对象提供,但有些是简单参数,因此作为字符串提供。当我点击主要的数据库服务端点时,所有数据都可以正常返回,没有问题。

我有一系列其他应用程序以各种方式使用这些数据。因为许多对象在应用程序中被重用(DB 服务响应形状、人实体 POJO 等),所以我有一个由一些通用类组成的包。每个应用程序都会导入这些公共类,然后通过RestTemplate. 因为响应总是以标准方式包装,所以我通过执行交换来获取值,该交换期望ParameterizedTypeReference响应包装器具有适当的 POJO 或 Java 变量(字符串、int 等)。

截至5个月前,一切都很好。该应用程序已部署到服务器并且仍在正常运行。但是,我最近返回代码进行一些修改,现在我发现当我在本地运行应用程序时,一些端点失败并出现以下错误:

java.lang.NoSuchMethodError: com.fasterxml.jackson.annotation.JsonFormat$Value.hasLenient()Z

起初我以为这两个 POM 可能不同步,一个正在拉更新版本的 Jackson,但是在 POM 中对版本进行硬编码以 100% 确定它们是相同的(版本 2.10.1)之后,它仍然有同样的问题。还应注意,错误消息中的方法似乎已在 2.9 版中添加,并且截至目前尚未弃用。此错误仅在尝试从返回 POJO 的端点检索数据时发生,而不是在数据类型为字符串时发生。调用似乎永远不会在引发错误之前真正离开应用程序也可能相关,因为数据库服务端点永远不会被命中。

任何想法为什么我会收到此错误以及如何解决它?

响应对象:

public class DatabaseServiceResponse<T> {
    @JsonInclude(Include.NON_NULL)
    private List<T> entities;
    
    @JsonInclude(Include.NON_NULL)
    private String error;
    
    [getters and setters ommitted]
}

个人服务:

public List<Person> getPeople() {
    List<Person> people = new ArrayList<>();
    HttpHeaders headers = getHeaders();
    HttpEntity<Object> requestEntity = new HttpEntity<>(null, headers);
    ResponseEntity<DatabaseServiceResponse<Person>> response = restTemplate.exchange(url, HttpMethod.GET, requestEntity, new ParamaterizedTypeReference<DatabaseServiceResponse<Person>>() {});  // Fails on this line
    if (response.getStatusCode() == HttpStatus.OK) {
        people = response.getBody().getEntities();
    } else {
        throw new ServiceException("Error retrieving people");
    }
    return people;
}

public List<String> getPersonTypes() {
    List<String> personTypes = new ArrayList<>();
    HttpHeaders headers = getHeaders();
    HttpEntity<Object> requestEntity = new HttpEntity<>(null, headers);
    ResponseEntity<DatabaseServiceResponse<String>> response = restTemplate.exchange(url, HttpMethod.GET, requestEntity, new ParamaterizedTypeReference<DatabaseServiceResponse<String>>() {});  // Works fine here
    if (response.getStatusCode() == HttpStatus.OK) {
        personTypes = response.getBody().getEntities();
    } else {
        throw new ServiceException("Error retrieving person types");
    }
    return personTypes;
}

个人应用 POM:

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.2.2.RELEASE</version>
    <relativePath />
</parent>

常见元素 POM:

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.10.1</version>
    <scope>provided</scope>
</dependency>

更新 我相信外部库和可能不同步的 POM 文件是一个红鲱鱼。我已将所有相关类复制到主项目中,以消除对外部包的依赖,我也遇到了同样的问题。我还尝试将所有版本完全升级到最新版本,但仍然没有运气。无论出于何种原因,杰克逊都会将 JSON 映射到字符串或字符串列表,但不会将我的 JSON 映射到 POJO。

4

2 回答 2

1

终于弄清楚了这里出了什么问题,这感觉太荒谬了,以至于我不相信没有人手中的代码会得到正确的答案。只有将所有代码拉回一个地方,然后通过杰克逊寻找另一种映射对象的方法(ObjectMapper直接使用而不是让RestTemplate数字出来),我才偶然发现了真正的问题。

有一个审计类,它是我的 Person 对象上的一个属性,它包含创建者、创建日期、修改者、修改日期的正常基本属性。这些日期是LocalDateTime标准 ISO-8601 格式的对象。事实证明,杰克逊不能再将字符串直接处理成LocalDateTime对象,需要“帮助”。通过添加一个将日期作为字符串并执行 aLocalDateTime.parse(date)来设置实际属性的 setter,我现在可以随意成功地命中端点。

我仍然不知道为什么会抛出上面的确切错误,但是你有它。由于没有指定帮助从 aString转换为LocalDateTime对象的方法,我收到了JsonFormat$Value.hasLenient()Jackson 的错误。

于 2020-09-10T18:12:58.520 回答
1

我有一个类似的问题。

就我而言,@Eyowzitgoin 的回答帮助我弄清楚了我的问题。我对杰克逊注释有一个 Maven 依赖冲突。

我试图运行一些测试,在命令行上一切都很好,但是 intellij 在知道选择哪个版本时遇到了问题。我已经2.10.3明确声明,但2.8.5通过传递依赖被拾取。

2.10.3有方法JsonFormat$Value.hasLenient,但2.8.5没有。

我在 pojo 中的 String 变量上使用 JsonFormat 注释,而 intellij 希望能够调用该方法,但无法这样做。

就我而言,我没有解决问题的根源,因为变量应该是 LocalDate,所以我更改了类型并删除了注释,问题就消失了。

我希望如果我将类型保留原样并保留注释,而是解决依赖问题并确保只有一个版本存在/声明了该问题也将得到解决。

于 2020-10-27T16:44:31.533 回答