java - 为什么 Lombok 在覆盖通用 getter 时会生成额外的 Getter?
问题描述
我有一个接口,它定义了一个 id 字段(和其他字段,但正在简化),它使用 Java 的泛型。
我正在使用 Lombok 为实现此功能的类生成 Getter 和 Builder。
在IdType getId()
界面中,Lombok 正在生成Object getId()
, 和UUID getId()
. 这两种方法在通过反射调用时都可以工作,但它非常奇怪,并且弄乱了一些假设一个类不会有多个具有相同名称和不同返回类型的方法的代码。
(我 <3 反射)
这是一个显示此行为的单元测试。我的龙目岛错了吗?我需要申请其他注释吗?我是否只是耸耸肩并编写代码让所有吸气剂检查并避免它?
Java 8,Lombok 1.18.16,目前是最新的。
public class LombokGeneratesDuplicateMethodsTest {
interface WithId<IdType> {
IdType getId();
}
@Getter
@Builder
static class Record implements WithId<UUID> {
private UUID id;
private String name;
}
@Test
public void testStuff() throws Exception {
Collection<Method> getIds = Arrays.stream(Record.class.getDeclaredMethods())
.filter(m -> Modifier.isPublic(m.getModifiers()))
.filter(m -> !Modifier.isStatic(m.getModifiers()))
.filter(m -> !Void.TYPE.equals(m.getReturnType()))
.filter(m -> m.getParameterTypes().length == 0)
.filter(m -> m.getName().equals("getId"))
.collect(Collectors.toList());
assertThat(getIds.size()).isEqualTo(2); // This seems wrong...
UUID someId = UUID.randomUUID();
Record record = Record.builder().id(someId).name("Gunter").build();
for (Method getId : getIds) {
assertThat(getId.invoke(record)).isEqualTo(someId);
}
WithId<UUID> withId = record;
assertThat(withId.getId()).isEqualTo(someId);
assertThat(record.getId()).isEqualTo(someId);
}
}
解决方案
与龙目岛无关。
试试看。写下这段代码:
interface Example<T> {
T get();
}
class Foo implements Example<String> {
public String get() {return null;}
}
然后:
>javac Foo.java
>javap Foo
Compiled from "Foo.java"
class Foo implements Example<java.lang.String> {
Foo();
public java.lang.String get();
public java.lang.Object get();
}
这是在 JLS 中。返回对象的方法称为合成桥接器。它在那里,但对它不是特别可见javac
(javac 知道它,但表现得好像它不存在)。在类文件级别(因此,JVM,在某种程度上,反射),它确实存在。
那么,如何修复呢?
检查合成标志。它将被设置为返回对象:
class Foo implements Example<String> {
public String get() {return null;}
public static void main(String[] args) throws Exception {
for (Method m : Foo.class.getDeclaredMethods()) {
System.out.println(m.getReturnType() + " " + m.getName() + ": " + m.isSynthetic());
}
}
}
然后:
> javac Foo.java; java Foo
void main: false
class java.lang.String get: false
class java.lang.Object get: true
(我 <3 反射)
在你的游行中冒着下雨的风险,这……在我看来,对于一个优秀的 Java 程序员来说,这不是一个好的心态。Java 并没有使反射变得容易,而且这些工具大多假设您也不积极使用它。例如,当您使用反射调用一堆方法而不是实际调用它们时,重构脚本效果不佳。
推荐阅读
- google-cloud-platform - 如何使用 terraform 在项目之间进行交换
- python - 抓取雅虎股票新闻
- javascript - 当单选按钮被选中时,如何使用反应钩子单选更改值?
- flutter - 使用 Future.wait() 等待多个期货崩溃
- postgresql - SELECT 中的子查询 - 来自外部查询的未分组列
- python - 如何在类方法中引用对象而不将其作为参数传递?
- anylogic - 代理在 AnyLogic 中同时接收多条消息
- android - 当应用程序在我的手机(android 10)上运行时,GPUMp4Composer 正在静音我的视频。但它在模拟器(android 9)中运行良好
- android - 如何删除活动堆栈中的第一个活动?
- c++ - 使用 QProcess 执行 CMD 命令并将其保存在 QString 中