Update an immutable object with Lombok in Java?
Asked Answered
W

3

5

I have a domain class Person annotated with Lombok @Value thus marking it as immutable, having has 3 fields.

In my service layer, I am making a call to the repository to check if the the person exists or not.

If it does exist, I need to take the Person object from the database and update the money field.

Since it is immutable, this cannot be done. I was reading some articles and came across that this can be done using builder pattern.

I will probably need to create a updatePerson() in my Person class but not sure how to do it. Or do I need to do something else ?

Person.java:

@Value
@Builder
public class Person {

    private final UUID id;
    private final String job;
    private final BigDecimal money;
    
}

I am using Java 15.

Wording answered 9/12, 2021 at 20:32 Comment(2)
Sounds like money should not be final (so it can be updated). Changing @Value to @Data should create the setter and getter for money, and only a getter for the other attributes that are still final.Crosspiece
I can't use Data. This needs to be immutable only.Wording
A
8

You can also use another feature of lombok, which doesn't require you to use a builder. It's called @With and using this annotation will create immutable setters, meaning that the setter returns a new object with the attributes of the old one except for the attribute that you wanted to change.

@Value
public class Person {
    /* You don't need to write final if you are using @Value. Lombok will make the variables final for you. 
    In theory you do not even need to write private, 
    because Lombok makes variables private by default instead of package private.*/
    private UUID id;
    private String job;
    @With 
    private BigDecimal money;
}

Person newPerson = person.withMoney(new Big decimal("10"));

In general I'm not sure if making the object immutable is really a good idea. Every variable except UUID seems like it could change in the future.

Agglutinin answered 9/12, 2021 at 22:51 Comment(3)
But how will I use this ? Can you please share the usage ? Like code snippet that fits my case here ?Wording
Sorry just realized I'm missing that part and added it below.Agglutinin
This is what I needed. Thanks a ton !Wording
S
3

Using Lombok:

@Value
@Builder(toBuilder = true)
public class Person {

    private final UUID id;
    private final String job;
    private final BigDecimal money;
}

personObjectFromDatabase.toBuilder().setMoney(...).build()

OR

You can use the Builder pattern in that case:

public class Person {

    private final UUID id;
    private final String job;
    private final BigDecimal money;
    
    public static class PersonBuilder { 
            private UUID id;
            private String job;
            private BigDecimal money;

            public PersonBuilder(Person defaultPerson){ 
                this.id = defaultPerson.getId();
                this.job = defaultPerson.getJob();
                this.money = defaultPerson.getMoney();
            }
            public PersonBuilder withId(UUID id) {
                this.id = UUID;
                return this;
            }
            public PersonBuilder withJob(String job) {
                this.job = job;
                return this;
            }
            public PersonBuilder withMoney(BigDecimal money) {
                this.money = money;
                return this;
            }
            public Person build() {
                return new Person(id, job, money);
            }
     }
}

Use this builder like the following:

Person person = new Person.PersonBuilder(personObjectFromDatabase)
    .withMoney(...)
    .build();

OR

You can just create a copyWith() method:

public class Person {
    ...
    public Person copyWith(BigDecimal money) {
        return new Person(this.id, this.job, money);
    }
}
Shuttle answered 9/12, 2021 at 20:50 Comment(1)
You can still use Lombok with toBuilder - projectlombok.org/features/BuilderShaver
B
0

The class is immutable; you can never change the values of an instance of that class.

Instead, you must create a new instance of the class.

Do not write a builder; you are already using Lombok, just use the @Builder annotation and Lombok will create a builder for you.

Edit: You are using the builder annotation. The soltion you are looking for appears to be this:

you must create a new instance of the class.

Borscht answered 9/12, 2021 at 21:6 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.