null cannot be used as a default property value
GoogleCodeExporter opened this issue · 5 comments
What steps will reproduce the problem?
1. Create an Instantiator that instantiates a class with a non-primitive
constructor value, e.g.
public static final Instantiator<FruitShop> FruitShop =
new Instantiator<FruitShop>() {
@Override public FruitShop instantiate(PropertyLookup<FruitShop> lookup) {
return new FruitShop(
lookup.valueOf(owner, null));
}
};
public static final Property<FruitShop, String> owner = newProperty();
2. Instantiate the object
make(a(FruitShop));
What is the expected output? What do you see instead?
The expected output would be a FruitShop with owner set to "null". Instead, a
NullPointerException occurs as the overloaded valueOf() method is resolved to
the Donor one.
@Override
public <V> V valueOf(Property<? super T, V> property,
Donor<? extends V> defaultValue) {
if (values.containsKey(property)) {
return (V) values.get(property).value();
}
else {
return defaultValue.value(); // NPE as defaultValue is null
}
}
What version of the product are you using? On what operating system?
3.1.0 Ubuntu 10.10 OpenJDK 6
Please provide any additional information below.
I am currently solving this with a NullDonor:
public class NullDonor<T> implements Donor<T> {
@Override public T value() {
return null;
}
}
and call it a la:
return new FruitShop(lookup.valueOf(owner, new NullDonor<String>()));
though I think this could become a feature of the library by creating a
NullDonor whenever null is provided as a default value or simply returning null
when (defaultValue == null)
Original issue reported on code.google.com by holz.tho...@gmail.com
on 22 Jan 2012 at 6:09
I've done something like this.
MyMaker {
private static class No implements Donor {
@Override public Object value()
{
return null;
}
}
public static No NO = new No();
new Instantiator() {
final Authentication authenticationLookup = lookup.valueOf(authentication, authentication);
new MyObject((authenticationLookup == NO) ? null : authenticationLookup);
}
}
....
MyTest
a(SecurityContextRepository).but(with(NO, authentication)).make();
Original comment by dominicf...@gmail.com
on 25 Jul 2012 at 2:50
Came upon the same problem, trying to tell a default object A that it should
not have a reference to another object B initially. If you just use null in the
Instantiator (with no valueOf(property, donor) assignment) you won't be able to
set the property it later, as it is not contained in the values List. If you
use null as a donor - null pointer exception, when trying to get
defaultValue().value().
The only workaround doesn't feel right:
Maker<A> defaultAWithB = an(A); // this will have a reference to B
Maker<A> aWithNoB = defaultAWithB.but(with(b,(B)null);
This keeps me from having objects with default null values, forcing me to have
the default initialize all values and then selectively assign nulls.
However, If I now assign a B reference to the AWithNoB:
Maker<A> aWithNewB = aWithNoB.but(with(b,make(a(B)));
it will work and assign a B to a field that formerly referenced null. So I feel
like it shouldn't be too much trouble to implement the null donor and I'd
greatly appreciate it.
Thanks!
Original comment by pclau...@gmail.com
on 23 Feb 2012 at 1:36
Indeed it would be nice to have NullValue donor be part of library. On the
other side you could always do: new SameValueDonor(null)
Original comment by jmilkiew...@gmail.com
on 24 Apr 2012 at 9:09
On the one hand, I'm loathe to add a feature to make it easier to use null references! And the library has extension points that let you write what you need if you want to use nulls.
On the other hand, enough people have encountered the same issue.
So I think a NullDonor is the best approach. It'll be ugly enough to guide people away from using nulls but will let people use Make it Easy with legacy code that is infested with nullness.
Implemented a withNull(property) method on MakeItEasy. Now in master.