Skip to content
pawel_labaj edited this page Aug 5, 2023 · 4 revisions

Auto Record Immutable Collections

An implementations of the link AutoRecord extension for customizing a record generation process with support for immutable collections.

Guava library is used to provide immutable copies of collections used in the record.

📝 Note
It is recommended to disable useImmutableCollections and useUnmodifiableCollections features for generated builders.

How to enable ARICE

If you want the ARICE wis used during the record generation, you need to use @AutoRecord.Extension annotation and set "pl.com.labaj.autorecord.extension.arice.ImmutableCollectionsExtension" as its extensionClass property value.

@AutoRecord.Extension(extensionClass = "pl.com.labaj.autorecord.extension.arice.ImmutableCollectionsExtension")
📝 Note
For details how to use extensions in single record generation or in custom template, see How to use extensions

Example interface and generated record

Here's an example interface:

@AutoRecord
@AutoRecord.Extension(extensionClass = "pl.com.labaj.autorecord.extension.arice.ImmutableCollectionsExtension")
interface Person {
    String name();

    @Nullable
    String surname();

    Set<String> strongFeatures();

    @Nullable
    List<String> hobbies();

    @Mutable
    Map<String, Integer> experience();
}

Please note, the experience map has been annotated with @Mutable annotation to state that ARICE should leave this component intact.

Here's the corresponding generated record that demonstrates ARICE generated statements:

@Generated(
        value = "pl.com.labaj.autorecord.AutoRecord",
        comments = "pl.com.labaj.autorecord.extension.arice.ImmutableCollectionsExtension"
)
@GeneratedWithAutoRecord
@ARICEUtilities(className = "pl.com.labaj.autorecord.extension.arice.ARICE")
record PersonRecord(String name,
                    @Nullable String surname,
                    Set<String> strongFeatures,
                    @Nullable List<String> hobbies,
                    @Mutable Map<String, Integer> experience) implements Person {
    PersonRecord {
        // pl.com.labaj.autorecord.processor.AutoRecordProcessor
        requireNonNull(name, "name must not be null");
        requireNonNull(strongFeatures, "strongFeatures must not be null");
        requireNonNull(experience, "experience must not be null");

        // pl.com.labaj.autorecord.extension.arice.ImmutableCollectionsExtension
        strongFeatures = ARICE.immutable(strongFeatures);
        hobbies = isNull(hobbies) ? null : ARICE.immutable(hobbies);
    }
}

Additional utility class ARICE is generated with immutable methods for collections. Here's the excerpt presenting methods for Sets and Lists:

public static<E> Set<E> immutable(Set<E> set){
        if(set instanceof ImmutableSet<E>){
        return set;
        }
        if(set instanceof SortedSet<E> sortedSet){
        return immutable(sortedSet);
        }
        return ImmutableSet.copyOf(set);
        }

public static<E> List<E> immutable(List<E> list){
        if(list instanceof ImmutableList<E>){
        return list;
        }
        return ImmutableList.copyOf(list);
        }

Custom immutable types

You can specify types that are immutable and ARICE should handle properly. To do that you need to set their names as AutoRecord.Extension annotation parameters property value.

@AutoRecord.Extension(
        extensionClass = "pl.com.labaj.autorecord.extension.arice.ImmutableCollectionsExtension",
        parameters = "wiki.extension.arice.UserImmutableList"
)

Example interface and generated record

Here's an example interface:

@AutoRecord
@AutoRecord.Extension(
        extensionClass = "pl.com.labaj.autorecord.extension.arice.ImmutableCollectionsExtension",
        parameters = "wiki.extension.arice.UserImmutableList"
)
interface Item {
    String name();

    Set<String> properties();

    UserImmutableList<Double> rates();
}

Here's the corresponding generated record that demonstrates ARICE generated statements:

@Generated(
        value = "pl.com.labaj,.autorecord.AutoRecord"
        comments= "pl.com.labaj.autorecord.extension.arice.ImmutableCollectionsExtension"
)
@GeneratedWithAutoRecord
@ARICEUtilities(
        className = "pl.com.labaj.autorecord.extension.arice.ARICE_GIMSDUD",
        immutableTypes = "wiki.extension.arice.UserImmutableList"
)
record ItemRecord(String name, Set<String> properties, UserImmutableList<Double> rates) implements Item {
    ItemRecord {
        // pl.com.labaj.autorecord.processor.AutoRecordProcessor
        requireNonNull(name, "name must not be null");
        requireNonNull(properties, "properties must not be null");
        requireNonNull(rates, "rates must not be null");

        // pl.com.labaj.autorecord.extension.arice.ImmutableCollectionsExtension
        properties = ARICE_GIMSDUD.immutable(properties);
    }
}

Additional utility class ARICE_GIMSDUD is generated with immutable methods for collections. Here's the excerpt presenting methods for Lists:

public static<E> List<E> immutable(List<E> list){
        if(list instanceof ImmutableList<E>
            ||list instanceof UserImmutableList<E>){
        return list;
        }
        return ImmutableList.copyOf(list);
        }

Adding dependency to your project

Maven

Add the following dependency to your pom.xml file:

<dependency>
    <groupId>pl.com.labaj.autorecord</groupId>
    <artifactId>auto-record</artifactId>
    <version>${auto-record.version}</version>
    <scope>provided</scope>
</dependency>
<dependency>
    <groupId>pl.com.labaj.autorecord</groupId>
    <artifactId>arice</artifactId>
    <version>${arice.version}</version>
    <scope>provided</scope>
</dependency>

Gradle

Declare the following dependency in your build.gradle script:

dependencies {
    annotationProcessor 'pl.com.labaj.autorecord:auto-record:${autoRecordVersion}',
    implementation 'pl.com.labaj.autorecord:arice:${ariceVersion}'
}

IDE

Depending on your IDE you are likely to need to enable Annotation Processing in your IDE settings.