numerobis

maven plugin for the generation of builder classes

This project is maintained by mletkin

Maven Builder Generator Plugin (Version 2.3)

This is a simple maven plugin that generates builder classes for classes that have the appropriate annotation. The builders are generated during the generate-sources phase of the maven build. The current version is restricted to the use of default settings. Customization is currently in a proof of concept state.

The generator creates the builders as a fully functional skeleton. It can be used “as is” without manual changes. On the other hand is it possible to change and extend the generated builder. Methods can be added and implementation can be changed. When the generator runs a second time, missing methods will be created existing methods will not be changeed. When the builder class was deleted or renamed a new one will be created.

The generator can also generate accessor methods for the fields in the class of the objects that are generated by the builder.

Nomenclature

There is no standard for the naming of builder components.
The following terms are used throughout the code and the documentation.

The (generated) class that builds the object instances is the builder. The object it builds is the product. The class which defines the product is the product class. A method of the builder that sets the value of a product field is a mutator. A mutator that adds something (e.g. an Object to a Collection) is an adder. The method in the builder that provides the product is the build method. A method of the product class that returns the content of a field is an accessor.

I avoided the terms getter and setter because of the special meaning they have in the JavaBeans context.

Principles

  1. The generator reads and generates source. The generation of a builder is only possible if the source code for the product class is available. The result is java source, no byte code manipulation is done.
  2. Generated code should always be changable The generator produces methods with default implementations. The implementation may ge changed, the generator should never change the implementation after generation. Deleted methods will be generated again.
  3. The generated code performs no null checks. This is important when dealing with collections. A collection object should never contain a null value.
  4. correct code leads to correct code. If the parsed product class – and optionally the buiöde class – is compiled correctly, the generated or modified code is correct too. The reverse must not be true. If the product or builder class has errors, the generated code might be correct.

Usage

Add the following to the plugin section of your pom.xml

<plugin>
    <groupId>io.github.mletkin</groupId>
    <artifactId>builder-generator-maven-plugin</artifactId>
    <version>1.0.0</version>
    <executions>
        <execution>
            <goals>
                <goal>generate</goal>
            </goals>
        </execution>
    </executions>
</plugin>

Add the annotation @GenerateBuilderto each class for which you want to create a builder. Builder code is generated in the generate-sources phase of the maven build.

Configuration

The following settings may be customized through Maven configuration

builder creation

To use the generated builder it is necessary to create builder instances. The generator provides two alternatives. The builder creates the object of the product class during builder creation. For this reason the builder generator must provide a constructor or factory method for each product constrcutor.

Constructor

For each constructor in the production class a constructor in the builder class is created.

<configuration>
    <builderCreation>CONSTRUCTOR</builderCreation>
<configuration>

Factory

For each constructor in the production class a static factory method the builder class is created. This is the default.

<configuration>
    <builderCreation>FACTORY</builderCreation>
<configuration>

builder location

The builder can be generated as separate class or as member class of the product class.

embedded

The builder class is generated as member class (sometimes called “static inner class”) of the product class. This is the default.

<configuration>
    <builderLocation>EMBEDDED</builderLocation>
<configuration>

separate

The builder class is generated as a separate class. It is located logically in the same package as the product class an physically in the same directory in the file system.

<configuration>
    <builderLocation>SEPARATE</builderLocation>
<configuration>

compileSourceRoots

A list property with the directories that contain the production classes. The directories will be searched recursively. The default is ${project.compileSourceRoots}

targetDirectory

The directory in which the generated builder classes are stored. File paths are created for the packages. The parameter is only relevant if the builders are created as separate classes. The default is the generation in the same directory as the product class.

products are mutable by default

If set to true product classes are considered mutable. For the modification of product class instances a constructor (or factory method) will be created in the builder class. This modificaton method accepts a product class instance as parameter. The default value is false. This means that the product objetcs are considered immutable and no method for modification is generated.

<configuration>
    <productsAreMutable>true</productsAreMutable>
<configuration>

mutator and adder generation for lists and sets

Lists and sets are special. You may want to fill a list with one statement (e.g. from a stream or with a list if values). Or maybe you want to add values without clearinging the list collected to far. The generator generates two sets of methods: Plain mutator methods drop the current list and replace it with another list. Adder methods retain the list content and add values to the list. You my specify a list of mutator/adder vatiants in the plugin configuration. The possible values are collected in the enum GenerateAdder.Variants. The following values are available:

The difference between OBJECT an COLLECTION is that COLLCTION copies the values into the list (or a new list) while OBJECT uses the reference of the List or Set object.

None of the generated methods checks the arguments for null values and none of the adder methods checks that the list or set field contains an object. You should initialize the list in the product class. A list object should never ever contain null.

mutator configuration

Mutator variants are defined like this:

<listMutatorVariants>
    <listMutatorVariant>STREAM</listMutatorVariant>
    <listMutatorVariant>VARARG</listMutatorVariant>
    <listMutatorVariant>COLLECTION</listMutatorVariant>
</listMutatorVariants>

adder configuration

Adder variants are defined like this:

<listAdderVariants>
    <listAdderVariant>STREAM</listAdderVariant>
    <listAdderVariant>VARARG</listAdderVariant>
</listAdderVariants>

naming

There are various names that may be set here. The base idea is to define project wide settings to establish a standard. Annotations may be used to override the default settings but this should be the exception. If a prefix is used, the following letter is cated to upper case. If a prefix is not set the name is used without alteration.

Future versions may have the possibility to define pattern like prefix{0}. This may result in name changes.

Annotations

Most of the behavior of the builder generator is controlled through annotations. The generator will stick to the annotation concept. The names might change and options may be set via annotation parameters. All annotations are located in the package io.github.mletkin.numerobis.annotation

The generator is – currently – unable to evaluate constant expressions. For this reason annotation parameters can only be literals of the expected type. String arguments must be quoted string literals, enum arguments must be enum constants an may be qualified. Later versions may be smarter.

GenerateBuilder

Used on product classes. This is the most important annotation. Only for classes annotated with @GenerateBuilder builder classes will be generated.

GenerateAccessors

Used on product classes. For every field in the product class an accessor will be generated. Accessors have the same name as the field.

GenerateMutator

Mutator generation is the default. This annotation is a means to specify a custom name for the mutator.

GenrateListMutator and GenerateAdder

Used on list fields. Ignored on fields that do not extend List Mutator methods (and adder mutators respectively) are generated for the field. The variants may be configured through annotation parameters.

Ignore

Used on product fields. Fields annotated with @Ignore are ignored by the generator, no mutators and no accessors are generated.

Mutable and Immutable

Used on product classes. Overrides the builder setting for “product classes are immutable/mutable by default” in the pom.