还有没有人注意到Java 21中Java泛型的变化?
我们使用Jdbi来访问数据库,当更新到Java 21时,由于泛型类型无法确定,所以会出错.
在调试过程中,我注意到一个条件
java.lang.reflect.Type type = ...
if (type instanceof Class) {..}
其中type
是一个接口,在Java 17中的计算结果为false
,但在Java 21中为true
.
JDbi的一些泛型依赖于Geantyref库.静态方法GenericTypeReflector.getTypeParameter(..)在Java 17中返回泛型类型,但在Java 21中返回null
.
在发布说明或其他公告中,我找不到任何关于Java 21中泛型的变化.也没有向后兼容的 destruct 性变化.
我假设由于记录反射(JEP-440)或switch 的模式匹配(JEP-441),一些内部功能可能已经改变,但这些功能我已经作为17预览功能使用,没有任何问题.
有人知道是什么导致了这些变化吗?为什么?
更新17-2023年11月
我想我已经想通了.我将问题追溯到Record类的构造函数参数. 似乎在Java 21中,对于记录类,默认构造函数的参数不知何故没有泛型类型. 所以对于像这样的唱片来说
record Person(Optional<String> name, Optional<Integer> age) {}
泛型类型String
和Integer
在Person的默认构造函数中丢失.
通过显式添加具有所有记录属性的规范构造函数,可以更改Java生成的默认构造函数:
record Person(Optional<String> name, Optional<Integer> age) {
@JdbiConstructor
public Person(Optional<String> aName, Integer anAge) {
this(aName, anAge);
}
}
通过添加@JdbiConstructor
注释(Jdbi总是需要记录中的注释),可以指示Jdbi使用哪个构造函数.
因为这个构造函数现在显式定义了参数类型,包括泛型类型,所以反射util能够确定类型,我让它与Java 21一起工作.
在过go 的2个小时里,我一直试图创建一个最小的测试用例,以验证泛型类型在Record的默认构造函数参数中丢失,但我无法在测试中重现它.即使它在我们的应用程序中始终失败. 我一直在比较类型参数,同时调试应用程序和测试.参数值和类型看起来相同,但在Java 21中测试仍然成功.
我现在离开测试,因为我必须继续我的工作,现在我确实有了一个通过添加额外的构造函数来解决问题的方法. 我稍后会试着回到这个问题上.它必须在简单的测试中是可重现的.
更新20-2023年11月
感谢Holger创建了一个小型测试用例来证明这个问题.
在11月17日的更新中,我犯了两个错误:
- 交换两个可选参数确实会创建一个不同的构造函数,因为被擦除的类型是相等的.
- 通过显式地提供规范构造函数来覆盖默认记录构造函数can.
我已经相应地更新了17日的更新.谢谢你指出这些错误.
我已经提交了一份ID为9076247
的错误报告,目前正在审查中.