Generic interfaces and covariance - java

the code below works fine:
public class ICopyableTest {
private interface ICopyable<T extends ICopyable<? extends T>> {
void copyFrom(T original);
}
private interface IVal<T> extends ICopyable<IVal<? extends T>> {
T getV();
}
private static class Val<T> implements IVal<T> {
private T v;
public T getV() {
return v;
}
public Val(final T v) {
this.v = v;
}
#Override public void copyFrom(final IVal<? extends T> original) {
v = original.getV();
}
}
private static class StrVal extends Val<String> {
public StrVal(final String v) {
super(v);
}
}
public static void main(String[] args) {
Val<Object> o1 = new Val<>(new Object());
Val<String> o2 = new Val<>("qwe");
StrVal o3 = new StrVal("zxc");
o1.copyFrom(o2); // that's the point
o1.copyFrom(o3);
o2.copyFrom(o3);
o3.copyFrom(o2);
Val<Object> toObj = (Val<Object>) (Val<?>) o2; // [1]
}
}
Basically i have ICopyable interface with provides copying functionality, IVal which adds storage of value above, and two example classes which implement Val. The point of <? extends T> is to provide covariant argument to the CopyFrom method, so you could do o1.copyFrom(o2) etc.
So it all works fine i guess.
Now let's say i want to have another parameterized over ICopyable or IVal class:
private static class Bla<T extends ICopyable<T>> {
final T value1;
final T value2;
public Bla(final T value1, final T value2) {
this.value1 = value1;
this.value2 = value2;
}
void letsCopy() {
value1.copyFrom(value2);
value2.copyFrom(value1);
}
}
Now why can't i instantiate it with any of the following?
new Bla<StrVal>(o3, o3);
new Bla<Val<Object>>(o1, o1);
new Bla<Val<String>>(o2, o2);
To be honest i'm a bit lost here myself and that's why i'm exploring it. There's a separate very important question of why working with generics is SO draining, when even after 5+ years working with java i can't figure out those things without half an hour meditation - am i just dumb?
I just want to have a parameterized class which will allow me to work with IVal/ICopyable values, note that it should be parameterized class, not individual method, so you can store the instances of those values in fields, for example.

I would have done that this way
public class Test {
interface Copyable<T> {
void copyFrom(Copyable<T> v);
T getV();
}
interface Val<T> extends Copyable<T> {
// Do not know if this is usefull
}
abstract class AbstractVal<T> implements Val<T> {
T value;
public AbstractVal(T val) {
this.value = val;
}
}
class StrVal extends AbstractVal<String> {
public StrVal(String o3) {
super(o3);
}
#Override
public void copyFrom(Copyable<String> v) {
this.value = v.getV();
}
#Override
public String getV() {
return this.value;
}
}
class Bla<T extends AbstractVal<S>, S> {
final T value1;
final T value2;
public Bla( T value1, final T value2) {
this.value1 = value1;
this.value2 = value2;
}
void letsCopy() {
value1.copyFrom(value2);
}
}
void test() {
StrVal o1 = new StrVal("qwe");
StrVal o2 = new StrVal("qwe2");
StrVal o3 = new StrVal("zxc");
Bla tester = new Bla<StrVal, String>(o1, o2);
tester.letsCopy();
System.out.println(tester.value1.getV());
}
public static void main(String[] args) {
Test t = new Test();
t.test();
}
}
Maybe a little complicated for what it's doing but I think it's the idea..

Related

Casting Predicate<> to a child type

I have a custom implementation of a Predicate that I want to use in some operations.
However, I am having a hard type making polymorphism work with it.
After some investigation I wrote the minimal code below to reproduce the problem (which is a better explanation of the problem than I could describe).
class Custom implements Predicate<Integer> {
int y;
public Custom(int y) {
this.y = y;
}
#Override
public boolean test(Integer i) {
return y+i>0;
}
}
public class Main{
public static void main(String[] args) {
Custom c1 = new Custom(5);
Custom c2 = new Custom(8);
Custom c = (Custom) c1.and(c2); // faulty line - unable to cast
}
}
I am unsure why the casting fails and how to make it work.
If you want to preserve state of your Custom objects and implement the Predicate interface I would suggest to overload the and, or and negate methods. When you combine two Custom objects with and, or or when you call negate you will get a Custom object as return value. When you combine a Custom object with any other implementation of Predicate<Integer the methods will still return Predicate<Integer:
class Custom implements Predicate<Integer> {
class And extends Custom {
Custom a;
Custom b;
public And(Custom a, Custom b) {
super((i) -> a.test(i) && b.test(i));
this.a = a;
this.b = b;
}
}
class Or extends Custom {
Custom a;
Custom b;
public Or(Custom a, Custom b) {
super((i) -> a.test(i) || b.test(i));
this.a = a;
this.b = b;
}
}
class Not extends Custom {
Custom custom;
public Not(Custom custom) {
super((i) -> !custom.test(i));
this.custom = custom;
}
}
private final Predicate<Integer> predicate;
public Custom(int y) {
this((i) -> y + i > 0);
}
private Custom(Predicate<Integer> predicate) {
this.predicate = predicate;
}
#Override
public boolean test(Integer i) {
return predicate.test(i);
}
public Custom.And and(Custom other) {
return new Custom.And(this, other);
}
public Custom.Or or(Custom other) {
return new Custom.Or(this, other);
}
public Custom.Not negate() {
return new Custom.Not(this);
}
}
I don't see a good reason of creating such a type of predicate as it complicates your predicates. However, there are at least 3 different ways that come to my mind "changing" the predicate state.
v0 - simply use java.util.function.Predicate<T>
final Predicate<String> p1 = "foo"::equals;
final Predicate<String> unit1 = p1.or("bar"::equals);
Assertions.assertTrue(unit1.test("foo"));
Assertions.assertTrue(unit1.test("bar"));
Assertions.assertFalse(unit1.test("baz"));
final Predicate<String> unit2 = p1.or("baz"::equals);
Assertions.assertTrue(unit2.test("foo"));
Assertions.assertTrue(unit2.test("baz"));
There is nothing wrong with this code and I would still go with it not implementing any custom classes.
v1 - "do cast" in a custom predicate implementation
This still requires all default methods from the Predicate<T> interface to be overridden in order not to break in a future Java release.
public abstract class V1MutablePredicate<T, P extends V1MutablePredicate<T, P>>
implements Predicate<T> {
#Nullable
private final Predicate<T> predicate;
protected V1MutablePredicate(#Nullable final Predicate<T> predicate) {
this.predicate = predicate;
}
protected abstract boolean doTest(T t);
#Nonnull
protected abstract P wrap(#Nonnull Predicate<T> predicate);
#Override
public final boolean test(final T t) {
return predicate == null ? doTest(t) : predicate.test(t);
}
#Nonnull
#Override
public final P and(#Nonnull final Predicate<? super T> other) {
return wrap(Predicate.super.and(other));
}
#Nonnull
#Override
public final P negate() {
return wrap(Predicate.super.negate());
}
#Nonnull
#Override
public final P or(#Nonnull final Predicate<? super T> other) {
return wrap(Predicate.super.or(other));
}
}
private static final class Custom
extends V1MutablePredicate<String, Custom> {
private String s;
Custom(final String s) {
this(null, s);
}
private Custom(#Nullable final Predicate<String> predicate, final String s) {
super(predicate);
this.s = s;
}
#Override
protected boolean doTest(final String t) {
return t.equals(s);
}
#Nonnull
#Override
protected Custom wrap(#Nonnull final Predicate<String> predicate) {
return new Custom(predicate, s);
}
}
#Test
public void test() {
final Custom p1 = new Custom("foo");
final Custom p2 = new Custom("bar");
final Custom unit = p1.or(p2);
Assertions.assertTrue(unit.test("foo"));
Assertions.assertTrue(unit.test("bar"));
Assertions.assertFalse(unit.test("baz"));
p2.s = "baz";
Assertions.assertTrue(unit.test("foo"));
Assertions.assertTrue(unit.test("baz"));
}
This one seems to be closest to what you want to accomplish.
v2 - inject the predicate state from outside
public final class V2MutablePredicate<T, S>
implements Predicate<T> {
private final Supplier<? extends S> stateSupplier;
private final BiPredicate<? super S, ? super T> predicate;
public V2MutablePredicate(final Supplier<? extends S> stateSupplier, final BiPredicate<? super S, ? super T> predicate) {
this.stateSupplier = stateSupplier;
this.predicate = predicate;
}
#Override
public boolean test(final T t) {
return predicate.test(stateSupplier.get(), t);
}
}
final AtomicReference<String> r1 = new AtomicReference<>("foo");
final V2MutablePredicate<String, String> p1 = new V2MutablePredicate<>(r1::get, String::equals);
final AtomicReference<String> r2 = new AtomicReference<>("bar");
final V2MutablePredicate<String, String> p2 = new V2MutablePredicate<>(r2::get, String::equals);
final Predicate<String> unit = p1.or(p2);
Assertions.assertTrue(unit.test("foo"));
Assertions.assertTrue(unit.test("bar"));
Assertions.assertFalse(unit.test("baz"));
r2.set("baz");
Assertions.assertTrue(unit.test("foo"));
Assertions.assertTrue(unit.test("baz"));
This implementation requires the state to be changed from outside managing multiple objects to be handled and it also requires "state" classes, but it does not require the default methods to be overridden and also requires the supplier to provide the value in every test method call.

Calling common methods without a common interface

I have some generated code (i.e. it cannot be changed) that looks something like this.
class Generated1 {
public String getA() {
return "1";
}
public void setB(String b) {
}
public void setC(String c) {
}
public void setD(String d) {
}
}
class Generated2 {
public String getA() {
return "2";
}
public void setB(String b) {
}
public void setC(String c) {
}
public void setD(String d) {
}
}
I am exploring these objects by reflection. None of them implement any common interface but there's many of them and I want to treat them as if they implement:
interface CommonInterface {
String getA();
void setB(String b);
void setC(String c);
void setD(String d);
}
It certainly should be possible. This is considered perfectly good code
class CommonInterface1 extends Generated1 implements CommonInterface {
// These are perfectly good classes.
}
class CommonInterface2 extends Generated2 implements CommonInterface {
// These are perfectly good classes.
}
I suppose what I'm looking for is something like:
private void doCommon(CommonInterface c) {
String a = c.getA();
c.setB(a);
c.setC(a);
c.setD(a);
}
private void test() {
// Simulate getting by reflection.
List<Object> objects = Arrays.asList(new Generated1(), new Generated2());
for (Object object : objects) {
// What is the simplest way to call `doCommon` with object here?
doCommon(object);
}
}
My question: How do I treat an object that doesn't implement an interface but actually has all the code to do so as if it does implement the interface.
I want to replace
private void doCommon(Generated1 c) {
String a = c.getA();
c.setB(a);
c.setC(a);
c.setD(a);
}
private void doCommon(Generated2 c) {
String a = c.getA();
c.setB(a);
c.setC(a);
c.setD(a);
}
...
with
private void doCommon(CommonInterface c) {
String a = c.getA();
c.setB(a);
c.setC(a);
c.setD(a);
}
I know I can use a Proxy like this but I'd really prefer to use something better.
private void test() {
// Simulate getting by reflection.
List<Object> objects = Arrays.asList(new Generated1(), new Generated2());
for (Object object : objects) {
// What is the simplest way to call `doCommon` with object here?
doCommon(adapt(object));
}
}
private CommonInterface adapt(Object o) {
return adapt(o, CommonInterface.class);
}
public static <T> T adapt(final Object adaptee,
final Class<T>... interfaceToImplement) {
return (T) Proxy.newProxyInstance(
adaptee.getClass().getClassLoader(),
interfaceToImplement,
// Call the equivalent method from the adaptee.
(proxy, method, args) -> adaptee.getClass()
.getMethod(method.getName(), method.getParameterTypes())
.invoke(adaptee, args));
}
If you're using reflection, you don't need the two CommonInterfaceX classes, you can use a proxy implementing CommonInterface:
public class Wrapper implements InvocationHandler {
private final Object delegate;
public static <T> T wrap(Object obj, Class<T> intf) {
ClassLoader cl = Thread.currentThread().getContextClassLoader();
Object proxy = Proxy.newProxyInstance(cl, new Class<?>[] {intf},
new Wrapper(obj));
return intf.cast(proxy);
}
private Wrapper(Object delegate) {
this.delegate = delegate;
}
#Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Method dmethod = delegate.getClass().getMethod(
method.getName(), method.getParameterTypes());
return dmethod.invoke(delegate, args);
}
}
You can use this class as follows:
List<Object> objects = Arrays.asList(new Generated1(), new Generated2());
for (Object object : objects) {
CommonInterface proxy = Wrapper.wrap(object, CommonInterface.class);
doCommon(proxy);
}
UPDATE: note that the same Wrapper class works with any interface.
There's no way to achieve a static type relationship between Generated1 and Generated2.
Even if you created CommonInterface1 and CommonInterface2, you still wouldn't be able to statically use a Generated1 object as a CommonInterface1 because new Generated1() is not a CommonInterface1 (and will never become one)
By far the simplest solution is to change your code generation to add the CommonInterface to Generated1 and Generated2.
If that's absolutely impossible, the only other way to avoid this code duplication is to go for reflection.
You can do it manuallly by reflection.
public class Generated {
public String getA() {
return "A";
}
public String sayHello(String name) {
return "hello " + name;
}
}
public class Helper {
private static final String METHOD_NAME = "getA";
private static final String METHOD_WITH_PARAM_NAME = "sayHello";
public static void main(String[] args) throws Exception {
Generated generated = new Generated();
accessMethod(generated);
accessMethodWithParameter(generated);
}
private static void accessMethod(Generated g) throws Exception {
Method[] methods = g.getClass().getDeclaredMethods();
for(Method method : methods) {
if(isCommonMethod(method)) {
String result = (String) method.invoke(g);
System.out.println(METHOD_NAME + "() = " + result);
}
}
}
private static boolean isCommonMethod(Method m) {
return m.getName().equals(METHOD_NAME) && m.getReturnType().equals(String.class);
}
private static void accessMethodWithParameter(Generated g) throws Exception {
Method[] methods = g.getClass().getDeclaredMethods();
for(Method method : methods) {
if(isCommonMethodWithParameter(method)) {
String result = (String) method.invoke(g, "Max");
System.out.println(METHOD_WITH_PARAM_NAME + "(\"Max\") = " + result);
}
}
}
private static boolean isCommonMethodWithParameter(Method m) {
return m.getName().equals(METHOD_WITH_PARAM_NAME) &&
m.getReturnType().equals(String.class) &&
m.getParameterTypes().length == 1 &&
m.getParameterTypes()[0].equals(String.class);
}
}
Output is
getA() = A
sayHello("Max") = hello Max
If you want to replace as your comment. I think you can do it easily
First, you create interface CommonInterface
interface CommonInterface {
String getA();
void setB(String b);
void setC(String c);
void setD(String d);
}
After that, you create 2 class Generated1 and Generated2 inherited CommonInterface
class Generated1 implements CommonInterface {
#overide
public String getA() {
return "1";
}
#overide
public void setB(String b) {
}
#overide
public void setC(String c) {
}
#overide
public void setD(String d) {
}
}
class Generated2 implements CommonInterface {
#overide
public String getA() {
return "2";
}
#overide
public void setB(String b) {
}
#overide
public void setC(String c) {
}
#overide
public void setD(String d) {
}
}

Using a predicate for a query on a field

I'm messing around with lambdas and I'm trying to create a generic way to form a predicate for a class on a field. Here's some code to illustrate:
public class A {
private String b;
private String c;
public A(String b, String c) {
this.b = b;
this.c = c;
}
public String getB() {
return b;
}
public String getC() {
return c;
}
}
public class Main {
public static void main(String[] args) {
List<A> list = Arrays.asList(new A("aa","bb"),new A("aaC","bb"));
Test test = new Test();
test.setList(list);
test.createPred("aa");
}
}
public class Test {
private List<A> list;
public void setList(List<A> list) {
this.list = list;
}
public Predicate<A> createPred(String query) {
return new Predicate<A>() {
#Override
public boolean test(A t) {
return t.getB().equals(query);
}
};
}
public List<A> search(Predicate<A> a) {
return list.stream().filter(a).collect(Collectors.toList());
}
}
How can I write createPred so it can take a field? I want the method to be "field-generic" I suppose. I'm guessing using java reflection here is not a good idea.
You can make your method take a Function and a T as the query field.
public static void main(String[] args) {
List<A> list = Arrays.asList(new A("aa", "bb"), new A("aaC", "bb"));
Test test = new Test();
test.setList(list);
test.createPred("aa", A::getB);
}
public static class Test {
private List<A> list;
public void setList(List<A> list) {
this.list = list;
}
public <T> Predicate<A> createPred(T query, Function<A, T> f) {
return new Predicate<A>() {
#Override
public boolean test(A x) {
return f.apply(x).equals(query);
}
};
}
public List<A> search(Predicate<A> a) {
return list.stream().filter(a).collect(Collectors.toList());
}
}

How to refactor a class with multiple Lists + getters and setters for each list

I have the following class:
public class RefactorMe {
private static List<Event<Apple>> mAppleEventList = new ArrayList<Event<Apple>>();
private static List<Event<Banana>> mBananaEventList = new ArrayList<Event<Banana>>();
private static List<Event<Orange>> mOrangeEventList = new ArrayList<Event<Orange>>();
public static List<Event<Apple>> getAppleList() {
return mAppleEventList;
}
public static List<Event<Banana>> getBananaEventList() {
return mBananaEventList;
}
public static List<Event<Orange> getOrangeList() {
return mOrangeEventList;
}
public static void addAppleEvent(Event<Apple> pEvent) {
mAppleEventList.add(pEvent);
}
public static void addBananaEvent(Event<Banana> pEvent) {
mBananaEventList.add(pEvent);
}
public static void addOrangeEvent(Event<Orange> pEvent) {
mOrangeEventList.add(pEvent);
}
}
I tried refactoring it using the Visitor pattern but could not get it to work because of the generics.. Is there a better way to do this?
Following on #user902383 by using the Map here is a solution for you in Java 7:
public class RefactorMe {
class Event<K> {
public K getNewObject() {
return null;
}
}
private static Map<Class<?>, List<Event<?>>> eventLists = new HashMap<>();
public static <E> List<Event<E>> getEventList(Class<E> clazz) {
return (List) eventLists.get(clazz);
}
public static <E extends Event<E>> void addEvent(Event<E> pEvent) {
Class<E> key = (Class<E>) pEvent.getNewObject().getClass();
List<Event<?>> events = eventLists.get(key);
if (events == null) {
events = new ArrayList<>();
eventLists.put(key, events);
}
events.add(pEvent);
}
}

Subclassing a Java Builder class

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.

Categories

Resources