【问题标题】:Why is Lombok generating an extra Getter when overriding a generic getter?为什么 Lombok 在覆盖通用 getter 时会生成额外的 Getter?
【发布时间】:2021-04-04 21:10:59
【问题描述】:

我有一个接口,它定义了一个 id 字段(和其他字段,但很简单),它使用 Java 的泛型。

我正在使用 Lombok 为实现此功能的类生成 Getter 和 Builder。

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

(我

这是一个显示此行为的单元测试。我的龙目岛错了吗?我需要申请其他注释吗?我是否只是耸耸肩并编写代码让所有吸气剂检查并避免它?

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);
    }
}

【问题讨论】:

标签: java generics lombok


【解决方案1】:

与龙目岛无关。

试试看。写下这段代码:

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

(我

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-11-23
    • 2012-08-01
    • 2020-05-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-28
    • 1970-01-01
    相关资源
    最近更新 更多