1

I'm modeling something in Java and using a Builder pattern. In a number of cases, some common members are defined in a parent, with additional members on children that inherit from the parent. An example is as follows:

public class Parent {
    private Integer age;

    static class ParentBuilder {
        private Integer age;

        public ParentBuilder age(Integer age) {
            this.age = age;
            return this;
        }
    }
}

and

public class Child extends Parent {

    private Integer height;

    static class ChildBuilder extends Parent.ParentBuilder {
        private Integer height;

        public ChildBuilder height(Integer height) {
            this.height = height;
            return this;
        }

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

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

    public Child(ChildBuilder b) {
        this.height = b.height;
    }
}

If I try to do something like

Child child = Child.builder()
    .age(18)
    .height(150)
    .build();

I get an error trying to compile:

Main.java:6: error: cannot find symbol
        .height(150)
        ^
symbol:   method height(int)
location: class ParentBuilder

If I remove .height(150) I then get the same error on .build(). It seems I have a fundamental misunderstanding of inheritance with static nested classes.

Why, when Child.builder() returns a ChildBuilder, is the compiler complaining about the method not being in ParentBuilder? Is there a way to make this work as I'm attempting to, leveraging inheritance together with this Builder pattern to allow common members to be defined in the parent and others on the child?

user207421
  • 305,947
  • 44
  • 307
  • 483
razor
  • 110
  • 1
  • 10
  • 4
    It is `age` that returns a `ParentBuilder`, hence why there is a complation error trying to invoke `height`. Look into http://stackoverflow.com/questions/21086417/builder-pattern-and-inheritance or http://stackoverflow.com/questions/17164375/subclassing-a-java-builder-class – Tunaki Feb 04 '17 at 22:38
  • I would only use `Integer` instead of `int` if a) the value could be `null` or b) you had no choice – Peter Lawrey Feb 04 '17 at 22:43
  • There are no [tag:inner-classes] here, only static nested classes, which are not inner by definition. – user207421 Feb 04 '17 at 22:45

1 Answers1

1

You can make it work with generics

static class ParentBuilder<B extends ParentBuilder<B>> {
    public B age(Integer age) {
        this.age = age;
        return (B) this;
    }
}

static class ChildBuilder extends Parent.ParentBuilder<ChildBuilder> {
    private Integer height;

    public ChildBuilder height(Integer height) {
        this.height = height;
        return this;
    }

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

This way age will return a ChildBuilder for a ChildBuilder

Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130