Java generics + Builder pattern

If you are a fan of lombok project and using its annotation @Builder to achieve builder pattern then you can remove all the unnecessary code like you are writing and do it in less code.

Example:

@Builder
public class ErrorResponse<T> {
    private String message;
    private List<String> reasons;
    private List<String> details;
    private T data;
}

And you can initialize it like:

ErrorResponse<MyData> myDataError = ErrorResponse.<MyData>builder()
.message("My message")
.build();

You were close:

Foo.Builder.<Bar> start().setCount(1).setKey(bar).build();

Cheers! :)

P.S. If the compiler can't infer the type parameter of the method on its own, you can force it by calling obj.<Type> method(...) .

P.P.S you might want to use:

public Foo<K2> build() {
    return new Foo<K2>(this);
}

Avoid using raw types.


Andrei's method is okay, but most programmers will likely struggle with the rather unknown syntax. It might be easier to use this way:

static public <K3> Builder<K3> start(Class<K3> cls) { return new Builder<K3>(); }

Foo<Bar> foo1 = Foo.Builder.start(Bar.class).setCount(1).setKey(bar).build();

The class is only passed to help with the generic type. It's not pretty, but at least the syntax is common knowledge.

Another option would be to start right away with an object of the generic type:

Foo<Bar> foo1 = Foo.Builder.startWithKey(bar).setCount(1).build();

here's how I would do :

package odmor2018.krit.rtti.builderpattern;

import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;

public class Person {

    private String firstName;
    private String middleName;
    private String lastName;
    private boolean sex;

    public Person(String firstName, String middleName, String lastName, boolean sex) {
        this.firstName = firstName;
        this.middleName = middleName;
        this.lastName = lastName;
        this.sex = sex;
    }

    public Person() {
    }

    @Override
    public String toString() {
        return "Person{" + "firstName=" + firstName + ", middleName=" + middleName + ", lastName=" + lastName + ", sex=" + sex + '}';
    }

    public static class Builder {

        private final Field[] fields = Person.class.getDeclaredFields();
        private final List<Field> fieldsList = Arrays.asList(fields);
        private final List<String> fNames = fieldsList.stream().map(f -> f.getName()).collect(Collectors.toList());

        private final Person nP = new Person();

        public Builder with(String fName, Object value) {
            if (fNames.contains(fName)) {
                int fInd = fNames.indexOf(fName);
                try {
                    Field f = fields[fInd];
                    f.setAccessible(true);
                    f.set(nP, value);
                } catch (Exception ex) {
                    Logger.getLogger(Person.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
            return this;
        }

        public Person createPerson2() {
            return nP;
        }
    }

    public static void main(String[] args) {
        Person p3 = new Person.Builder()
                .with("firstName", "doooobri2")
                .with("sex", false)
                .createPerson2();
        System.err.println("p3:" + p3);
    }
}