projectlombok / lombok

Very spicy additions to the Java programming language.
https://projectlombok.org/
Other
12.82k stars 2.38k forks source link

[FEATURE] Strict builder annotation #3367

Open 3DRaven opened 1 year ago

3DRaven commented 1 year ago

Describe the feature I think need to create new annotation @StrictBuilder with realization of Builder with checking by compiler of full initialization. And annotation @StrictBuilders for multiple chains of initialization calls. As example it is "lomboked" code.

@StrictBuilder
public class Person {
    private final String username;
    private final int age;
}

//Allowed usage
Person.builder().username("Alice").age(10).build()
//Impossible usage
Person.builder().username("Alice").build()

Code without lombok

public class Person {
    private final String username;
    private final int age;

    Person(PersonBuilder personBuilder) {
        this.username = personBuilder.username;
        this.age = personBuilder.age;
    }

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

    public static class PersonUsernameBuilder {
        public PersonAgeBuilder username(String username) {
            return new PersonAgeBuilder(username);
        }
    }

    public static class PersonAgeBuilder {
        public final String username;

        PersonAgeBuilder(String username) {
            this.username = username;
        }

        public PersonBuilder age(int age) {
            return new PersonBuilder(username, age);
        }
    }

    public static class PersonBuilder {
        public final String username;
        public final int age;

        PersonBuilder(String username, int age) {
            this.username = username;
            this.age = age;
        }

        public Person build() {
            return new Person(this);
        }
    }
}

This annotation generate builder for all final fields in class. But with this approach you can have multiple chains of sub builders, so you can have set of some controlled fields combinations not only all fields. This is second variant of annotation - @StrictBuilders. Example: annotation with multiple "sub builders chains". All fields builder with this annotation must not generated by default. Order of fields in "fields" annotation parameter it is order of fields in generated sub builder.

@StrictBuilders({
        @StrictBuilders.FieldSet(name = "onlyUserBuilder", fields = {"username"}),
        @StrictBuilders.FieldSet(name = "onlyAgeBuilder", fields = {"age"})
})
public class Person {
......
}

//Usage
Person.onlyUserBuilder().username("username").build()
Person.onlyAgeBuilder().age(10).build()
//Imposible usage
Person.onlyUserBuilder().username("username").age(10).build()

Describe the target audience Lombok annotation @Builder has some problems with partially initialized classes. So, in some projects and companies this annotation totally restricted. This annotation for this projects. Additional context Based on this gist: https://gist.github.com/3DRaven/9a11ef9d0c42df6bf5603628327d88b3

janrieke commented 1 year ago

Have a look at the wiki: https://github.com/projectlombok/lombok/wiki/FEATURE-IDEA:-%22Mandatory%22-fields-with-@Builder

3DRaven commented 1 year ago

The described idea is simpler than what is in the wiki. That is why I described it. It does not lead to a combinatorial explosion of code, since it is necessary to explicitly list the order of calls that are allowed, or indicate that all should be called. And all sub builders it is nested classes (for IDE autocomplete). This is a completely different solution to this problem.