Automatic generation of immutable class and matching builder class of a Java interface
Asked Answered
M

6

5

What tools or libraries exists for Java that will take an interface only with accessor method definitions and automatically generate an immutable object class and also a "builder" class for incrementally building new instances or changing existing instances by creating new ones?

Example input:

public interface Car {
    String getModelName();
    int getWheelCount();
}

Example output:

import javax.annotation.concurrent.Immutable;
import javax.annotation.concurrent.NotThreadSafe;

@Immutable
public final class ImmutableCar implements Car {

    @NotThreadSafe
    public static final class Builder implements Car {

        private String modelName;
        private int wheelCount;

        public Builder() {
        }

        public Builder(final Car car) {
            modelName = car.getModelName();
            wheelCount = car.getWheelCount();
        }

        public ImmutableCar build() {
            return new ImmutableCar(wheelCount, modelName);
        }

        @Override
        public String getModelName() {
            return modelName;
        }

        @Override
        public int getWheelCount() {
            return wheelCount;
        }

        public void setModelName(final String modelName) {
            this.modelName = modelName;
        }

        public void setWheelCount(final int wheelCount) {
            this.wheelCount = wheelCount;
        }
    }

    private final String modelName;
    private final int wheelCount;

    public ImmutableCar(final int wheelCount, final String modelName) {
        this.wheelCount = wheelCount;
        this.modelName = modelName;
    }

    @Override
    public String getModelName() {
        return modelName;
    }

    @Override
    public int getWheelCount() {
        return wheelCount;
    }

}
Monitory answered 6/2, 2013 at 9:43 Comment(1)
first tell why you need this..Sharonsharona
E
3

Immutables (http://immutables.github.io) annotation processor is the exact match for your needs. It is full-featured and very customizable (you know all those set vs with vs no-prefix wars, - use whatever you prefer). It can generate immutable implementation with builders for interfaces, abstract classes, annotations. In addition, it can generate builders to invoke static factory methods or POJO constructors and many other things.

@Value.Immutable
public interface ValueObject {
  String name();
  List<Integer> counts();
  Optional<String> description();
}

// Compile using annotation processor and use it like this
ValueObject valueObject =
   ImmutableValueObject.builder()
      .name("My value")
      .addCounts(1)
      .addCounts(2)
      .build();
Extroversion answered 21/3, 2017 at 5:41 Comment(2)
I found your project already and contributed to it. Thank you ;-)Monitory
Did this necroposting for other people to found an answer. Thank you for participation and contributions!Extroversion
K
3

Lombok allows code like this:

@lombok.Data
@lombok.Builder
public class ImmutableCar implements Car {
    private final @lombok.NonNull String modelName;
    private final @lombok.NonNull int wheelCount;
}

The lombok annotations are processed at compile time (JSR-269) to generate the full class. It is also possible to look at the generated code by 'delomboking' via a Maven plugin.

Kleptomania answered 2/7, 2015 at 9:20 Comment(1)
As JSR-269 was mentioned, isn't it fair to mention that lombok is rather a compiler plugin masquerading as annotation processor and make you code JLS non-compliant? In other words, you suddenly end up programming in Java dialect rather than standard Java. Hint: JLS do not describe any means by which getter and other methods could appear on the class if they were not declared or inherited.Extroversion
S
3

Google have a tool called AutoValue that does this, except based on an abstract base class instead of an interface.

import com.google.auto.value.AutoValue;

class Example {
  @AutoValue
  abstract static class Animal {
    static Builder builder() {
      return new AutoValue_Example_Animal.Builder();
    }

    abstract String name();
    abstract int numberOfLegs();

    @AutoValue.Builder
    abstract static class Builder {
      abstract Builder name(String s);
      abstract Builder numberOfLegs(int n);
      abstract Animal build();
    }
  }
}

Another similar tool is Immutables; this is probably a closer match to the question, as it uses an interface and generates an immutable implementation and a builder.

Scaremonger answered 2/7, 2015 at 9:59 Comment(0)
E
3

Immutables (http://immutables.github.io) annotation processor is the exact match for your needs. It is full-featured and very customizable (you know all those set vs with vs no-prefix wars, - use whatever you prefer). It can generate immutable implementation with builders for interfaces, abstract classes, annotations. In addition, it can generate builders to invoke static factory methods or POJO constructors and many other things.

@Value.Immutable
public interface ValueObject {
  String name();
  List<Integer> counts();
  Optional<String> description();
}

// Compile using annotation processor and use it like this
ValueObject valueObject =
   ImmutableValueObject.builder()
      .name("My value")
      .addCounts(1)
      .addCounts(2)
      .build();
Extroversion answered 21/3, 2017 at 5:41 Comment(2)
I found your project already and contributed to it. Thank you ;-)Monitory
Did this necroposting for other people to found an answer. Thank you for participation and contributions!Extroversion
T
1

check out Eclipse Model2Text project and its subprojects, especially Acceleo and Xpand. they are generally used to generate EMF-based Java code for EMF models but they can be used to generate simple POJOs too.

however this functionality does not come out of the box: you'd have to create your own code generator and templates for it. see Accelelo tutorial .

EDIT:

one more idea - one so simple that it took me a day to realize it

you can use Velocity, Freemarker or similar template library (which are normally used for html generation). though still you need to make a model somewhere, in a .txt or .xml file for example. here's a tutorial on Velocity code generation.

Thinker answered 6/2, 2013 at 10:58 Comment(2)
What a pity that such a tool does not exist. I'll write my own library.Monitory
I've started an implementation and added it to github. Any feedback is very appreciated. github.com/before/quality-check/tree/master/modules/…Monitory
A
1

I just created an eclipse plugin https://github.com/karajdaar/templator.

It generates code based on Freemarker templates. The context to the Freemarker template is a ICompilationUnit which allows fully access to named classes and their information. We are using it to generate DAOs for NoSQL databases, jersey client, tests, etc.

I think it can easily do what is required here.

Anaglyph answered 21/3, 2013 at 16:44 Comment(0)
B
1

Here is how I do it today with features that were not available when the question was asked.

With Java 14+, there are records, a builtin way to make immutable classes, and it is compatible with lomboks builder:

@Builder
public record Person(String name, String address) {}

This will create an immutable Person class with all the common methods (equality, constructor, getters) behaving as one would expect from a Java-class. Lombok will generate the builder.

Details about records can be found at Baeldung, in the JEP or at oracle, but since they are designed to do what you expect, you will probably not have to go too deep into that.

Limitations: Records do not support inheritance. But you can define custom methods and implement interfaces.

Bethel answered 15/1 at 8:10 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.