Skip to content

Extensions

pawel_labaj edited this page Aug 3, 2023 · 6 revisions

AutoRecord Extensions provide a way to customize the record generation process in AutoRecord. They allow you to extend and modify the behavior of AutoRecord to better suit your specific use cases and requirements. Extensions can be used to add additional features, customize code generation, and provide extra functionality beyond what is available with the default AutoRecord behavior.

Creating a Custom Extension

To create a custom extension, you need to implement at least one of the following interfaces that extends the AutoRecordExtension interface:

These interfaces provide a set of methods that you can override to customize various aspects of the record generation process.

Please see Javadoc comments of specific interfaces to see what methods needs to be implemented while developing an extension

Known available extensions

extension description docummnetation
ARICE Auto Record Immutable Collections Etension. Extension for customizing a record generation process with support for immutable collections. WIKI

How to use extensions

To add an extension to the record generation process, @AutoRecord.Extension annotation needs to be used. The annotation allows to specify the class of the extension and parameters that will be passed to it.

Here is an example of what it might look like:

@AutoRecord.Extension(extensionClass = LoggingExtension.class, parameters = "info")
📝 Note
Class specified in `extensionClass1 method must be already present on classpath during the annotation processing.

For single record generation

To add extensions to the generation of a single record, you have to use the @AutoRecord.Extension annotations next to @AutoRecod. You can add many extensions.

Here is an example of what it might look like:

@AutoRecord
@AutoRecord.Extension(extensionClass = IsPersonAdultVerifierExtension.class, parameters = "java.lang.IllegalStateException")
@AutoRecord.Extension(extensionClass = LoggingExtension.class)

In custom annotation

To add extensions to the records generation with custom annotation, you have to specify the @AutoRecord.Extension annotations in @AutoRecord.Template#extensions() method.

Here is an example of what such custom annotation might look like:

package pl.com.labaj.autorecord;

import (...)

@Retention(SOURCE)
@Target(TYPE)
@AutoRecord.Template(
        recordOptions = @AutoRecord.Options(withBuilder = true),
        builderOptions = @RecordBuilder.Options(useUnmodifiableCollections = true),
        extensions = {
                @AutoRecord.Extension(extensionClass = LoggingExtension.class, parameters = "info"),
                @AutoRecord.Extension(extensionClass = IsPersonAdultVerifierExtension.class)
        }
)
public @interface AutoRecordWithExtensions {}

Example extension, interface and generated record

Here's example extension:

public class LoggingExtension implements CompactConstructorExtension {

    private Level level;

    @Override
    public void setParameters(String[] parameters) {
        if (parameters.length < 1) {
            level = FINE;
        } else {
            level = Level.parse(parameters[0].toUpperCase());
        }
    }

    @Override
    public boolean shouldGenerate(boolean isGeneratedByProcessor, Context context) {
        return true;
    }

    @Override
    public CodeBlock prefixCompactConstructorContent(Context context, StaticImports staticImports) {
        var codeBuilder = CodeBlock.builder();

        codeBuilder.addStatement("var map = new $T<$T, $T>()", HashMap.class, String.class, Object.class);

        context.components().stream()
                .map(RecordComponent::name)
                .forEach(name -> codeBuilder.addStatement("map.put($S, $L)", name, name));

        codeBuilder.addStatement("var logger = getLogger($L.class.getName())", context.recordName())
                .addStatement("logger.log($L, $S, $L)", level, "Parameters passed to record: {0}", "map");

        staticImports.add(Logger.class, "getLogger")
                .add(Level.class, level.getName());

        return codeBuilder.build();
    }
}

Here's an example interface:

@AutoRecord
@AutoRecord.Extension(extensionClass = LoggingExtension.class, parameters = "info")
interface Person {
    String name();

    @Nullable
    String surname();

    int age();
}

Here's the corresponding generated record that demonstrates builder generation:

@Generated("pl.com.labaj.autorecord.AutoRecord")
@GeneratedWithAutoRecord
record PersonRecord(String name, @Nullable String surname, int age) implements Person {
    PersonRecord {
        // pl.com.labaj.autorecord.extension.compact.LoggingExtension
        var map = new HashMap<String, Object>();
        map.put("name", name);
        map.put("surname", surname);
        map.put("age", age);
        var logger = getLogger(PersonRecord.class.getName());
        logger.log(INFO, "Parameters passed to record: {0}", map);

        // pl.com.labaj.autorecord.processor.AutoRecordProcessor
        requireNonNull(name, "name must not be null");
    }
}