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.
Related
While working with Java 8 Optionals I face following scenario very frequently. I have two Optional objects and then I want to call different methods based on the values (ifPresent) of those Optionals.
Here is an example:
void example(Optional<String> o1, Optional<String> o2) throws Exception {
if (o1.isPresent() && o2.isPresent()) {
handler1(o1.get(), o2.get());
} else if (o1.isPresent()) {
handler2(o1.get());
} else if (o2.isPresent()) {
handler3(o2.get());
} else {
throw new Exception();
}
}
However, this chain of if-else statements doesn't seem like a proper way of working with Optional (after all, they were added so that you can avoid writing these if-else checks everywhere in your code).
What is the proper way of doing this with Optional objects?
You said that you use such structure frequently, so I propose to introduce a Helper class:
final class BiOptionalHelper<F, S> {
private final Optional<F> first;
private final Optional<S> second;
public BiOptionalHelper(Optional<F> first, Optional<S> second){
this.first = first;
this.second = second;
}
public BiOptionalHelper<F, S> ifFirstPresent(Consumer<? super F> ifPresent){
if (!second.isPresent()) {
first.ifPresent(ifPresent);
}
return this;
}
public BiOptionalHelper<F, S> ifSecondPresent(Consumer<? super S> ifPresent){
if (!first.isPresent()) {
second.ifPresent(ifPresent);
}
return this;
}
public BiOptionalHelper<F, S> ifBothPresent(BiConsumer<? super F, ? super S> ifPresent){
if(first.isPresent() && second.isPresent()){
ifPresent.accept(first.get(), second.get());
}
return this;
}
public <T extends Throwable> void orElseThrow(Supplier<? extends T> exProvider) throws T{
if(!first.isPresent() && !second.isPresent()){
throw exProvider.get();
}
}
}
Which then may be used in a way like this:
new BiOptionalHelper<>(o1, o2)
.ifBothPresent(this::handler1)
.ifFirstPresent(this::handler2)
.ifSecondPresent(this::handler3)
.orElseThrow(Exception::new);
Though, this just moves your problem into a separate class.
Note: above code may be refactored to not use Optional and isPresent() checks at all. And just use null for first and second and replace isPresent() with null-checks.
As it is generally a bad design to store Optional in fields or accept them as parameters in the first place. As JB Nizet already pointed out in a comment to the question.
Another way it to move that logic into common helper method:
public static <F, S, T extends Throwable> void handle(Optional<F> first, Optional<S> second,
BiConsumer<F, S> bothPresent, Consumer<F> firstPresent,
Consumer<S> secondPresent, Supplier<T> provider) throws T{
if(first.isPresent() && second.isPresent()){
bothPresent.accept(first.get(), second.get());
} else if(first.isPresent()){
firstPresent.accept(first.get());
} else if(second.isPresent()){
secondPresent.accept(second.get());
} else{
throw provider.get();
}
}
Which then could be called like this:
handle(o1, o2, this::handler1, this::handler2, this::handler3, Exception::new);
But it's still kind of messy to be honest.
Disclaimer: My answer is based on Lino's answer - the first part of this answer (BiOptional<T, U>) is a modified version of Lino's BiOptionalHelper, while the second part (BiOptionalMapper<T, U, R>) is my idea for extending this nice pattern.
I like Lino's answer a lot. However, I feel that instead of calling it BiOptionalHelper, it deserves to be simply called BiOptional, provided that:
it gets Optional<T> first() and Optional<T> second() methods
it gets is(First/Second)Present, is(First/Second)OnlyPresent and are(Both/None)Present methods
if(First/Second)Present methods are renamed to if(First/Second)OnlyPresent
it gets ifNonePresent(Runnable action) method
orElseThrow method is renamed to ifNonePresentThrow
Finally (and this is the entirely original part of my answer), I realized this pattern could support not only "handling" (in BiOptional), but also "mapping" (in BiOptionalMapper obtained through BiOptional.mapper()), like that:
BiOptional<String, Integer> biOptional = BiOptional.from(o1, o2);
// handler version
biOptional
.ifBothPresent(this::handleBoth)
.ifFirstOnlyPresent(this::handleFirst)
.ifSecondOnlyPresent(this::handleSecond)
.ifNonePresent(this::performAction);
// mapper version
String result = biOptional.<String>mapper()
.onBothPresent(this::mapBoth)
.onFirstOnlyPresent(this::mapFirst)
.onSecondOnlyPresent(this::mapSecond)
.onNonePresent("default")
.result();
Optional<String> optionalResult = biOptional.<String>mapper()
.onBothPresent(this::mapBoth)
.onNonePresentThrow(IllegalStateException::new)
.optionalResult();
Note that one can either:
call all on*Present mapping methods, and then call R result() (which will throw if result were to be absent), or
call only some of them, and then call Optional<R> optionalResult()
Note also that:
in order to avoid confusion between "handling" and "mapping", the naming convention is as follows:
BiOptional: if*Present
BiOptionalMapper: on*Present
if any of the on*Present methods is called twice, BiOptionalMapper will throw if result were to be overwritten (unlike BiOptional, which can handle multiple if*Present calls)
result cannot be set to null by the mappers provided to on*Present or by calling onNonePresent(R) (Optional<...> should be used as result type R instead)
Here's the source code of the two classes:
final class BiOptional<T, U> {
#Nullable
private final T first;
#Nullable
private final U second;
public BiOptional(T first, U second) {
this.first = first;
this.second = second;
}
public static <T, U> BiOptional<T, U> from(Optional<T> first, Optional<U> second) {
return new BiOptional<>(first.orElse(null), second.orElse(null));
}
public Optional<T> first() {
return Optional.ofNullable(first);
}
public Optional<U> second() {
return Optional.ofNullable(second);
}
public boolean isFirstPresent() {
return first != null;
}
public boolean isSecondPresent() {
return second != null;
}
public boolean isFirstOnlyPresent() {
return isFirstPresent() && !isSecondPresent();
}
public boolean isSecondOnlyPresent() {
return !isFirstPresent() && isSecondPresent();
}
public boolean areBothPresent() {
return isFirstPresent() && isSecondPresent();
}
public boolean areNonePresent() {
return !isFirstPresent() && !isSecondPresent();
}
public BiOptional<T, U> ifFirstOnlyPresent(Consumer<? super T> ifFirstOnlyPresent) {
if (isFirstOnlyPresent()) {
ifFirstOnlyPresent.accept(first);
}
return this;
}
public BiOptional<T, U> ifSecondOnlyPresent(Consumer<? super U> ifSecondOnlyPresent) {
if (isSecondOnlyPresent()) {
ifSecondOnlyPresent.accept(second);
}
return this;
}
public BiOptional<T, U> ifBothPresent(BiConsumer<? super T, ? super U> ifBothPresent) {
if (areBothPresent()) {
ifBothPresent.accept(first, second);
}
return this;
}
public BiOptional<T, U> ifNonePresent(Runnable ifNonePresent) {
if (areNonePresent()) {
ifNonePresent.run();
}
return this;
}
public <X extends Throwable> void ifNonePresentThrow(Supplier<? extends X> throwableProvider) throws X {
if (areNonePresent()) {
throw throwableProvider.get();
}
}
public <R> BiOptionalMapper<T, U, R> mapper() {
return new BiOptionalMapper<>(this);
}
}
and:
final class BiOptionalMapper<T, U, R> {
private final BiOptional<T, U> biOptional;
private R result = null;
BiOptionalMapper(BiOptional<T, U> biOptional) {
this.biOptional = biOptional;
}
public BiOptionalMapper<T, U, R> onFirstOnlyPresent(Function<? super T, ? extends R> firstMapper) {
if (biOptional.isFirstOnlyPresent()) {
setResult(firstMapper.apply(biOptional.first().get()));
}
return this;
}
public BiOptionalMapper<T, U, R> onSecondOnlyPresent(Function<? super U, ? extends R> secondMapper) {
if (biOptional.isSecondOnlyPresent()) {
setResult(secondMapper.apply(biOptional.second().get()));
}
return this;
}
public BiOptionalMapper<T, U, R> onBothPresent(BiFunction<? super T, ? super U, ? extends R> bothMapper) {
if (biOptional.areBothPresent()) {
setResult(bothMapper.apply(biOptional.first().get(), biOptional.second().get()));
}
return this;
}
public BiOptionalMapper<T, U, R> onNonePresent(Supplier<? extends R> supplier) {
if (biOptional.areNonePresent()) {
setResult(supplier.get());
}
return this;
}
public BiOptionalMapper<T, U, R> onNonePresent(R other) {
if (biOptional.areNonePresent()) {
setResult(other);
}
return this;
}
public <X extends Throwable> BiOptionalMapper<T, U, R> onNonePresentThrow(Supplier<? extends X> throwableProvider) throws X {
biOptional.ifNonePresentThrow(throwableProvider);
return this;
}
public R result() {
if (result == null) {
throw new IllegalStateException("Result absent");
}
return result;
}
public Optional<R> optionalResult() {
return Optional.ofNullable(result);
}
private void setResult(R result) {
if (result == null) {
throw new IllegalArgumentException("Null obtained from a mapper");
}
if (this.result != null) {
throw new IllegalStateException("Result already present: " + this.result);
}
this.result = result;
}
}
It doesn’t really answer your question, but since Java 9 I would prefer something along these lines:
o1.ifPresentOrElse(s1 -> {
o2.ifPresentOrElse(s2 -> {
handler1(s1, s2);
}, () -> {
handler2(s1);
});
}, () -> {
o2.ifPresentOrElse(s2 -> {
handler3(s2);
}, () -> {
throw new IllegalArgumentException("Neither was present");
});
});
There’s a rule of thumb about Optional saying not to use isPresent and get. I do use them very occasionally; most often they are better avoided.
To avoid if statements or here if (Optional.isPresent()) you should have a common way to handle the Optional values but it is not the case as according their content you may invoke a function with the functional interface Consumer<String> or BiConsumer<String, String>.
As hint, you may factor the second part but it is not more readable or a better way :
if (o1.isPresent() && o2.isPresent()) {
handler1(o1.get(), o2.get());
} else {
Map<Optional<String>, Consumer<String>> map = new HashMap<>();
map.put(o1, this::handler2);
map.put(o2, this::handler3);
Optional<String> opt = Stream.of(o1, o2)
.filter(Optional::isPresent)
.findFirst()
.orElseThrow(Exception::new);
map.get(opt)
.accept(opt.get());
}
If you have much more Optionals to handle in this way such as this would probably make more sense but still it is a lot of code to write.
A more readable alternative could be to introduce a Rule class that stores the information required to trigger that if required :
public Rule(BiPredicate<Optional<String>, Optional<String>> ruleFunction, Runnable runnableIfApplied) {
this.ruleFunction = ruleFunction;
this.runnable = runnableIfApplied;
}
The BiPredicate<Optional<String>, Optional<String>> represents the matching function and the Runnable is the method to execute if the matching occurs.
You could move the rule execution logic in a Rule static method.
The idea is to make as clear as possible the rule specifications from the client side such as :
void example(Optional<String> o1, Optional<String> o2, Optional<String> o3) throws Exception {
Rule.executeFirstMatchOrFail(o1, o2,
new Rule((opt1, opt2) -> opt1.isPresent() && opt2.isPresent(), () -> handler1(o1.get(), o2.get())),
new Rule((opt1, opt2) -> opt1.isPresent(), () -> handler2(o1.get())),
new Rule((opt1, opt2) -> opt2.isPresent(), () -> handler3(o2.get())));
}
Rule could look like :
public class Rule {
static void executeFirstMatchOrFail(Optional<String> o1, Optional<String> o2, Rule... rules) throws Exception {
for (Rule rule : rules) {
if (rule.apply(o1, o2)) {
return;
}
}
throw new Exception();
}
private Runnable runnable;
private BiPredicate<Optional<String>, Optional<String>> ruleFunction;
public Rule(BiPredicate<Optional<String>, Optional<String>> ruleFunction, Runnable runnableIfApplied) {
this.ruleFunction = ruleFunction;
this.runnable = runnableIfApplied;
}
public boolean apply(Optional<String> o1, Optional<String> o2) {
if (ruleFunction.test(o1,o2)) {
runnable.run();
return true;
}
return false;
}
}
I now came several times across this problem and always kinda solved this with some casts and #SuppressWarnings annotations.
The relevant interfaces / abstract classes:
public abstract class Data { }
public interface DataOperations {
boolean isValid();
}
public interface DataOperationsFactory<T extends Data> {
Class<T> getDataClass();
DataOperations getOperations(T data);
}
Example Implementations:
public class DataImpl1 extends Data {
public String foo;
}
public class DataImpl1Operations implements DataOperations {
private DataImpl1 data;
public DataImpl1Operations(DataImpl1 data) {
this.data = data;
}
public boolean isValid() {
return data.foo != null;
}
}
public class DataImpl1OperationsFactory extends DataOperationsFactory<DataImpl1> {
public Class<DataImpl1> getDataClass() {
return DataImpl1.class;
}
DataOperations getOperations(DataImpl1 data) {
return new DataImpl1Operations(data);
}
}
Using this pattern, I can decide whether I need to create a new DataImpl1Operations everytime. Or maybe use a final static NO_OP implementation or what have you.
The Code:
Now I'd like to put all those factories inside a Map<Class<T>, DataOperationsFactory<T>> (constructor). And afterwards read from it (getOps method).
public class Test {
Map<Class<?>, DataOperationsFactory<?>> map;
public Test(List<DataOperationsFactory<?>> fs) {
for(DataOperationsFactory<?> f : fs) {
map.put(f.getDataClass(), f);
}
}
#SuppressWarnings("unchecked")
public <T extends Data> DataOperations getOps(T data) {
// --> Here I need to do an unchecked cast <--
DataOperationsFactory<? super T> f =
(DataOperationsFactory<? super T>) map.get(data.getClass());
return f.getOperations(data);
}
}
Is there any way doing this without unchecked casting?
You can delegate to a private method that captures the type, so it can be used to reliably cast to the correct Data subclass:
Map<Class<?>, DataOperationsFactory<?>> map;
// Unchanged
public Test(List<DataOperationsFactory<?>> fs) {
for(DataOperationsFactory<?> f : fs) {
map.put(f.getDataClass(), f);
}
}
public DataOperations getOps(Data data) {
DataOperationsFactory<?> f = map.get(data.getClass());
return getOperations(f, data);
}
private static <T extends Data> DataOperations getOperations(DataOperationsFactory<T> f,
Data data) {
return f.getOperations(f.getDataClass().cast(data));
}
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..
I have an third-party RPC-API that provides an interface similar to that of java.sql.ResultSet (for reading values) and java.sql.PreparedStatement (for writing values). Assume it looks something like this:
public interface RemoteDeviceProxy {
public void setBoolean(Boolean value);
public void setInteger(Integer value);
// ...
public Boolean getBoolean();
public Integer getInteger();
// ...
}
I want to write a wrapper for this API that uses generics to create instances of specific types:
public class <T> RemoteVariable {
private final RemoteDeviceProxy wrappedDevice;
public RemoteVariable(RemoteDeviceProxy wrappedDevice) {
this.wrappedDevice = wrappedDevice;
}
public T get() {
// should call wrappedDevice.getBoolean() if T is Boolean, etc.
// how to implement?
}
public void set(T newValue) {
// should call wrappedDevice.setBoolean(newValue) if T is Boolean, etc.
// implement using instanceof
}
}
How can I implement the getter in my generic wrapper? I have found this answer which explains a similar scenario in depth, but I am not able to transfer this to my problem. Specifically, when I write this:
public T get() {
Type[] actualTypeArguments = ((ParameterizedType) getClass())
.getActualTypeArguments();
}
I get a compiler error saying I cannot cast to ParameterizedType, and I do not understand why. Can anyone explain how to achieve this?
Here is one way:
public class <T> RemoteVariable {
private final RemoteDeviceProxy wrappedDevice;
private final Class<T> clazz;
public RemoteVariable(RemoteDeviceProxy wrappedDevice, Class<T> clazz) {
this.wrappedDevice = wrappedDevice;
this.clazz = clazz;
}
public T get() {
if(clazz == Boolean.class){return clazz.cast(wrappedDevice.getBoolean());}
else if(clazz == Integer.class){return clazz.cast(wrappedDevice.getInteger());}
// ...
}
// ...
}
I thought over this quite a while and finally came up with a different approach:
First I added a getter to you RemoteVariable class:
protected RemoteDeviceProxy getWrappedProxy() {
return wrappedProxy;
}
Second I created a builder interface that will be used by a factory later:
public interface RemoteVariableBuilder {
public <T> RemoteVariable<T> buildNewVariable(RemoteDeviceProxy wrappedProxy);
}
Then I created non generic sub classes for Boolean...
public class RemoteBooleanVariable extends RemoteVariable<Boolean> implements RemoteVariableBuilder {
public RemoteBooleanVariable(RemoteDeviceProxy wrappedProxy) {
super(wrappedProxy);
}
#SuppressWarnings("unchecked")
#Override
public <T> RemoteVariable<T> buildNewVariable(RemoteDeviceProxy wrappedProxy) {
return (RemoteVariable<T>) new RemoteBooleanVariable(wrappedProxy);
}
#Override
public Boolean get() {
return getWrappedProxy().getBoolean();
}
#Override
public void set(Boolean value) {
getWrappedProxy().setBoolean(value);
}
}
... and Integer ...
public class RemoteIntegerBuilder extends RemoteVariable<Integer> implements RemoteVariableBuilder {
public RemoteIntegerBuilder(RemoteDeviceProxy wrappedProxy) {
super(wrappedProxy);
}
#SuppressWarnings("unchecked")
#Override
public <T> RemoteVariable<T> buildNewVariable(RemoteDeviceProxy wrappedProxy) {
return (RemoteVariable<T>) new RemoteIntegerBuilder(wrappedProxy);
}
#Override
public Integer get() {
return getWrappedProxy().getInteger();
}
#Override
public void set(Integer value) {
getWrappedProxy().setInteger(value);
}
}
actually eclipse created most of the code once it knew base class and interface.
The final step was to create a factory
public class RemoteVariableFactory {
private static final Map<String, RemoteVariableBuilder> BUILDERS = new HashMap<>();
static {
BUILDERS.put(Boolean.class.getName(), new RemoteBooleanVariable(null));
BUILDERS.put(Integer.class.getName(), new RemoteIntegerBuilder(null));
// add more builders here
}
public static <T> RemoteVariable<T> getRemoteVariable(RemoteDeviceProxy wrappedProxy, Class<T> typeClass) {
RemoteVariableBuilder remoteVariableBuilder = BUILDERS.get(typeClass.getName());
if (remoteVariableBuilder == null) {
return null; // or throw an exception whichever is better in your case
}
return remoteVariableBuilder.buildNewVariable(wrappedProxy);
}
}
Now we are ready to create new RemoteVariables...
RemoteVariable<Boolean> var1 = RemoteVariableFactory.getRemoteVariable(new RemoteDevice(), Boolean.class);
RemoteVariable<Integer> var2 = RemoteVariableFactory.getRemoteVariable(new RemoteDevice(), Integer.class);
To conclude this let's do a quick comparison to the answer of Eng.Fouad:
Disadvantage:
you need to create a new class for every datatype you provide
Advantage:
you only have to add one line to the static block of the factory and not two new if blocks to the getter and setter in RemoteVariable
get and set do not have to work through the if-else-blocks every time
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.