为什么Lombok在重写泛型Getter时会生成一个额外的Getter



我有一个接口,它定义了一个id字段(以及其他字段,但正在简化(,它使用Java的泛型。

我正在使用Lombok为实现这个功能的类生成Getters和Builder。

使用接口中的IdType getId(),Lombok同时生成Object getId()UUID getId()。当通过反射调用这两个方法时,这两种方法都可以工作,但这非常奇怪,并且混淆了一些假设一个类不会有多个具有相同名称和不同返回类型的方法的代码。

(I<3反射(

下面是一个显示这种行为的单元测试。我的lombokking错了吗?我需要申请其他注释吗?我只是耸耸肩写代码,让所有的getter检查并避免它吗?

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中。Object返回方法称为合成桥接器。它在那里,但对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

(I<3反射(

在我看来,这不是一个好的java程序员的好心态。Java并不能使反射变得容易,而且工具大多假设您也没有积极使用它。例如,当您使用反射而不是实际调用一堆方法时,重构脚本就不能很好地执行。

相关内容

最新更新