diego
diego

Reputation: 150

@Builder Lombok - Inheritance

I try to use inheritance for my class that has annotation @SuperBuilder. I have one superclass:

@SuperBuilder
@Data
public class BaseClass {
    private String userID;
    private String clientID;
}

And two classes that extend BaseClass:

@SuperBuilder
@Data
public class UserWithName extends BaseClass {
    private String name;
}

And:

@SuperBuilder
@Data
public class UserWithNumber extends BaseClass {
    private int number;
}

After that, I try to create some BaseBuilder:

public BaseClass.BaseClassBuilder generateBaseBuilder() {
    return BaseClass.builder()
            .userID("1")
            .clientID("1");
}

And I want to use the base builder when I try to create my objects for classes UserWithName and UserWithNumber. I tried to do that something like that:

public UserWithName generateUserWithName(String name) {
    UserWithName.UserWithNameBuilder builder = (UserWithName.UserWithNameBuilder) generateBaseBuilder();
    return builder
            .name(name)
            .build();
}

But it doesn't work (ClassCastException). Here is the full code:

public class Main {
    @SuperBuilder
    @Data
    public static class BaseClass {
        private String userID;
        private String clientID;
    }

    @SuperBuilder
    @Data
    public static class UserWithName extends BaseClass {
        private String name;
    }

    @SuperBuilder
    @Data
    public static class UserWithNumber extends BaseClass {
        private int number;
    }

    public BaseClass.BaseClassBuilder generateBaseBuilder() {
        return BaseClass.builder()
                .userID("1")
                .clientID("1");
    }

    public UserWithName generateUserWithName(String name) {
        UserWithName.UserWithNameBuilder builder = (UserWithName.UserWithNameBuilder) generateBaseBuilder();
        return builder
                .name(name)
                .build();
    }
}

Is there some way how I can use my method generateBaseBuilder() for creating my objects?

Upvotes: 0

Views: 592

Answers (1)

Jan Rieke
Jan Rieke

Reputation: 8042

You cannot cast an instance of BaseClassBuilder to UserWithNameBuilder, because the inheritance relation is in the opposite direction, as it reflects the relation between the annotated classes: UserWithNameBuilder extends BaseClassBuilder, like UserWithName extends BaseClass.

Thus, there is no way around calling the builder() method of the very class you want to build.

That being said, I guess that the primary purpose of your generateBaseBuilder() method is not to create the builder, but to set some default values for the new instances. There are two ways to achieve this:

  1. Add default values (as field initializers) to your fields and put a @Builder.Default on them.

  2. Rewrite your generateBaseBuilder method to become setDefaultValues that takes a builder instance as parameter and only sets those values:

public static <T extends BaseClass.BaseClassBuilder<?, ?>> T setDefaultValues(T builder) {
    builder
        .userID("1")
        .clientID("1");
    return builder;
}

public static UserWithName generateUserWithName(String name) {
    UserWithNameBuilder<?,?> builder = setDefaultValues(UserWithName.builder());
    return builder            
        .name(name)
        .build();
}

I'd prefer the first option because it is more concise. However, the second option is more flexible, as you can have multiple of those setValues methods, each of which could set different values.

Note that you could also include this/these method(s) directly into the BaseClassBuilder. There are a few questions and answers here at StackOverflow that discuss customizing @SuperBuilder.

Upvotes: 2

Related Questions