英文:
Using Lombok @SuperBuilder Using Generic Final Child Class Does Not Compile
问题
I'm currently facing a problem with Lombok's @SuperBuilder
annotation and generics. I have an abstract
parent and a final
child class. When creating the child using the builder, passing values of the correct type leads to compile errors.
The simplified classes and interfaces:
@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> {
}
The test code:
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();
}
}
It works as soon as the child itself no longer has a generic parameter. So having the child like this, everything compiles and works perfectly fine:
@SuperBuilder(toBuilder = true)
final class Child extends Parent<Long> {
}
Am I doing something wrong or is it not possible to have generic final
classes when using the @SuperBuilder
?
英文:
I'm currently facing a problem with Lombok's @SuperBuilder
annotation and generics. I have an abstract
parent and a final
child class. When creating the child using the builder, passing values of the correct type leads to compile errors.
The simplified classes and interfaces
@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> {
}
The test code
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();
}
}
If works, as soon as the child itself no longer has a generic parameter. So having the child like this, everything compiles and works perfectly fine:
@SuperBuilder(toBuilder = true)
final class Child extends Parent<Long> {
}
Am I doing something wrong or is it not possible to have generic final
classes when using the @SuperBuilder
?
答案1
得分: 3
builder()
方法的类型参数(表示您正在创建的 Child
的类型)没有被正确地推断出来。编译器认为它是 Object
。要修复这个错误,只需明确指出您要创建的 Child.Builder
的类型,例如:
Child.<Long>builder()
...
不能正确推断的原因与链式调用 thenComparing
破坏了类型推断的原因类似。
对于简单的构建器也会出现类似的情况:
@Builder
final class Foo<T> {
private T t;
}
// 出错在这里!
Foo<Long> f = Foo.builder().t(1L).build();
尽管在简单情况下,错误消息会更清晰,说明不能将 Foo<Object>
转换为 Foo<Long>
。
您的情况更加复杂 - 您有一个 SomeGenericClass<?, Parent<T>>
字段。这意味着 someGenericClass()
预期一个 SomeGenericClass<?, Parent<Object>>
。一个 SomeGenericClass<String, Parent<Long>>
显然不能传递给它。而且您使用了 SuperBuilder
使事情变得更加复杂。
英文:
The type parameter for builder()
(which represents what kind of Child
you are creating) is not inferred correctly. The compiler thinks it's Object
. To fix the error, just make it very clear what kind of Child.Builder
you are creating, e.g.
Child.<Long>builder()
...
The reason for why this cannot be inferred is similar to why chaining thenComparing
s breaks type inference.
You can see something similar happen with simple builders too:
@Builder
final class Foo<T> {
private T t;
}
// error here!
Foo<Long> f = Foo.builder().t(1L).build();
Though in simple cases like that, the error message is a lot clearer, saying that you cannot convert a Foo<Object>
to Foo<Long>
.
Your case is more complicated - you have a SomeGenericClass<?, Parent<T>>
field. That means someGenericClass()
is expecting a SomeGenericClass<?, Parent<Object>>
. A SomeGenericClass<String, Parent<Long>>
certainly can't be passed to that. And the fact that you're using SuperBuilder
makes things even more complicated.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论