问题描述
我正在Spring Boot中构建一组微服务。我有一个与数据库连接的服务,并且具有其他应用程序可以访问的一系列RESTful端点。这些表实体中有许多是复杂的对象,可以作为JSON对象使用,但有些是简单的参数,因此可以用作字符串。当我命中主要的DB服务端点时,所有数据都可以正常返回而没有问题。
我还有一系列其他应用程序,它们以各种方式使用此数据。因为许多对象可在应用程序之间重复使用(DB服务响应形状,人员实体POJO等),所以我得到了一个由一些通用类组成的包。每个应用程序都会导入这些通用类,然后通过RestTemplate
调用主数据库服务。因为响应始终以标准方式包装,所以我通过执行交换来获取值,该交换期望使用适当的POJO或Java变量(字符串,整数等)来响应包装的ParameterizedTypeReference
。
截至5个月前,一切都很好。该应用程序已部署到服务器,并且仍可正常运行。但是,我最近回到代码中进行了一些修改,现在我发现在本地运行该应用程序时,某些端点会失败,并出现以下错误:
java.lang.NoSuchMethodError: com.fasterxml.jackson.annotation.JsonFormat$Value.hasLenient()Z
我起初以为这两个POM可能不同步,而一个正在拉动Jackson的较新版本,但是在对POM中的版本进行硬编码后,可以100%确定它们是相同的(2.10.1版),它仍然有相同的问题。还应该注意的是,错误消息中的方法似乎已在2.9版中添加,并且在此刻尚未弃用。仅当尝试从返回POJO的端点检索数据时才会发生此错误,而当数据类型为String时则不会发生。可能与之相关的是,该调用似乎在抛出错误之前从未真正离开应用程序,因为DB服务端点从未受到攻击。
响应对象:
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,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;
}
Person App 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文件是一个麻烦。我已经将所有相关类复制到主项目中,以消除对外部包的依赖,并且我遇到了同样的问题。我还尝试将所有版本完全升级到最新版本,但仍然没有运气。不论出于何种原因,Jackson都会将JSON映射到字符串或字符串列表,但不会将JSON映射到POJO。
解决方法
我最终弄清楚这里出了什么问题,这太荒谬了,以至于我不相信任何人都不会在没有手中代码的情况下得到正确的答案。只有通过将所有代码都放回一个位置,然后寻求通过杰克逊(直接使用ObjectMapper
而不是让RestTemplate
弄清楚)来找到另一种通过对象映射对象的方法,我偶然发现了真正的问题。
有一个审计类,它是我的Person对象上的一个属性,其中包含创建者,创建日期,修改者和修改日期的常规基本属性。这些日期是标准ISO-8601格式的LocalDateTime
对象。事实证明,杰克逊无法再将字符串直接处理到LocalDateTime
对象中,而需要“帮助”。通过添加一个以日期为字符串并使用LocalDateTime.parse(date)
来设置实际属性的设置器,我现在能够随意成功地击中端点。
我仍然不知道为什么会抛出上面的确切错误,但是在那里。通过未指定帮助从String
到LocalDateTime
对象转换的方法,我收到了Jackson的JsonFormat$Value.hasLenient()
错误。
我有一个类似的问题。
就我而言,@ Eyowzitgoin的回答帮助我弄清楚了我的问题。我在杰克逊注释上遇到了Maven依赖冲突。
我试图运行一些测试,但在命令行上一切都很好,但是intellij在知道选择哪个版本时遇到了问题。我已经明确声明了2.10.3
,但是2.8.5
是通过传递依赖来获取的。
2.10.3
具有方法JsonFormat$Value.hasLenient
,但2.8.5
没有。
我在pojo的String变量上使用了JsonFormat批注,而intellij希望能够调用该方法,但无法这样做。
对于我来说,我没有解决问题的根源,因为该变量应该是LocalDate,所以我更改了类型并删除了注释,问题就消失了。
我希望,如果我将类型保持原样并将注释保留在原处,而是解决了依赖性问题,并确保仅存在一个版本/声明了该问题,那么该问题也将得到解决。