Search code examples
javajava-17builder-patternjava-annotationsjava-record

Annotation-processor based builder pattern with Java 14 records


At my org we extensively use @Value.Immutable annotation with interfaces or abstract classes to generate Immutable classes with builders for our internal data transfer objects (DTOs) [ref].

We are writing a new service in Java 17 and want to leverage records for DTOs, but we don't want to give up on builder-pattern for construction. We do understand that immutability provided by records and builder-pattern are two unrelated concepts, but for our DTOs use-case builder-pattern is absolutely essential

A quick literature survey reveals that as of Sep 2023, the available options for getting builder-pattern out of Java records are

  1. Hand-written Builder class nested within Java record file
    • manual effort, no annotation-magic
  2. Lombok's @Builder annotation
    • Lombok is evil (no offense) and our entire org is moving away from it
  3. RecordBuilder library
    • I'm sceptical as to how long would it be supported by community
    • plus it also offers several customizations around pure / simple builders that i'm not too keen to adopt & don't want those unnecessary loopholes in my project

Are there any other workarounds of getting builder-pattern with Java records? We are even okay to start-off with hand-written nested builder-classes within records (since both options 2 & 3 make us uneasy), provided our beloved Immutables library starts supporting them in future so that we could seamlessly migrate to them.


Solution

  • We had created an issue [#1484] against Immutables library for this query and as per their response

    • They are planning to add full support for records. Most probably it will be Immutables 3
    • Till then Immutables library does in fact offer a workaround by means of @Builder.Constructor annotation
    record Uio(
      int x,
      String b,
      boolean z) {
    
      @Builder.Constructor
      Uio {
        // ...
      }
    }
    
    var b = new UioBuilder()
      .x(4)
      .b("xx")
      .z(true)
      .build();