I would like to write a class for generating xpaths. The class should have 2 methods: down(String string) and child(String string).
I would like to use the class like that:
XpathBuilder.child("div").down("button").child("a").child("span")
//That should return a String: div//button/a/span
Could anybody suggest me how can I do that?
You could take a look at builder pattern.
Here is one example (uses internal builder class):
public class XpathBuilder {
public Builder builder() {
return new XpathBuilder.Builder();
}
class Builder {
private final StringBuilder sb;
Builder() {
sb = new StringBuilder();
}
public Builder child(String name) {
sb.append("/").append(name);
return this;
}
public Builder down(String name) {
sb.append("//").append(name);
return this;
}
public String build() {
return sb.toString();
}
}
}
It can be called like this:
String path = new XpathBuilder().builder().child("div").down("button").child("a").child("span").build();
Here is another example (uses builder as well as singleton pattern):
public class XpathBuilder {
private final StringBuilder sb;
private static XpathBuilder instance;
private XpathBuilder() {
sb = new StringBuilder();
}
public static XpathBuilder newInstance() {
if (instance == null) {
instance = new XpathBuilder();
}
return instance;
}
public XpathBuilder child(String name) {
sb.append("/").append(name);
return this;
}
public XpathBuilder down(String name) {
sb.append("//").append(name);
return this;
}
public String build() {
return sb.toString();
}
}
It can be called like this:
String path = XpathBuilder.newInstance().child("div").down("button").child("a").child("span").build();
I think I found an easier solution overriding the toString method from the class Object. Doing that I need only one class:
public class XpathBuilder {
StringBuilder sb = new StringBuilder();
public XpathBuilder child(String string) {
sb.append("/"+string);
return this;
}
public XpathBuilder down(String string){
sb.append("//"+string);
return this;
}
#Override
public String toString(){
return sb.toString();
}
I'd like to know whether my implementation of QuestionBuilder violates mutability.
public class Question<T extends Serializable> implements Serializable {
private QuestionHolder<T> questionHolder;
private Question(QuestionHolder<T> questionHolder) {
this.questionHolder = questionHolder;
}
public String getId() {
return questionHolder.id;
}
public int getOrder() {
return questionHolder.order;
}
public QuestionType getType() {
return questionHolder.type;
}
public boolean isImmediate() {
return questionHolder.immediate;
}
public boolean isMandatory() {
return questionHolder.mandatory;
}
public List<T> getSelectedValues() {
return questionHolder.selectedValues;
}
public List<T> getPossibleValues() {
return questionHolder.possibleValues;
}
private static final class QuestionHolder<T extends Serializable> {
private String id;
private int order = 0;
private QuestionType type;
private boolean immediate;
private boolean mandatory;
private List<T> selectedValues;
private List<T> possibleValues;
}
public static final class QuestionBuilder<T extends Serializable> implements Builder<Question<T>> {
private QuestionHolder<T> questionHolder;
public QuestionBuilder(String id) {
questionHolder = new QuestionHolder<>();
questionHolder.id = id;
}
public QuestionBuilder withOrder(int order) {
questionHolder.order = order;
return this;
}
public QuestionBuilder withType(QuestionType questionType) {
questionHolder.type = questionType;
return this;
}
public QuestionBuilder withImmediate(boolean immediate) {
questionHolder.immediate = immediate;
return this;
}
public QuestionBuilder withMandatory(boolean mandatory) {
questionHolder.mandatory = mandatory;
return this;
}
public QuestionBuilder withSelectedValues(List<T> selectedValues) {
questionHolder.selectedValues = selectedValues;
return this;
}
public QuestionBuilder withPossibleValues(List<T> possibleValues) {
questionHolder.possibleValues = possibleValues;
return this;
}
public Question<T> build() {
Question<T> question = new Question<>(questionHolder);
questionHolder = null;
return question;
}
}
}
Or what should I adjust in order to resolve mutability issue. Any suggestions?
If you're worried about thread safety, then your code here is not necessarily thread safe.
It is possible that one thread calls build() and returns a Question pointing to a QuestionHolder. Even though build() sets the holder to null, another thread might not see that null, but instead see the old value of the field. If that other thread called any of your setters, it would potentially mutate the Holder that the Question class had already accessed.
In a single threaded application you would be fine.
As far as I can see, you are mutating the QuestionHolder with each builder call.
What I would do is:
1) Make all properties inside QuestionHolder private and don't create any setters at all.
2) Store each property inside the builder instance and create a new instance of QuestionHolder in the build method of the builder.
For example:
public Question<T> build() {
// DO ALL THE VALIDATIONS NEEDED
QuestionHolder holder = new QuestionHolder(id, order, type, inmediate, mandatory, selectedValues, possibleValues);
return new Question<>(questionHolder);
}
With these approach, you will be mutating the Builder, but that's ok for the Builder Pattern. You will obviously need to create a new Builder instance each time you want to create a Question. If you want to use the same Builder over and over again you will probably need to store some kind of structure inside it (a Map identified by Id, for example).
I'm implementing a Builder constructor as documented in Joshua Bloch's "Effective Java 2nd Edition. However, I'm running into a few complications when I try to extend the class and its builder. Essentially, the extended Builder in the extended child class has set field methods that return the parent Builder type, not the child builder type.
Of course, I can cast back to the ChildBuilder in the property build chain (as shown in my main method) but it is not seamless which defeats the purpose of the Builder, and it also forces me to segregate the parent setters and child setters.
I tried to use generics but it ended up becoming more verbose than the cast.
Is there a way I can consistently make the set methods on the builders return the builder type that was actually instantiated?
public class ParentObj {
public static void main(String[] args) {
ChildObj childObj = ((ChildObj.ChildBuilder) (new ChildObj.ChildBuilder())
.prop1(11)
.prop2(21)
.prop3(14))
.prop4(12)
.prop5(33)
.build();
}
private int prop1;
private int prop2;
private int prop3;
protected ParentObj(Builder builder) {
this.prop1 = builder.prop1;
this.prop2 = builder.prop2;
this.prop3 = builder.prop3;
}
public class Builder {
private int prop1;
private int prop2;
private int prop3;
public Builder prop1(int prop1) { this.prop1 = prop1; return this; }
public Builder prop2(int prop2) { this.prop2 = prop2; return this; }
public Builder prop3(int prop3) { this.prop3 = prop3; return this; }
public ParentObj build()
{
return new ParentObj(this);
}
}
}
private class ChildObj extends ParentObj {
private final int prop4;
private final int prop5;
private ChildObj(ChildBuilder childBuilder) {
super(childBuilder);
}
public class ChildBuilder extends Builder {
private int prop4;
private int prop5;
public ChildBuilder prop4(int prop4) { this.prop4 = prop4; return this; }
public ChildBuilder prop5(int prop5) { this.prop5 = prop5; return this; }
public ChildObj build() {
return new ChildObj(this);
}
}
}
Probably the best way would be to Override the parent builder methods.
class ChildBuilder {
public ChildBuilder prop1(int prop1){
return (ChildBuilder) super.prop1(prop1);
}
}
While this isn't exactly clean it will work for what you're trying to do.
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");
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.