Set value to one of the property in Java 15 record
Asked Answered
R

3

35

I am using Java 15 preview feature record in my code, and defined the record as follow

public record ProductViewModel
        (
                String id,
                String name,
                String description,
                float price
        ) {
}

In the controller level I have the below code

@Put(uri = "/{id}")
public Maybe<HttpResponse> Update(ProductViewModel model, String id) {
        LOG.info(String.format("Controller --> Updating the specified product"));
        return iProductManager.Update(id, model).flatMap(item -> {
            if(item == null)
                return Maybe.just(HttpResponse.notFound());
            else
                return Maybe.just(HttpResponse.accepted());
        });
    }

From the UI in the model the value of id is not passed, however, it is passed as a route parameter. Now I want to set the value in the controller level, something like

model.setid(id) // Old style

How can I set the value to the record particular property

Roister answered 11/12, 2020 at 15:10 Comment(0)
N
55

You can't. Record properties are immutable. What you can do however is add a wither to create a new record with same properties but a new id:

public record ProductViewModel(String id,
                               String name, 
                               String description,
                               float price) {

    public ProductViewModel withId(String id) {
        return new ProductViewModel(id, name(), description(), price());
    }
} 
Notarize answered 11/12, 2020 at 15:38 Comment(3)
It would be great to have a method like copy in Scala's case class.Alika
Not there yet but... github.com/openjdk/amber-docs/blob/master/eg-drafts/…Notarize
You could also use lombok's @With annotation - baeldung.com/lombok-with-annotationsAideaidedecamp
N
11

If you need to mutate an attribute, then you need to use a class instead of a record.

From the JEP:

Enhance the Java programming language with records, which are classes that act as transparent carriers for immutable data. Records can be thought of as nominal tuples.

So, you'd better use a class if you need that behavior.

Naphtha answered 11/12, 2020 at 15:14 Comment(2)
I'd also add that you explicitly named your class as a 'model' which generally implies it is mutable.Ahders
@Ahders No, it doesn't, not generally. In fact in domain driven design large parts of the domain model will be value objects that by definition do not have a behaviour and thus should be immutable (it is derived from the fact that for values there is no concept of identity other than the value itself).Villainage
C
7

You cannot modify them. From the Oracle page:

A record class is a shallowly immutable, transparent carrier for a fixed set of values, called the record components. The Java language provides concise syntax for declaring record classes, whereby the record components are declared in the record header. The list of record components declared in the record header form the record descriptor.

From the Java Language Specification Section 8.10 one can read the following:

A record declaration is implicitly final. It is permitted for the declaration of a record class to redundantly specify the final

and

8.10.3 Record Members

A record class has for each record component appearing in the record component list an implicitly declared field with the same name as the record component and the same type as the declared type of the record component. This field is declared private and final. The field is annotated with the annotations, if any, that appear on the corresponding record component and whose annotation types are applicable in the field declaration context, or in type contexts, or both.

Calibre answered 11/12, 2020 at 15:14 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.