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?

3
  • 4
    It is age that returns a ParentBuilder, hence why there is a complation error trying to invoke height. Look into stackoverflow.com/questions/21086417/… or stackoverflow.com/questions/17164375/… Commented Feb 4, 2017 at 22:38
  • I would only use Integer instead of int if a) the value could be null or b) you had no choice Commented Feb 4, 2017 at 22:43
  • There are no inner-classes here, only static nested classes, which are not inner by definition. Commented Feb 4, 2017 at 22:45

1 Answer 1

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

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks, coupled with @Tunaki's link I think I've got it. Do need to cast this to (B) or use the getThis() pattern however.
@razor yes. You do need a cast. Updated the answer.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.