Search code examples
javalombokbuilder

Update a different variable in the class with Java Lombok Builder


I have the following class

@Builder
public class User {

    private String userName;
    private String email;
    private String device;
    private String deviceType;
}

I want to set the value deviceType based on the inputs I get for device. Is that possible with Builder? I don't want to set the value of deviceType directly.

Example

if (device == "iPhone") {
    this.deviceType = "mobile"
} else if (device == "Kindle") {
    this.deviceType = "tablet"
} .. and so on

Ideally, I want this to be done in the constructor one time

I am currently building the object like this but I am not sure how to initialize the userEmail field.

User.builder()
.userName("sample-username)
.email("sample-email")
.device("iPhone")
.build();

Solution

  • You could use Lombok's GetterLazy

    From the doc,

    You can let lombok generate a getter which will calculate a value once, the first time this getter is called, and cache it from then on. [...] To use this feature, create a private final variable, initialize it with the expression that's expensive to run, and annotate your field with @Getter(lazy=true). The field will be hidden from the rest of your code, and the expression will be evaluated no more than once, when the getter is first called.

    @Builder
    private static class User {
        private String userName;
        private String email;
        private String device;
        @Getter(lazy=true)
        private final String deviceType = deriveDeviceType();
    
        private String deriveDeviceType() {
            Objects.requireNonNull(device);
            switch (device) {
                case "iPhone": return "mobile";
                case "Kindle": return "tablet";
                // and so on...
            }
            throw new RuntimeException("Invalid value set for device");
        }
    }
    

    With this, the deviceType field won't be available to be set via the builder.

    Note that the field will be initialized only when the getter (getDeviceType()) is called and not when the field is accessed directly.

    User u = User.builder()
                .userName("test-name")
                .email("test-email")
                .device("Kindle")
                .build();
    
    System.out.println(user.getDeviceType()); //tablet 
    

    Since it is possible to pass an invalid value for device, I suggest you to look into using enums to model device and deviceType (if possible).