简体   繁体   中英

Update an immutable object with Lombok in Java?

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.

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.

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);
    }
}

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM