Give this Dr Dobbs article, and the Builder Pattern in particular, how do we handle the case of subclassing a Builder? Taking a cut-down version of the example where we want to subclass to add GMO labelling, a naive implementation would be:
public class NutritionFacts {
private final int calories;
public static class Builder {
private int calories = 0;
public Builder() {}
public Builder calories(int val) { calories = val; return this; }
public NutritionFacts build() { return new NutritionFacts(this); }
}
protected NutritionFacts(Builder builder) {
calories = builder.calories;
}
}
Subclass:
public class GMOFacts extends NutritionFacts {
private final boolean hasGMO;
public static class Builder extends NutritionFacts.Builder {
private boolean hasGMO = false;
public Builder() {}
public Builder GMO(boolean val) { hasGMO = val; return this; }
public GMOFacts build() { return new GMOFacts(this); }
}
protected GMOFacts(Builder builder) {
super(builder);
hasGMO = builder.hasGMO;
}
}
Now, we can write code like this:
GMOFacts.Builder b = new GMOFacts.Builder();
b.GMO(true).calories(100);
But, if we get the order wrong, it all fails:
GMOFacts.Builder b = new GMOFacts.Builder();
b.calories(100).GMO(true);
The problem is of course that NutritionFacts.Builder returns a NutritionFacts.Builder, not a GMOFacts.Builder, so how do we solve this problem, or is there a better Pattern to use?
Note: this answer to a similar question offers up the classes I have above; my question is regarding the problem of ensuring the builder calls are in the correct order.
You can solve it using generics. I think this is called the "Curiously recurring generic patterns"
Make the return type of the base class builder methods a generic argument.
public class NutritionFacts {
private final int calories;
public static class Builder<T extends Builder<T>> {
private int calories = 0;
public Builder() {}
public T calories(int val) {
calories = val;
return (T) this;
}
public NutritionFacts build() { return new NutritionFacts(this); }
}
protected NutritionFacts(Builder<?> builder) {
calories = builder.calories;
}
}
Now instantiate the base builder with the derived class builder as the generic argument.
public class GMOFacts extends NutritionFacts {
private final boolean hasGMO;
public static class Builder extends NutritionFacts.Builder<Builder> {
private boolean hasGMO = false;
public Builder() {}
public Builder GMO(boolean val) {
hasGMO = val;
return this;
}
public GMOFacts build() { return new GMOFacts(this); }
}
protected GMOFacts(Builder builder) {
super(builder);
hasGMO = builder.hasGMO;
}
}
Just for the record, to get rid of the
unchecked or unsafe operations warning
for the return (T) this; statement as #dimadima and #Thomas N. talk about, following solution applies in certain cases.
Make abstract the builder which declares the generic type (T extends Builder in this case) and declare protected abstract T getThis() abstract method as follows:
public abstract static class Builder<T extends Builder<T>> {
private int calories = 0;
public Builder() {}
/** The solution for the unchecked cast warning. */
public abstract T getThis();
public T calories(int val) {
calories = val;
// no cast needed
return getThis();
}
public NutritionFacts build() { return new NutritionFacts(this); }
}
Refer to http://www.angelikalanger.com/GenericsFAQ/FAQSections/ProgrammingIdioms.html#FAQ205 for further details.
Based off of a blog post, this approach requires all the non-leaf classes to be abstract, and all the leaf classes must be final.
public abstract class TopLevel {
protected int foo;
protected TopLevel() {
}
protected static abstract class Builder
<T extends TopLevel, B extends Builder<T, B>> {
protected T object;
protected B thisObject;
protected abstract T createObject();
protected abstract B thisObject();
public Builder() {
object = createObject();
thisObject = thisObject();
}
public B foo(int foo) {
object.foo = foo;
return thisObject;
}
public T build() {
return object;
}
}
}
Then, you have some intermediate class that extends this class and its builder, and as many more as you need:
public abstract class SecondLevel extends TopLevel {
protected int bar;
protected static abstract class Builder
<T extends SecondLevel, B extends Builder<T, B>> extends TopLevel.Builder<T, B> {
public B bar(int bar) {
object.bar = bar;
return thisObject;
}
}
}
And, finally a concrete leaf class that can call all the builder methods on any of its parents in any order:
public final class LeafClass extends SecondLevel {
private int baz;
public static final class Builder extends SecondLevel.Builder<LeafClass,Builder> {
protected LeafClass createObject() {
return new LeafClass();
}
protected Builder thisObject() {
return this;
}
public Builder baz(int baz) {
object.baz = baz;
return thisObject;
}
}
}
Then, you can call the methods in any order, from any of the classes in the hierarchy:
public class Demo {
LeafClass leaf = new LeafClass.Builder().baz(2).foo(1).bar(3).build();
}
You can override also the calories() method, and let it return the extending builder. This compiles because Java supports covariant return types.
public class GMOFacts extends NutritionFacts {
private final boolean hasGMO;
public static class Builder extends NutritionFacts.Builder {
private boolean hasGMO = false;
public Builder() {
}
public Builder GMO(boolean val)
{ hasGMO = val; return this; }
public Builder calories(int val)
{ super.calories(val); return this; }
public GMOFacts build() {
return new GMOFacts(this);
}
}
[...]
}
There is also another way to create classes according to Builder pattern, which conforms "Prefer composition over inheritance".
Define an interface, that parent class Builder will inherit:
public interface FactsBuilder<T> {
public T calories(int val);
}
The implementation of NutritionFacts is almost the same (except for Builder implementing 'FactsBuilder' interface):
public class NutritionFacts {
private final int calories;
public static class Builder implements FactsBuilder<Builder> {
private int calories = 0;
public Builder() {
}
#Override
public Builder calories(int val) {
return this;
}
public NutritionFacts build() {
return new NutritionFacts(this);
}
}
protected NutritionFacts(Builder builder) {
calories = builder.calories;
}
}
The Builder of a child class should extend the same interface (except different generic implementation):
public static class Builder implements FactsBuilder<Builder> {
NutritionFacts.Builder baseBuilder;
private boolean hasGMO = false;
public Builder() {
baseBuilder = new NutritionFacts.Builder();
}
public Builder GMO(boolean val) {
hasGMO = val;
return this;
}
public GMOFacts build() {
return new GMOFacts(this);
}
#Override
public Builder calories(int val) {
baseBuilder.calories(val);
return this;
}
}
Notice, that NutritionFacts.Builder is a field inside GMOFacts.Builder (called baseBuilder). The method implemented from FactsBuilder interface calls baseBuilder's method of the same name:
#Override
public Builder calories(int val) {
baseBuilder.calories(val);
return this;
}
There is also a big change in the constructor of GMOFacts(Builder builder). The first call in the constructor to parent class constructor should pass appropriate NutritionFacts.Builder:
protected GMOFacts(Builder builder) {
super(builder.baseBuilder);
hasGMO = builder.hasGMO;
}
The full implementation of GMOFacts class:
public class GMOFacts extends NutritionFacts {
private final boolean hasGMO;
public static class Builder implements FactsBuilder<Builder> {
NutritionFacts.Builder baseBuilder;
private boolean hasGMO = false;
public Builder() {
}
public Builder GMO(boolean val) {
hasGMO = val;
return this;
}
public GMOFacts build() {
return new GMOFacts(this);
}
#Override
public Builder calories(int val) {
baseBuilder.calories(val);
return this;
}
}
protected GMOFacts(Builder builder) {
super(builder.baseBuilder);
hasGMO = builder.hasGMO;
}
}
A full 3 level example of multiple builder inheritance would look like this:
(For the version with a copy constructor for the builder see the second example below)
First level - parent (potentially abstract)
import lombok.ToString;
#ToString
#SuppressWarnings("unchecked")
public abstract class Class1 {
protected int f1;
public static class Builder<C extends Class1, B extends Builder<C, B>> {
C obj;
protected Builder(C constructedObj) {
this.obj = constructedObj;
}
B f1(int f1) {
obj.f1 = f1;
return (B)this;
}
C build() {
return obj;
}
}
}
Second level
import lombok.ToString;
#ToString(callSuper=true)
#SuppressWarnings("unchecked")
public class Class2 extends Class1 {
protected int f2;
public static class Builder<C extends Class2, B extends Builder<C, B>> extends Class1.Builder<C, B> {
public Builder() {
this((C) new Class2());
}
protected Builder(C obj) {
super(obj);
}
B f2(int f2) {
obj.f2 = f2;
return (B)this;
}
}
}
Third level
import lombok.ToString;
#ToString(callSuper=true)
#SuppressWarnings("unchecked")
public class Class3 extends Class2 {
protected int f3;
public static class Builder<C extends Class3, B extends Builder<C, B>> extends Class2.Builder<C, B> {
public Builder() {
this((C) new Class3());
}
protected Builder(C obj) {
super(obj);
}
B f3(int f3) {
obj.f3 = f3;
return (B)this;
}
}
}
And an example of usage
public class Test {
public static void main(String[] args) {
Class2 b1 = new Class2.Builder<>().f1(1).f2(2).build();
System.out.println(b1);
Class2 b2 = new Class2.Builder<>().f2(2).f1(1).build();
System.out.println(b2);
Class3 c1 = new Class3.Builder<>().f1(1).f2(2).f3(3).build();
System.out.println(c1);
Class3 c2 = new Class3.Builder<>().f3(3).f1(1).f2(2).build();
System.out.println(c2);
Class3 c3 = new Class3.Builder<>().f3(3).f2(2).f1(1).build();
System.out.println(c3);
Class3 c4 = new Class3.Builder<>().f2(2).f3(3).f1(1).build();
System.out.println(c4);
}
}
A bit longer version featuring a copy constructor for the builder:
First level - parent (potentially abstract)
import lombok.ToString;
#ToString
#SuppressWarnings("unchecked")
public abstract class Class1 {
protected int f1;
public static class Builder<C extends Class1, B extends Builder<C, B>> {
C obj;
protected void setObj(C obj) {
this.obj = obj;
}
protected void copy(C obj) {
this.f1(obj.f1);
}
B f1(int f1) {
obj.f1 = f1;
return (B)this;
}
C build() {
return obj;
}
}
}
Second level
import lombok.ToString;
#ToString(callSuper=true)
#SuppressWarnings("unchecked")
public class Class2 extends Class1 {
protected int f2;
public static class Builder<C extends Class2, B extends Builder<C, B>> extends Class1.Builder<C, B> {
public Builder() {
setObj((C) new Class2());
}
public Builder(C obj) {
this();
copy(obj);
}
#Override
protected void copy(C obj) {
super.copy(obj);
this.f2(obj.f2);
}
B f2(int f2) {
obj.f2 = f2;
return (B)this;
}
}
}
Third level
import lombok.ToString;
#ToString(callSuper=true)
#SuppressWarnings("unchecked")
public class Class3 extends Class2 {
protected int f3;
public static class Builder<C extends Class3, B extends Builder<C, B>> extends Class2.Builder<C, B> {
public Builder() {
setObj((C) new Class3());
}
public Builder(C obj) {
this();
copy(obj);
}
#Override
protected void copy(C obj) {
super.copy(obj);
this.f3(obj.f3);
}
B f3(int f3) {
obj.f3 = f3;
return (B)this;
}
}
}
And an example of usage
public class Test {
public static void main(String[] args) {
Class3 c4 = new Class3.Builder<>().f2(2).f3(3).f1(1).build();
System.out.println(c4);
// Class3 builder copy
Class3 c42 = new Class3.Builder<>(c4).f2(12).build();
System.out.println(c42);
Class3 c43 = new Class3.Builder<>(c42).f2(22).f1(11).build();
System.out.println(c43);
Class3 c44 = new Class3.Builder<>(c43).f3(13).f1(21).build();
System.out.println(c44);
}
}
If you don't want to poke your eye out on an angle bracket or three, or perhaps don't feel you... umm... I mean... cough... the rest of your team will quickly comprehend curiously recurring generics pattern, you can do this:
public class TestInheritanceBuilder {
public static void main(String[] args) {
SubType.Builder builder = new SubType.Builder();
builder.withFoo("FOO").withBar("BAR").withBaz("BAZ");
SubType st = builder.build();
System.out.println(st.toString());
builder.withFoo("BOOM!").withBar("not getting here").withBaz("or here");
}
}
supported by
public class SubType extends ParentType {
String baz;
protected SubType() {}
public static class Builder extends ParentType.Builder {
private SubType object = new SubType();
public Builder withBaz(String baz) {
getObject().baz = baz;
return this;
}
public Builder withBar(String bar) {
super.withBar(bar);
return this;
}
public Builder withFoo(String foo) {
super.withFoo(foo);
return this;
}
public SubType build() {
// or clone or copy constructor if you want to stamp out multiple instances...
SubType tmp = getObject();
setObject(new SubType());
return tmp;
}
protected SubType getObject() {
return object;
}
private void setObject(SubType object) {
this.object = object;
}
}
public String toString() {
return "SubType2{" +
"baz='" + baz + '\'' +
"} " + super.toString();
}
}
and the parent type:
public class ParentType {
String foo;
String bar;
protected ParentType() {}
public static class Builder {
private ParentType object = new ParentType();
public ParentType object() {
return getObject();
}
public Builder withFoo(String foo) {
if (!"foo".equalsIgnoreCase(foo)) throw new IllegalArgumentException();
getObject().foo = foo;
return this;
}
public Builder withBar(String bar) {
getObject().bar = bar;
return this;
}
protected ParentType getObject() {
return object;
}
private void setObject(ParentType object) {
this.object = object;
}
public ParentType build() {
// or clone or copy constructor if you want to stamp out multiple instances...
ParentType tmp = getObject();
setObject(new ParentType());
return tmp;
}
}
public String toString() {
return "ParentType2{" +
"foo='" + foo + '\'' +
", bar='" + bar + '\'' +
'}';
}
}
Key points:
Encapsulate the object in the builder so that inheritance prevents you from setting the field on the object held in the parent type
Calls to super ensure that logic (if any) added to the super type builder methods is retained in the sub types.
Down side is spurious object creation in the parent class(es)... But see below for a way to clean that up
Up side is much easier to understand at a glance, and no verbose constructor transferring properties.
If you have multiple threads accessing your builder objects... I guess I'm glad I'm not you :).
EDIT:
I found a way around the spurious object creation. First add this to each builder:
private Class whoAmI() {
return new Object(){}.getClass().getEnclosingMethod().getDeclaringClass();
}
Then in the constructor for each builder:
if (whoAmI() == this.getClass()) {
this.obj = new ObjectToBuild();
}
The cost is an extra class file for the new Object(){} anonymous inner class
One thing you could do is to create a static factory method in each of your classes:
NutritionFacts.newBuilder()
GMOFacts.newBuilder()
This static factory method would then return the appropriate builder. You can have a GMOFacts.Builder extending a NutritionFacts.Builder, that is not a problem. THE problem here will be to deal with visibility...
I created a parent, abstract generic builder class that accepts two formal type parameters. First is for the type of object returned by build(), the second is the type returned by each optional parameter setter. Below are parent and child classes for illustrative purpose:
// **Parent**
public abstract static class Builder<T, U extends Builder<T, U>> {
// Required parameters
private final String name;
// Optional parameters
private List<String> outputFields = null;
public Builder(String pName) {
name = pName;
}
public U outputFields(List<String> pOutFlds) {
outputFields = new ArrayList<>(pOutFlds);
return getThis();
}
/**
* This helps avoid "unchecked warning", which would forces to cast to "T" in each of the optional
* parameter setters..
* #return
*/
abstract U getThis();
public abstract T build();
/*
* Getters
*/
public String getName() {
return name;
}
}
// **Child**
public static class Builder extends AbstractRule.Builder<ContextAugmentingRule, ContextAugmentingRule.Builder> {
// Required parameters
private final Map<String, Object> nameValuePairsToAdd;
// Optional parameters
private String fooBar;
Builder(String pName, Map<String, String> pNameValPairs) {
super(pName);
/**
* Must do this, in case client code (I.e. JavaScript) is re-using
* the passed in for multiple purposes. Doing {#link Collections#unmodifiableMap(Map)}
* won't caught it, because the backing Map passed by client prior to wrapping in
* unmodifiable Map can still be modified.
*/
nameValuePairsToAdd = new HashMap<>(pNameValPairs);
}
public Builder fooBar(String pStr) {
fooBar = pStr;
return this;
}
#Override
public ContextAugmentingRule build() {
try {
Rule r = new ContextAugmentingRule(this);
storeInRuleByNameCache(r);
return (ContextAugmentingRule) r;
} catch (RuleException e) {
throw new IllegalArgumentException(e);
}
}
#Override
Builder getThis() {
return this;
}
}
This one has met my needs to satisfaction.
The following IEEE contribution Refined Fluent Builder in Java gives a comprehensive solution to the problem.
It dissects the original question into two sub-problems of inheritance deficiency and quasi invariance and shows how a solution to these two sub-problems opens for inheritance support with code reuse in the classical builder pattern in Java.
Related
I have following code implementing abstract builder (as in effective java book):
interface I {
I ret();
}
abstract class A implements I {
private String s = "";
A(Builder b) {
s = b.s;
}
#Override
public I ret() {
String s = "some new string from calc.";
//HERE I NEED TO CONSTRUCT class B
//THIS IS PROBLEMATIC LINE BELOW <<<<--------------------------------------
return new Builder<>().withString(s).build();
}
static abstract class Builder<T extends Builder<T>> {
String s = "";
T withString(String s) {
this.s = s;
return self();
}
protected abstract A build();
//simulated self-type idiom
protected abstract T self();
}
}
class B extends A {
private B(A.Builder b) {
super(b);
}
static class Builder extends A.Builder<Builder> {
#Override
protected B build() {
return new B(this);
}
#Override
protected Builder self() {
return this;
}
}
}
and this is small use-case
public static void main(String[] args) {
I b = new B.Builder().withString("bclass").build();
I b2 = b.ret(); //<---- this one should construct new immutable B
}
What I want to do is - from ret() method in the class A, I would like to construct immutable object that is ignorant of parent type - so in my example it would be new class B that has new inner string.
Problem is that class A does not know about class B, since B is it's parent.
Is something like this possible without resorting for generics?
If I use mutable class, it would be as simple as this.s = newS;.
UPDATE
abstract class A implements I {
private String s = "";
A(Builder b) {
s = b.s;
}
#Override
public I ret() {
String s = "SOME NEW STING FROM CALCULATION";
return builder().withString(s).build();
}
abstract Builder<?> builder();
static abstract class Builder<T extends Builder<T>> {
String s = "";
T withString(String s) {
this.s = s;
return self();
}
protected abstract A build();
//simulated self-type idiom
protected abstract T self();
}
}
class B extends A {
B(A.Builder b) {
super(b);
}
#Override
Builder builder() {
return new Builder();
}
static class Builder extends A.Builder<Builder> {
#Override
protected B build() {
return new B(this);
}
#Override
protected Builder self() {
return this;
}
}
}
You need to provide an abstract method in A to construct a suitable instance of Builder:
abstract Builder<A> toBuilder();
Then implement that in the concrete subclasses, and invoke:
return toBuilder().withString(s).build();
I have the following Manager Class with the builder() method:
public class Manager extends Employee {
public static Manager.Builder builder() {
return new ManagerBuilder();
}
public abstract static class Builder<T extends Employee, B extends Builder<T,B>> extends Employee.Builder<T,B>{
}
public static class ManagerBuilder extends Builder<Manager,ManagerBuilder> {
#Override
protected ManagerBuilder self() {
return this;
}
#Override
public Manager build() {
return new Manager(this);
}
}
}
unfortunatelly trying to build an Object with Manager.builder().age(25).build(); return a Person and not a Manager as I need.
How should I change the Manager.builder() return type to return a Manager and at the same time not clashing with the Employee.builder() Method signature.
The code Employee.builder().age(25).build(); returns Employee, which is fine.
The Employee Class is looking like this:
public class Employee extends Person {
public static Employee.Builder<Employee, EmployeeBuilder> builder() {
return new EmployeeBuilder();
}
public abstract static class Builder<T extends Person, B extends Builder<T,B>> extends Person.Builder<T,B>{
}
public static class EmployeeBuilder extends Builder<Employee, EmployeeBuilder> {
#Override
protected EmployeeBuilder self() {
return this;
}
#Override
public Employee build() {
return new Employee(this);
}
}
}
public class Person implements PersonInterface {
private Optional<Integer> age;
protected Person(Builder<?,?> builder) {
this.age = builder.age;
}
public abstract static class Builder<T extends Person, B extends Builder<T,B>> {
private Optional<Integer> age;
protected Builder() {
}
public B age(Integer age) {
if (Objects.isNull(age) || age == 0) throw new IllegalArgumentException("Age ist empty");
this.age = Optional.of(age);
return self();
}
protected abstract B self();
public abstract T build();
}
public static class PersonBuilder extends Builder<Person, PersonBuilder>{
#Override
protected PersonBuilder self() {
return this;
}
#Override
public Person build() {
return new Person(this);
}
}
}
The core problem is your strange inheritance structure which overloads the classname Builder. I cant' quite pin the problem down, but at some point your specific type information of ManagerBuilder is lost. This can be simplyfied a lot:
public class Employee extends Person {
public static EmployeeBuilder builder() {
return new EmployeeBuilder();
}
public static class EmployeeBuilder extends Person.Builder<Employee, EmployeeBuilder> {
#Override
protected EmployeeBuilder self() {
return this;
}
#Override
public Employee build() {
return new Employee(this);
}
}
}
public class Manager extends Employee {
public static ManagerBuilder builder() {
return new ManagerBuilder();
}
public static class ManagerBuilder extends Person.Builder<Manager, ManagerBuilder> {
#Override
protected ManagerBuilder self() {
return this;
}
#Override
public Manager build() {
return new Manager(this);
}
}
}
This should solve a few of your problems.
Now you are left with one more problem. The static method builder is overloaded with incompatible return types. You find information about this at Why does Java enforce return type compatibility for overridden static methods?
If you name those methods differently, it should work.
Well your code works perfectly, and Manager.builder().age(25).build() actually returns a Manager. It is only a compile time problem.
The following Junit test should succeed (it does on my tests):
#Test
public void testEss3() throws Exception {
Person emp = Manager.builder().age(25).build();
assertTrue(emp instanceof Manager);
}
In fact, it looks like as you declare no variable to host the builder, and as the method age is not defined in Manager.Builder nor in its direct subclass Employee.Builder, the Java compiler assume that it will return an object of the class in which it is declared, that is a Person.Builder. It is not false because it is actually an ancestor class. But from that point, the compiler do not know the exact class returned by build() and only knows that it will be a Person.
But the following code is accepter by the compiler:
Manager.Builder<Manager,?> builder = Manager.builder();
Manager emp = builder.age(25).build();
public interface A extends C {
String getCh();
String getId();
String getReview();
}
public interface B extends C {
String getCh();
String getId();
String getReview();
}
#Data
#Builder
public class AImpl implements A{
private String ch;
private String id;
private String review;
}
#Data
#Builder
public class BImpl implements B{
private String ch;
private String id;
private String review;
}
so now to use the builders of these I do:
return AImpl.builder()
.ch("ch")
.id("id")
.review("somerview");
For B I do:
return BImpl.builder()
.ch("ch1")
.id("id1")
.review("some new review");
Is there a way where I can make this builder part into a function? I dont like the idea of repeating the same code again. Like where I can pass id channel and review in a function and I can the object?
Disclaimer: I have never really dealt with builders so there might be a really much better option :D
This approach writes builders for each interface individually.
This does require that the interfaces provide a setter method.
Using generics, the methods of the RootBuilder and BaseABuilder return an instance of the ImplABuilder so that the chain can continue properly.
This is a very simple implementation of the Thistype generic which in other languages exists by default. This implementation also relies on casting to the actual Thistype but if you set the generics properly, that shouldnt be an issue.
public class Test
{
public static void main(String[] args)
{
ImplA implA = ImplA
.builder()
.id("id")
.description("description")
.valueA("a")
.build();
}
}
public interface Root
{
String getId();
void setId(String id);
String getDescription();
void setDescription(String description);
}
public class RootBuilder<Thistype extends RootBuilder<Thistype, Instance>, Instance extends Root>
{
protected final Instance object;
RootBuilder(Instance object)
{
this.object = object;
}
public Thistype id(String value)
{
object.setId(value);
return (Thistype)this;
}
public Thistype description(String value)
{
object.setDescription(value);
return (Thistype)this;
}
public Instance build()
{
return object;
}
}
public interface BaseA extends Root
{
String getValueA();
void setValueA(String valueA);
}
public class BaseABuilder<Thistype extends BaseABuilder<Thistype, Instance>, Instance extends BaseA> extends RootBuilder<Thistype, Instance>
{
protected Instance object;
BaseABuilder(Instance object)
{
super(object);
}
public Thistype valueA(String value)
{
object.setValueA(value);
return (Thistype)this;
}
}
public interface BaseB extends Root
{
String getValueB();
void setValueB(String valueB);
}
public interface BaseC extends Root
{
String getValueC();
void setValueC(String valueC);
}
public final class ImplA implements BaseA
{
private String id;
private String description;
private String valueA;
private ImplA() { }
public static ImplABuilder builder()
{
return new ImplABuilder(new ImplA());
}
private static class ImplABuilder extends BaseABuilder<ImplABuilder, ImplA> // assuming ImplA is final
{
ImplABuilder(ImplA object)
{
super(object);
}
// additional methods for ImplA class
}
}
I want to implement Builder Pattern with inheritance. So I have 4 following classes: one abstract class (ClassA), ClassB, ClassC. TestTest class is used to see how all this works:
public abstract class ClassA {
private String aString;
public String getaString() {
return aString;
}
public abstract class ClassABuilder<T extends ClassABuilder>{
public T setaString(String str) {
ClassA.this.aString = str;
return (T)this;
}
public abstract ClassA build();
}
}
public class ClassB extends ClassA{
private String bString;
public String getbString() {
return bString;
}
public class ClassBBuilder<T extends ClassBBuilder> extends ClassA.ClassABuilder<T>{
public T setbString(String str) {
ClassB.this.bString = str;
return (T)this;
}
#Override
public ClassB build(){
return ClassB.this;
}
}
}
public class ClassC extends ClassB{
private String cString;
public String getcString() {
return cString;
}
public static ClassCBuilder<ClassCBuilder> newBuilder(){
return new ClassC().new ClassCBuilder();
}
public class ClassCBuilder<T extends ClassCBuilder> extends ClassB.ClassBBuilder<T>{
public T setcString(String str) {
ClassC.this.cString = str;
return (T)this;
}
#Override
public ClassC build(){
return ClassC.this;
}
}
}
public class TestTest {
public static void main(String[] args) {
// TODO code application logic here
ClassC C=ClassC.newBuilder()
.setaString(null)
.setbString(null)
.setcString(null) //LINE XXX
.build();
}
}
The problem is that at TestTest at LINE XXX I get can't find symbol "setcString". What do I do wrong?
Let's track it down along the hierarchy:
First consider this signature:
class ClassABuilder<T extends ClassABuilder>
When you call setaString(null) the returned T will be an object that extends ClassABuilder. The compiler knows that this is a ClassBBuilder and thus will allow you to call setbString(null).
However, since the definition states T is required to extend a raw ClassBBuilder only any information on ClassBBuilder's generic types will be lost. Thus the compiler only knows that T is a ClassBBuilder but not that it's actually a ClassCBuilder which extends ClassBBuilder<ClassCBuilder> and hence doesn't know about setcString() on the returned type.
As has already been mentioned, using T extends ClassABuilder<T> will fix that since now the compiler knows there's another generic type to be passed down the hierarchy.
newBuilder() would then have to look like this:
public static ClassCBuilder<?> newBuilder(){
//you have too create a raw type here so you'll have to ignore/suppress/live with the warning
return (new ClassC().new ClassCBuilder());
}
As #AndyTurner already observed, the problem is that you use raw versions of your builder class types as type parameters. He did not go into detail, but the upshot is this:
ClassC C=ClassC.newBuilder() // yields a ClassCBuilder<ClassCBuilder>
.setaString(null) // yields a raw ClassCBuilder (type parameter)
.setbString(null) // yields a raw ClassBBuilder (type parameter bound)
.setcString(null) // ERROR: no such method on ClassBBuilder
.build();
To fix this with minimal change to your class structure and strategy, you must not only correct the type parameter bounds for your builder classes, as Andy advised ...
ClassABuilder<T extends ClassABuilder<T>>
... etc., but also make a change to ClassC.newBuilder(), such as to make it generic:
public static <T extends ClassCBuilder<T>> ClassCBuilder<T> newBuilder() {
return new ClassC().new ClassCBuilder<T>();
}
With that combination of changes, your code compiles for me.
I would like to post here the test demonstrating builder pattern with deep inheritance.
class TypeParamTest {
#Test
void test() {
Dd dd = Dd.builder()
.setIntAa(0)
.setIntBb(1)
.setIntCc(2)
.setIntDd(3)
.build();
assertEquals(0, dd.intAa);
assertEquals(1, dd.intBb);
assertEquals(2, dd.intCc);
assertEquals(3, dd.intDd);
}
abstract static class Aa {
int intAa;
static class AaBuilder<B extends AaBuilder> {
int intAa;
Aa build(Aa aa) {
aa.intAa = intAa;
return aa;
}
B setIntAa(int i) {
this.intAa = i;
return (B) this;
}
}
}
abstract static class Bb extends Aa {
int intBb;
static class BbBuilder<B extends BbBuilder<B>>
extends AaBuilder<B>
{
int intBb;
Bb build(Bb bb) {
bb = (Bb) super.build(bb);
bb.intBb = intBb;
return bb;
}
B setIntBb(int i) {
this.intBb = i;
return (B) this;
}
}
}
static class Cc extends Bb {
int intCc;
static CcBuilder<?> builder() {
return new CcBuilder<>();
}
static class CcBuilder<B extends CcBuilder<B>>
extends BbBuilder<B>
{
int intCc;
Cc build() {
return build(new Cc());
}
Cc build(Cc cc) {
cc = (Cc) super.build(cc);
cc.intCc = intCc;
return cc;
}
B setIntCc(int i) {
this.intCc = i;
return (B) this;
}
}
}
static class Dd extends Cc {
int intDd;
static DdBuilder<?> builder() {
return new DdBuilder<>();
}
static class DdBuilder<B extends DdBuilder<B>>
extends CcBuilder<B>
{
int intDd;
Dd build() {
return build(new Dd());
}
Dd build(Dd dd) {
dd = (Dd) super.build(dd);
dd.intDd = intDd;
return dd;
}
B setIntDd(int i) {
this.intDd = i;
return (B) this;
}
}
}
}
UPDATE: I got it! It turns out that the "GENERICS" comment from Boris the Spider was exactly the clue I needed.
Original question and broken code first, solution below that. My generic design for needer-needable below that.
Original question and non-working code
On and off for the past few years, I have been trying to make self-returning method-chains "sharable" with other classes. This is to avoid the big pain of having to duplicate every self-returning function in every sub-class. The basic idea is that you pass the "needer" class to the "needable" class to start configuration, and then pass the needer back when configuration is over. The "needed" object is set internally.
For example:
ConfigUser cu = (new ConfigUser()).
cfgFavNum().twentySeven().increment().timesTwo().endCfg().
firstName("Kermit").lastName("Frog");
where
firstName("Kermit").lastName("Frog")
are part of the ConfigUser class, and
twentySeven().increment().timesTwo().endCfg()
comes from a separate "config the number" class. endCfg() returns the "needer" class (ConfigUser), at which point you should be able to continue the chain back in ConfigUser. But you can't. In the below code...and in every attempt I have made, I end up with the same error:
C:\java\ConfigUser.java:4: cannot find symbol
symbol : method firstName(java.lang.String)
location: interface NeedsFavNum
cfgFavNum().twentySeven().increment().timesTwo().endCfg().
^
If you comment out everything after endCfg() it reveals the problem:
ConfigUser cu = (new ConfigUser()).
cfgFavNum().twentySeven().increment().timesTwo().endCfg();//.
//firstName("Kermit").lastName("Frog");
C:\java\ConfigUser.java:15: incompatible types
found : NeedsFavNum
required: ConfigUser
cfgFavNum().twentySeven().increment().timesTwo().endCfg();//.
^
It can't return ConfigUser, which is sub-class of NeedsFavNum, which is the interface for all classes "needing" the favorite-number-config.
Of course, you can duplicate all the functions so they ALL return ConfigUser-s, but that defeats the purpose of sharing chains. The purpose is to share these chains among ANY class, not just sub-classes.
Is there any way to achieve this, or to rethink the whole issue? I'm starting to think that it is simply not possible.
The details are in the below code. It works (...up to these compilation errors, anyway): copy it into a file named ConfigUser.java and give it a try.
Thank you for helping me.
public class ConfigUser implements NeedsFavNum {
public static final void main(String[] igno_red) {
ConfigUser cu = (new ConfigUser()).
cfgFavNum().twentySeven().increment().timesTwo().endCfg().
firstName("Kermit").lastName("Frog");
cu = (new ConfigUser()). cfgFavNum().twentySeven().increment().timesTwo().endCfg();//.
// firstName("Kermit").lastName("Frog");
}
//init
public static final int iDEFAULT_FAV = 8;
int iFav = -1;
String sName1st = null;
String sNameLast = null;
//funcs
public ConfigUser() {
}
public ConfigUser firstName(String s_s) {
sName1st = s_s;
}
public ConfigUser lastName(String s_s) {
sNameLast = s_s;
}
public FavNumConfigurator cfgFavNum() {
return new FavNumConfigurator(this, iDEFAULT_FAV);
}
public ConfigUser setNumReturnNeeder(int i_favFullyConfigured) {
iFav = i_favFullyConfigured;
return this;
}
}
interface NeedsFavNum {
ConfigUser setNumReturnNeeder(int i_fav);
}
class FavNumConfigurator {
NeedsFavNum nfn = null;
int iFav = -1;
public FavNumConfigurator(NeedsFavNum nf_n, int i_defaultFav) {
nfn = nf_n;
iFav = i_defaultFav;
}
public FavNumConfigurator twentySeven() {
iFav = 27;
}
public FavNumConfigurator timesTwo() {
iFav = iFav * 2;
}
public FavNumConfigurator increment() {
iFav += 1;
}
public NeedsFavNum endCfg() {
return nfn.setNumReturnNeeder(iFav);
}
}
Solution with working code
It turns out that the "GENERICS" comment from Boris the Spider was exactly the clue I needed. Instead of the "needable" class being
FavNumConfigurator
now its
FavNumConfigurator<R extends FavNumNeeder>
where FavNumNeeder is the "needer" interface for any class needing the favorite-number configuration chain. Now the endCfg() function can return exactly the class I want.
Here's the fixed example (it works--copy and save it as ConfigUser.java):
/**
<P>The main class: the "needer".</P>
**/
public class ConfigUser implements NeedsFavNum {
public static final void main(String[] igno_red) {
ConfigUser cu = (new ConfigUser()).
cfgFavNum().twentySeven().increment().timesTwo().timesTwo().endCfg().
firstName("Kermit").lastName("Frog");
System.out.println("name: " + cu.sName1st + " " + cu.sNameLast);
System.out.println("favorite-num: " + cu.iFav);
//---OUTPUT:
//name: Kermit Frog
//favorite-num: 112
}
//init
public static final int iDEFAULT_FAV = 8;
int iFav = -1;
String sName1st = null;
String sNameLast = null;
//funcs
public ConfigUser() {
}
//Self-returning configurers...START
public ConfigUser firstName(String s_s) {
sName1st = s_s;
return this;
}
public ConfigUser lastName(String s_s) {
sNameLast = s_s;
return this;
}
//Self-returning configurers...END
//Start fav-num configuration. Returns the "needable"
public FavNumConfigurator<ConfigUser> cfgFavNum() {
return (new FavNumConfigurator<ConfigUser>(this, iDEFAULT_FAV));
}
//Called by the "needable" in endCfg()
public ConfigUser setNumReturnNeeder(int i_favFullyConfigured) {
iFav = i_favFullyConfigured;
return this;
}
}
//The "needer" interface, for all classes needing favorite-number
//configuration
interface NeedsFavNum {
ConfigUser setNumReturnNeeder(int i_fav);
}
//The "needable" class: A shareable function-chain for favorite-number
class FavNumConfigurator<R extends NeedsFavNum> {
R nfn = null;
int iFav = -1;
public FavNumConfigurator(R nf_n, int i_defaultFav) {
nfn = nf_n;
iFav = i_defaultFav;
}
//Self-returning configurers...START
public FavNumConfigurator<R> twentySeven() {
iFav = 27;
return this;
}
public FavNumConfigurator<R> timesTwo() {
iFav = iFav * 2;
return this;
}
public FavNumConfigurator<R> increment() {
iFav += 1;
return this;
}
//Self-returning configurers...END
public R endCfg() {
nfn.setNumReturnNeeder(iFav);
return nfn;
}
}
Generic needer-needable design
Here is my design of a generic needer-needable solution that implements the above fix. The hardest part was avoiding circular dependencies between ConfigNeedable and ConfigNeeder.
public interface Chainable {
Chainable chainID(Object o_id);
Object getChainID();
}
public interface ConfigNeedable<O,R extends ConfigNeeder> extends Chainable {
boolean isAvailableToNeeder();
ConfigNeedable<O,R> startConfigReturnNeedable(R c_n);
R getActiveNeeder();
boolean isNeededUsable();
R endCfg();
}
public interface ConfigNeeder {
void startConfig();
boolean isConfigActive();
<O> Class<O> getNeededType();
<O> void setNeeded(O o_fullyConfigured);
}
Here is the same (working) example that uses this design, but since it depends on implementations in my personal library (which is unreleased at the moment, because it's changing minute to minute as I'm working on it), it won't compile. Hopefully it will help someone to see.
import xbn.lang.chain.ChainableComposer;
import xbn.lang.chain.ConfigNeeder;
import xbn.lang.chain.SimpleConfigNeedable;
import xbn.lang.chain.SimpleConfigNeeder;
public class ConfigNeedableNeederXmpl {
public static final void main(String[] igno_red) {
UserSettings us = (new UserSettings()).
cfgFavInt().twentySeven().timesTwo().increment().endCfg().name("President Obama");
System.out.println("name=" + us.sName);
System.out.println("favorite number=" + us.iFav);
}
}
class UserSettings implements ConfigNeeder {
private SimpleConfigNeeder scn = new SimpleConfigNeeder(Integer.class);
public static final int iDEFAULT_FAV = 8;
public int iFav = -1;
public String sName = null;
public UserSettings name(String s_name) {
sName = s_name;
return this;
}
public FavNumConfigurator cfgFavInt() {
FavNumConfigurator fnc = new FavNumConfigurator();
fnc.startConfigReturnNeedable(this);
return fnc;
}
//ConfigNeeder: composition implementation...START
public <O> void setNeeded(O i_fullyConfigured) {
scn.setNeeded(i_fullyConfigured);
iFav = (Integer)scn.getElimNeeded();
}
public void startConfig() {
scn.startConfig();
}
public boolean isConfigActive() {
return scn.isConfigActive();
}
public <O> Class<O> getNeededType() {
return scn.getNeededType();
}
public void endConfig() {
iFav = (Integer)scn.getElimNeeded();
}
//ConfigNeeder: composition implementation...END
}
class FavNumConfigurator extends SimpleConfigNeedable<Integer,UserSettings> {
public FavNumConfigurator() {
super(33, true);
}
public FavNumConfigurator(Integer o_defaultNeeded, boolean b_defaultNeededUsable) {
super(o_defaultNeeded, b_defaultNeededUsable);
}
public FavNumConfigurator set(int i_i) {
try {
updateObject(i_i);
} catch(RuntimeException rtx) {
throw newRTXWChainID("set", rtx);
}
return this;
}
public FavNumConfigurator twentySeven() {
updateObject(27);
return this;
}
public FavNumConfigurator timesTwo() {
updateObject(getNeededInProcess() * 2);
return this;
}
public FavNumConfigurator increment() {
updateObject(getNeededInProcess() + 1);
return this;
}
}
What you're looking for is effectively the C++ Curiously recurring template pattern.
You can put all your "shared" self-returning bits in a base abstract class, then extend it.
For example:
public abstract class Base<T extends Base<T>>
{
protected abstract T self();
protected String name;
protected String address;
public T withtName(String name)
{
this.name = name;
return self();
}
public T withAddress(String address)
{
this.address = address;
return self();
}
}
class MyClass extends Base<MyClass>
{
private String someOtherThing;
public MyClass withSomeOtherThing(String thing)
{
this.someOtherThing = thing;
return self();
}
#Override
protected MyClass self()
{
return this;
}
}
Now you can do:
MyClass mc =
new MyClass()
.withAddress("111 elm")
.withtName("Bob")
.withSomeOtherThing("foo");