Jukebox

An annotation processor to create builder classes for JEP 359 Records (Preview)

License

License

Categories

Categories

Net
GroupId

GroupId

net.javahippie.jukebox
ArtifactId

ArtifactId

processor
Last Version

Last Version

0.2
Release Date

Release Date

Type

Type

jar
Description

Description

Jukebox
An annotation processor to create builder classes for JEP 359 Records (Preview)
Project URL

Project URL

https://github.com/javahippie/jukebox
Source Code Management

Source Code Management

https://github.com/javahippie/jukebox

Download processor

How to add to project

<!-- https://jarcasting.com/artifacts/net.javahippie.jukebox/processor/ -->
<dependency>
    <groupId>net.javahippie.jukebox</groupId>
    <artifactId>processor</artifactId>
    <version>0.2</version>
</dependency>
// https://jarcasting.com/artifacts/net.javahippie.jukebox/processor/
implementation 'net.javahippie.jukebox:processor:0.2'
// https://jarcasting.com/artifacts/net.javahippie.jukebox/processor/
implementation ("net.javahippie.jukebox:processor:0.2")
'net.javahippie.jukebox:processor:jar:0.2'
<dependency org="net.javahippie.jukebox" name="processor" rev="0.2">
  <artifact name="processor" type="jar" />
</dependency>
@Grapes(
@Grab(group='net.javahippie.jukebox', module='processor', version='0.2')
)
libraryDependencies += "net.javahippie.jukebox" % "processor" % "0.2"
[net.javahippie.jukebox/processor "0.2"]

Dependencies

There are no dependencies for this project. It is a standalone project that does not depend on any other jars.

Project Modules

There are no modules declared in this project.

Java CI Maven Central

Jukebox

"Oh, let that jukebox keep on playin'
Let that record roll around" - Carl Perkins

Usage

This is a annotation processor to generate builder classes for the Java 14 preview feature records (JEP 359). You can get it from Maven Central:

<dependency>
    <groupId>net.javahippie.jukebox</groupId>
    <artifactId>processor</artifactId>
    <version>0.2</version>
</dependency>

Include the dependency and reference the class net.javahippie.jukebox.processor.RecordBuilder in the Maven Compiler Plugin like this:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>3.8.1</version>
    <configuration>
        <compilerArgs>
            <arg>--enable-preview</arg>
        </compilerArgs>
        <source>14</source>
        <target>14</target>
        <encoding>UTF-8</encoding>
        <generatedSourcesDirectory>${project.build.directory}/generated-sources/</generatedSourcesDirectory>
        <annotationProcessors>
            <annotationProcessor>net.javahippie.jukebox.processor.RecordBuilder</annotationProcessor>
        </annotationProcessors>
    </configuration>
</plugin>

After doing this, the library will generate a builder class for any record annotated with the annotation net.javahippie.jukebox.annotation.Builder.

Intention

I had this idea when I compared Java records to Kotlins data classes and realized, that creating Java records with many record components would get confusing to the reader rather soon. If we would like to use records to represent a game between two people, the definitions would look like this:

public record Person(
        String firstName,
        String lastName,
        LocalDate birthDate,
        int heightInCentimeters){}

public record Game(
        Person player1,
        Person player2,
        int pointsPlayer1,
        int pointsPlayer2){}

If we create an instance of a Game with both participants, this would be the only way to do it:

new Game(new Person("Rüdiger", "Behrens", LocalDate.of(1982, 3, 17), 186)),
         new Person("Frank", "Meier", LocalDate.of(1990, 2, 2), 170)),
         10,
         20);

This would be more readable if we used named variables instead of literals, but it is hard to comprehend, what the meaning of each value is. As we do not have named parameters in Java, as we have in Kotlin, the builder pattern might help here:

GameBuilder.builder()
            player1(PersonBuilder.builder()
                    firstName("Rüdiger")
                    lastName("Behrens")
                    birthDate(LocalDate.of(1982, 3, 17))
                    heightInCentimeters(186)
                    .build())
            Player2(PersonBuilder.builder()
                    firstName("Frank")
                    lastName("Meier")
                    birthDate(LocalDate.of(1990, 2, 2))
                    heightInCentimeters(170)
                    .build())
            pointsPlayer1(10)
            pointsPlayer2(20)
            .build();

Luckily, we are able to access the records and its components in a structured way, which enables us to implement an annotation processor, which automatically generates those builders for us. If any record in our project is annotated with @net.javahippie.recordbuilders.annotation.Builder, the annotation processor will pick it up and generate a builder class in the following style:

@Builder
public record Person(
        String firstName,
        String lastName,
        LocalDate birthDate,
        int heightInCentimeters){}

@Builder
public record Game(
        Person player1,
        Person player2,
        int pointsPlayer1,
        int pointsPlayer2){}
package net.javahippie.jukebox.testtool;

public class PersonBuilder {

   private java.lang.String firstName;
   private java.lang.String lastName;
   private java.time.LocalDate birthDate;
   private int heightInCentimeters;

    public static PersonBuilder builder() {
        return new PersonBuilder();
    }

    public Person build() {
        return new Person(firstName, lastName, birthDate, heightInCentimeters);
    }

    public PersonBuilder firstName(java.lang.String firstName) {
        this.firstName = firstName;
        return this;
    }

    public PersonBuilder lastName(java.lang.String lastName) {
        this.lastName = lastName;
        return this;
    }

    public PersonBuilder birthDate(java.time.LocalDate birthDate) {
        this.birthDate = birthDate;
        return this;
    }

    public PersonBuilder heightInCentimeters(int heightInCentimeters) {
        this.heightInCentimeters = heightInCentimeters;
        return this;
    }

}

Versions

Version
0.2
0.1