使用 Lombok @SuperBuilder 使用通用最终子类无法编译

Mel*_*chs 5 java generics builder lombok

我目前面临 Lombok 注释和泛型的问题@SuperBuilder。我有一个abstract家长班和一个final孩子班。使用构建器创建子级时,传递正确类型的值会导致编译错误。

简化的类和接口

@SuperBuilder(toBuilder = true)
public abstract class Parent<T> {

    private SomeGenericClass<?, Parent<T>> someGenericClass;
    private T value;
}

interface SomeInterface<D> {

}

class SomeGenericClass<D, S> implements SomeInterface<D> {

}

@SuperBuilder(toBuilder = true)
final class Child<T> extends Parent<T> {

}
Run Code Online (Sandbox Code Playgroud)

测试代码

public class SuperBuilderTest {

    public static void main(String[] args) {
        SomeGenericClass<String, Parent<Long>> someGenericClass = new SomeGenericClass<>();

        Child<Long> child = Child.builder() 
                .someGenericClass(someGenericClass) // error: The method someGenericClass(SomeGenericClass<?,Parent<Object>>) in
                // the type Parent.ParentBuilder<Object,capture#1-of ?,capture#2-of ?> is
                // not applicable for the arguments (SomeGenericClass<String,Parent<Long>>)
                .value(10L) // error: Type mismatch: cannot convert from capture#1-of ? to Child<Long>
                .build();
    }
}
Run Code Online (Sandbox Code Playgroud)

如果可行,只要子级本身不再具有通用参数。因此,有了这样的孩子,一切都会编译并运行得很好:

@SuperBuilder(toBuilder = true)
final class Child extends Parent<Long> {

}
Run Code Online (Sandbox Code Playgroud)

final我做错了什么或者在使用时不可能有通用类吗@SuperBuilder

Swe*_*per 3

类型参数builder()(代表您正在创建的类型Child)未正确推断。编译器认为它是Object. 要修复错误,只需明确Child.Builder您正在创建的类型,例如

Child.<Long>builder()
    ...
Run Code Online (Sandbox Code Playgroud)

无法推断的原因与链接thenComparings 破坏类型推断的原因类似。

您也可以在简单的构建器中看到类似的情况发生:

@Builder
final class Foo<T> {
    private T t;
}

// error here!
Foo<Long> f = Foo.builder().t(1L).build();
Run Code Online (Sandbox Code Playgroud)

尽管在这样的简单情况下,错误消息更加清晰,指出您无法将 a 转换Foo<Object>Foo<Long>

你的情况更复杂——你有一个SomeGenericClass<?, Parent<T>>领域。这意味着someGenericClass()正在期待一个SomeGenericClass<?, Parent<Object>>. ASomeGenericClass<String, Parent<Long>>当然不能传递给它。您正在使用的事实SuperBuilder使事情变得更加复杂。