Alon
Alon

Reputation: 703

How to use generics to return child type from a parent method to support builder pattern

I am trying to support a builder pattern with inheritance, to allow chaining setters from parent and child class with no issue. For this I need the parent class to know to return back the child type to keep all methods exposed for chaining.

Here is a sample of code I wrote following this article which I think should work, But as you'll see, the first example using a1 works fine, but if I change the order of the setters, the last setter is not recognized.

Problem is: once I call a method from the parent class, it will return itself as a type and not the child, even thought T is defined as the child type.

public class JavaApplication1 {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        // TODO code application logic here

        A a1 = new B<>().setAge(0).setId(0).setName("name"); //Works fine
        A a2 = new B<>().setAge(0).setName("name").setId(0); //setId is not found

    }

    static class A<T extends A> {
        private String mpName;

        T setName(String name) {
            mpName = name;
            return (T) this;       
        }
    }

    static class B<T extends B> extends A<T> {
        private int mpAge;
        private int mpId;

        T setAge(int age) {
            mpAge = age;
            return (T) this;       
        }

        T setId(int id) {
            mpId = id;
            return (T) this;       
        }
    }
}

Upvotes: 2

Views: 3070

Answers (2)

Pavlo Viazovskyy
Pavlo Viazovskyy

Reputation: 937

You should change you classes definitions as following:

static class A<T extends A<T>>
static class B<T extends B<T>> extends A<T>

java.lang.Enum uses the same declaration. You can find explanation why it's required in this post.

Upvotes: 5

Andreas
Andreas

Reputation: 5113

Do we need parameterized types on the child class?

class Class {

  public static void main(String[] args) {

    new Child().setAge(0).setId(0).setName("name");
    new Child().setAge(0).setName("name").setId(0);

  }

  static class Parent<C extends Parent> {
    private String mpName;

    C setName(String name) {
      mpName = name;
      return (C) this;
    }
  }

  static class Child extends Parent<Child> {
    private int mpAge;
    private int mpId;

    Child setAge(int age) {
      mpAge = age;
      return this;
    }

    Child setId(int id) {
      mpId = id;
      return this;
    }
  }
}

Upvotes: 0

Related Questions