projectlombok / lombok

Very spicy additions to the Java programming language.
https://projectlombok.org/
Other
12.83k stars 2.37k forks source link

[BUG] SuperBuilder with generics #3510

Open hamidsultanzadeh opened 12 months ago

hamidsultanzadeh commented 12 months ago

I have been trying to make an architecture for my database models. and I'm using BaseEntity and IsDeletedEntity for storing common fields. and BaseEntity accepts a generic but IsDeletedEntity doesn't. So let me give you an example from my models:

It is my child model which extends BaseEntity model with generic Long type

@Data
@SuperBuilder
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(callSuper = true)
@FieldDefaults(level = AccessLevel.PRIVATE)
public class Employee extends BaseEntity<Long> {

    Long userId;

}

The BaseEntity

@Data
@SuperBuilder
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(callSuper = true)
@FieldDefaults(level = AccessLevel.PRIVATE)
public class BaseEntity<ID> extends IsDeletedEntity {

    ID id;

}

IsDeletedEntity

@Data
@SuperBuilder
@NoArgsConstructor
@AllArgsConstructor
@FieldDefaults(level = AccessLevel.PRIVATE)
public class IsDeletedEntity {

    boolean isDeleted;

}

And finally, the error is

java: name clash: <ID>builder() in com.webperside.courseerpbackend.models.mybatis.base.BaseEntity and builder() in com.webperside.courseerpbackend.models.mybatis.base.IsDeletedEntity have the same erasure, yet neither hides the other

Actually, there is a solution to fix it. If you just add a generic to IsDeletedEntity, and pass it from BaseEntity, it will work. But I want to follow that way, otherwise, I have to create a dummy generic for IsDeletedEntity. which I don't need it in this model.

Version info (please complete the following information):

gadirovakhadija commented 12 months ago

The error is occurring because both BaseEntity and IsDeletedEntity have a method named builder() that causes a name clash due to erasure when you use a generic type for BaseEntity. Create a separate builder for BaseEntity and specify the type parameter there: @Data @SuperBuilder(builderMethodName = "baseEntityBuilder") Use baseEntityBuilder() instead of builder() when constructing instances of BaseEntity: BaseEntity entity = BaseEntity.baseEntityBuilder().id(1L).isDeleted(false).build();

hamidsultanzadeh commented 12 months ago

It works!

Thank you

janrieke commented 12 months ago

That's a limitation due to static method "overriding" in Java (which is not a real overriding). If feasable, you could make IsDeletedEntity abstract. That would suppress the generation of the builder method.

hamidsultanzadeh commented 12 months ago

thanks @janrieke I appreciate your help Yeah, it is about static methods. but I am not sure why I getting clash after putting generic type on BaseEntity.