1

With Java record being immutable, I don't know how to use them properly in the context of something like a CRUD application.

If we take a very simple example of a "Organization" record:

public record Organization(String id, String name){}

This looks good, its immutable and has all the good stuff built into it.

Now, let's say I want to update the name value, I have been doing the following:

public record Organization(@Id String id, String name){
    public static Organization withNewName(
            final String name, 
            Organization organization
    ) {
        return new Organization(organization.id, name);
    }
}

This is okay, I create a new record with the updated name that I want. I can use this elsewhere in my code:

Organization renamedOrganization = Organization.withNewName("Fancy company", organization);

But this gets out of hand as soon as we have a real world example where the record might have 10, or even 100 different properties. Things get even more crazy as records don't have default values, so when dealing with Lists which are null at initialization.

I've used MapStruct for handling the basic remapping but even this seems like an overkill.

What is the proper design pattern here for working with immutable objects, when they need to be updated so they can be pushed into a databases should I have just stuck with classes and Lombok for database entities?

1 Answer 1

6

Immutable is nice when you're avoiding sharing mutable state across threads. It avoids nasty race conditions. It can also make reasoning about what code will do easier because the state is predictable.

Mutable is nice when you're on one thread and don't care about any of that. It can help you keep your memory footprint from growing by letting you reuse old memory. Mattered much more back in the day when memory was expensive.

It's important to know why things exist so you use them when they're useful and not just because they're there.

That said, using the right style for the job can make your life easier. I don't think static is the way to go here, unless you have some fanatic need to separate the withFoo() methods from the record object. In any case, if you're going to do the .withFoo() thing then do it fluently:

ProductViewModel updatedPVM = oldPVM
    .withId("1")
    .withName("Dohicky")
    .withDescription("A thingamabob")
;

That updates multiple fields with a reasonable expression. But this is still Java so you still need the boiler plate code.

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

    public ProductViewModel withId(String id) {
        return new ProductViewModel(id, name(), description(), price());
    }

    public ProductViewModel withName(String name) {
        return new ProductViewModel(id(), name, description(), price());
    }

    public ProductViewModel withDescription(String description) {
        return new ProductViewModel(id(), name(), description, price());
    }

    public ProductViewModel withPrice(int price) {
        return new ProductViewModel(id(), name(), description(), price);
    }
} 

See: Set value to one of the property in Java 15 record

Is this the fastest way to build a new immutable record from an old one? No. Does it avoid creating a mutable class that is a duplicate of the record? Yes.

So yeah, Lomboks @builder on a class can save you some keyboard typing here. Boiler plate code is not fun. But I see no reason that someday you wouldn't be able to throw @builder on a record as well.

I know price was originally a float in the linked code but I just can't perpetuate that in a world of base 10 money.

That's just one way to skin this cat. You can find a decent round up of other ways here, each with it's own benefits and costs. Use the one that supports the things you care about.

Scrap all this if Java ever breaks down and finally gives us named parameters so we can stop simulating them.

As for 100 properties, be sure you really need static knowledge of every property in your app before you spread knowledge of them. You can spare yourself a lot of pain by sticking to your immediate needs. Blindly duping the DB can eat up precious time and lock down things you didn’t even care about.

1
  • I would add that we are most likely going to get "Withers" in the alternatives section of this answer. Feb 4 at 4:59

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.