[JAVA] How to use org.immutables

Organize how to use Java's org.Immutables.

The official website is below. (Basically, the content of this article is based on this) https://immutables.github.io/

Preset

Set dependency in pom.xml of maven.

<dependency>
  <groupId>org.immutables</groupId>
  <artifactId>value</artifactId>
  <version>2.8.2</version>
  <scope>provided</scope>
</dependency>

Basic usage

Create an Immutable object by creating a Value class that stores data and building an automatically generated Immutable class based on it. Used when creating an object that you do not want to change.

Value --Declare with Immutable annotation. --Interface or class is OK. --Immutable class is automatically generated when compiled. --The class name of the Immutable class is ImmutableXxx. (Xxx is the class name of the Value class) --The automatically generated Immutable class should be created in target / generated-sources / annotations by default when compiled with maven compile.

import java.util.List;

import org.immutables.value.Value.Immutable;

@Immutable
public interface User {
    String name();
    String address();
    int age();
    List<String> hobbies();
}

Builder --Use the Immutable class automatically generated from the Value class (User class in the above example). --Call the builder method of the Immutable class, assign the data, and finally call the build method. --This will create an Immutable object. --Data can be obtained by the method of Value class.

        User user = ImmutableUser.builder()
            .name("Tom")
            .age(21)
            .address("Tokyo, Japan")
            .addHobbies("reading", "skiing")
            .build();

        System.out.println(user.toString());
        // User{name=Tom, address=Tokyo, Japan, age=21, hobbies=[reading, skiing]}

        System.out.println(user.name());
        // Tom

        System.out.println(user.age());
        // 21

--You cannot add data to Immutable objects. (UnsupportedOperationException occurs when trying to add data to List class or Map class)

        //listMap is an Immutable object
        listMap.list().add("item"); // java.lang.UnsupportedOperationException
        listMap.map().put("key", "value"); //java.lang.UnsupportedOperationException

from() --Use the from method to create another Immutable object based on one Immutable object.

        User userTemp = ImmutableUser.builder()
            .name("Tom")
            .age(21)
            .address("Tokyo, Japan")
            .addHobbies("reading", "skiing")
            .build();

        User user = ImmutableUser.builder()
            .from(userTemp)
            .address("Osaka, Japan")
            .build();

        System.out.println(user.toString());
        // User{name=Tom, address=Osaka, Japan, age=21, hobbies=[reading, skiing]}

Constructor --When creating an Immutable object with the constructor, add Parameter annotation to the method.

import org.immutables.value.Value.Immutable;
import org.immutables.value.Value.Parameter;

@Immutable
public interface Item {
    @Parameter
    String name();
    @Parameter
    int price();
}

--Create an Immutable object by giving data to the of method of the Immutable class.

        Item item = ImmutableItem.of("apple", 213);

        System.out.println(item);
        // Item{name=apple, price=213}

Optional

--Use Optional when defining an optional item in the Immutable class.

import java.util.Optional;

import org.immutables.value.Value.Immutable;

@Immutable
public interface Address {
    String country();
    String city();
    String blockNmuber();
    Optional<String> apartmentName();
}

--Items defined in Optional do not need to be set with data, but items that are not set with IllegalStateException will occur if data is not set.

        Address address1=ImmutableAddress.builder()
            .country("Japan")
            .city("Yokohama")
            .blockNmuber("1-2-3")
            .build(); // OK

        Address address2=ImmutableAddress.builder()
            .country("Japan")
            .city("Chiba")
            .blockNmuber("1-2-3")
            .apartmentName("YYY Apartment")
            .build(); // OK
        
        Address address3=ImmutableAddress.builder()
            .country("Japan")
            .city("Chiba")
            .build(); // java.lang.IllegalStateException: Cannot build Address, some of required attributes are not set [blockNmuber]

Default

--Add the Default annotation to the item that you want to have the default value, and define the default method.

import org.immutables.value.Value.Default;
import org.immutables.value.Value.Immutable;

@Immutable
public interface AddressWithDefault {
    @Default
    default String country(){
        return "Japan";
    }
    String city();
    String blockNmuber();
}

--If you do not set data when creating an Immutable object, the default value will be set.

        AddressWithDefault address = ImmutableAddressWithDefault.builder()
            .city("Saitama")
            .blockNmuber("4-5-6")
            .build();

        System.out.println(address.toString());
        // AddressWithDefault{country=Japan, city=Saitama, blockNmuber=4-5-6}

Derived

--Add Derived annotation and define the item to be processed based on the data set in Immutable object.

import java.util.Map;

import org.immutables.value.Value.Derived;
import org.immutables.value.Value.Immutable;

@Immutable
public abstract class Receipt {
    abstract Map<String, Integer> items();

    @Derived
    public int total() {
        //Sum the values of items
        return items().values().stream().reduce(0, Integer::sum);
    }
}
       Receipt receipt = ImmutableReceipt.builder()
            .putItems("bread", 210)
            .putItems("milk", 100)
            .build();

        System.out.println(receipt.total());
        // 310

Precondition check

--Define the check process when the Immutable object is created with the Check annotation.

import java.util.List;

import org.immutables.value.Value.Check;
import org.immutables.value.Value.Immutable;

@Immutable
public abstract class Cart {
    abstract List<String> items();

    @Check
    protected void check() {
        if (items() == null || items().isEmpty()) {
            throw new IllegalStateException();
        }
    }
}

--If the check conditions are not met, an error can be generated when creating an Immutable object.

        ImmutableCart.builder().build(); // java.lang.IllegalStateException

Advanced version

Wrapper Types

--If you have a Wrapped interface and a Wrapper class, the definition of the Value class will be simple and you will not have to write similar code many times.

--Wrapped interface

    @Value.Style(
            typeAbstract = "_*",
            typeImmutable = "*",
            visibility = ImplementationVisibility.PUBLIC,
            defaults = @Value.Immutable(builder = false, copy = false))
    public @interface Wrapped {
    }

--Wrapper class

    public static abstract class Wrapper<T> {
        @Value.Parameter
        public abstract T value();

        @Override
        public String toString() {
            return getClass().getSimpleName() + "(" + value() + ")";
        }
    }

--The Value class and how to call it are as follows.

    @Value.Immutable
    @Wrapped
    public static abstract class _FirstName extends Wrapper<String> {
    }

    @Value.Immutable
    @Wrapped
    public static abstract class _LastName extends Wrapper<String> {
    }

    @Value.Immutable
    @Wrapped
    public static abstract class _Age extends Wrapper<Integer> {
    }

    FirstName firstName = FirstName.of("Taro");

    LastName lastName = LastName.of("Yamada");

    Age age = Age.of(45);

If compilation fails

--Clean and compile like mvn clean compile. --Set false in the useIncrementalCompilation option. - https://immutables.github.io/getstarted.html#troubleshooting

Recommended Posts

How to use org.immutables
How to use Map
How to use rbenv
How to use letter_opener_web
How to use with_option
How to use fields_for
How to use java.util.logging
How to use map
How to use collection_select
How to use Twitter4J
How to use active_hash! !!
How to use MapStruct
How to use hidden_field_tag
How to use TreeSet
[How to use label]
How to use identity
How to use hashes
How to use JUnit 5
How to use Dozer.mapper
How to use Gradle
How to use java.util.stream.Collector
How to use VisualVM
How to use Map
[Java] How to use Map
How to use Chain API
How to use java Optional
How to use JUnit (beginner)
How to use Ruby return
[Rails] How to use enum
How to use @Builder (Lombok)
[Swift] How to use UserDefaults
How to use java class
How to use Swift UIScrollView
How to use Big Decimal
[Java] How to use Optional ②
[Java] How to use removeAll ()
How to use String [] args
[Java] How to use string.format
How to use rails join
How to use Java Map
How to use dependent :: destroy
How to use Eclipse Debug_Shell
How to use Apache POI
How to use Java variables
[Rails] How to use authenticate_user!
How to use GC Viewer
[Java] How to use Optional ①
How to use Lombok now
[Creating] How to use JUnit
[Rails] How to use Scope
How to use the link_to method
[Rails] How to use gem "devise"
How to use Lombok in Spring
How to use StringBurrer and Arrays.toString.
How to use Java HttpClient (Get)
How to use scope (JSP & Servlet)
How to use the include? method
[Rails] How to use devise (Note)
How to use the form_with method
[Rails] How to use flash messages
How to use EventBus3 and ThreadMode