Safely call setter after getter chain eg foo.getX().getY().setZ(...); - java

How do I safely call setter after getter chain eg foo.getX().getY().setZ(...);? For example, suppose I have a nested POJO, and I want to be able to set a field of a nested object.
Foo foo = ...
foo.getX().getY().setZ(...);
I want the behavior to be such that if X and Y do not exist then they are created automatically; otherwise it reuses the existing object.
In other words, I want it to be behave equivalent to
Foo foo = ...
X x = foo.getX();
if (x == null) {
x = new X();
foo.setX(x);
}
Y y = x.getY();
if (y == null) {
y = newY();
x.setY(y);
}
y.setZ(...);
I'm wondering if there is a trick out there using reflection/functional that comes close to this.
I also have the following constraints:
I cannot modify any of the classes
The solution must know about only the public getters and setters, not the private instance variables
I want the getter to modify the internal state only when specifically requested; I don't want x = foo.getX() to modify foo.

Use functional programming. Create a method that accepts a getter, a setter and a supplier for the default value, that returns a getter encapsulating the logic you need:
public static <T, U> Function<T, U> getOrSetDefault(
Function<T, U> getter,
BiConsumer<T, U> setter,
Supplier<U> defaultValue) {
return t -> {
U u = getter.apply(t);
if (u == null) {
u = defaultValue.get();
setter.accept(t, u);
}
return u;
};
}
Then create these decorated getters:
Function<Foo, X> getX = getOrSetDefault(Foo::getX, Foo::setX, X::new);
Function<X, Y> getY = getOrSetDefault(X::getY, X::setY, Y::new);
Finally, chain them and apply the resulting function passing in your foo instance as an argument:
Foo foo = ...
getX.andThen(getY).apply(foo).setZ(...);
EDIT: This assumes that both X and Y have a no-args constructor that is referenced by X::new and Y::new, respectively. But you could use anything as the Supplier, i.e. an already created instance, or the return value of a method, etc.

TL;DR: Don't try to force functional Java where there clearly is no place for it.
The only way you can do this functionally in Java 8 without modifying any of the classes is using Optionals and their .orElse() method. It gets really long really quick, but it's the only way that actually makes sense using functional if you want to do it in one line only.
Optional.ofNullable(foo.getX()).orElseGet(() -> { foo.setX(new X()); return foo.getX(); }).setY(...);
If foo.setX() also returns the setted value it can be simplified as:
Optional.ofNullable(foo.getX()).orElseGet(() -> foo.setX(new X())).setY(...);
This is the only generic and functional way of doing it that I can think of. Stated the above, you can clearly see that this becomes huge and ugly even for just a chain of two getters, so I wouldn't advise it. I would definitely suggest you to use the classic multi-statement approach if you have to chain more than one call.
Another option, even thought not really that functional, is to use the tristate operator, still only if the setter returns the setted value:
(foo.getX() == null ? foo.setX(new X()) : foo.getX()).setY(...);
This has the probably unwanted side effect of calling the getter twice if the element is found, which you may not like, but could be possibly ignored if the getter caches the value somehow.

To start off I just want to mention that this probably isn't the best solution and I'm sure there are ways to optimize this. That said, I wanted to try my hand at CGLIB and ObjenesisHelper again.
Using CGLIB and ObjenesisHelper we can wrap the data object in a proxy which will intercept the get methods. Using this interceptor we can add the logic you described in your post. Lets start off by assume these are our data types (using lombok for brevity).
#Data class W { private X x; }
#Data class X { private Y y; }
#Data class Y { private Z z; }
#Data class Z { private int alpha; }
Our final solution can be used like the following:
public static void main(String[] args) {
final W w = ProxyUtil.withLazyDefaults(new W());
System.out.println(w.getX().getY().getZ().getAlpha());
}
Implementation
Currently, if we try to invoke new W().getX().getY().getZ().getAlpha() we will get a NullPointerException when invoking getY() because getX() returned null. Even if we manage to produce a default X value, we will still need a default Y value to not get a null pointer on getZ() and getAlpha() and so forth. The proxy we create needs to be generic and be able to wrap its sub components recursively.
Okay, so lets start. The first thing we need to do is create a MethodInterceptor. Whenever any call hits our proxy instance it will perform the logic of our MethodInterceptor. We need to first determine if the method called is a getter. If not we will ignore it. During this getter call, if the value is not present in our data we will create it and update the object. If the value contained by the getter is an original unwrapped class, we will replace it with a wraped version. Finally we will return the wrapped instance. Edit I updated this to not inject wrapped instances into the real Data objects. This will be less performant if the object is accessed mutliple times this way
public class ProxyUtil {
public static <T> T withLazyDefaults(final T data) {
final MethodInterceptor interceptor = (object, method, args, proxy) -> {
if (method.getName().startsWith("get")) {
final Class<?> returnType = method.getReturnType();
Object response = method.invoke(data, args);
if (response == null) {
response = returnType.newInstance();
data.getClass()
.getDeclaredMethod(
method.getName().replaceFirst("get", "set"),
returnType)
.invoke(data, response);
}
if (!returnType.isPrimitive()) {
response = withLazyDefaults(response);
}
return response;
}
return method.invoke(data, args);
};
...
The rest of this method involves using CGLIB and Objenisis Helper to construct the wrapper instance. CGLib will allow you to proxy both classes and interfaces and ObjenesisHelper will allow you to construct an instance of a class without having to invoke a constructor. See here for a CGLib example and here for a ObjenesisHelper example.
...
final Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(data.getClass());
final Set<Class<?>> interfaces = new LinkedHashSet<>();
if (data.getClass().isInterface()) {
interfaces.add(data.getClass());
}
interfaces.addAll(Arrays.asList(data.getClass().getInterfaces()));
enhancer.setInterfaces(interfaces.toArray(new Class[interfaces.size()]));
enhancer.setCallbackType(interceptor.getClass());
final Class<?> proxyClass = enhancer.createClass();
Enhancer.registerStaticCallbacks(proxyClass, new Callback[]{interceptor});
return (T) ObjenesisHelper.newInstance(proxyClass);
}
}
Caveats
This is not a thread safe operation.
Reflection will slow down your code.
Better error handling needs to added for the reflection calls.
If a class does not have a no-arg constructor this will not work.
Does not account for inheritance of data classes
This could be best effort by checking for a no-arg ctor/setter first.

I ended up using a combination of functional and reflection and tried to make the interface similar to Java's Optional. Here is an example of how I would write foo.getX().getY().setZ(val);
MutableGetter.of(foo).map(Foo::getX).map(x::getY).get().setZ(val);
This is the code (It's still WIP).
I used reflection to avoid having to pass the setter and constructor
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.function.BiConsumer;
import java.util.function.Function;
import java.util.function.Supplier;
import javassist.util.proxy.MethodHandler;
import javassist.util.proxy.ProxyFactory;
import lombok.Getter;
import lombok.NonNull;
public class MutableGetter<T>
{
private T object;
private MutableGetter(T object)
{
this.object = object;
}
public static <T> MutableGetter<T> of(#NonNull T object)
{
return new MutableGetter<>(object);
}
public <U> MutableGetter<U> map(Function<T, U> getter)
{
Method getterMethod = getGetterMethod(object.getClass(), getter);
BiConsumer<T, U> setter = getSetter(getterMethod);
Supplier<U> defaultValue = getDefaultValue(getterMethod);
U nextObject = getter.apply(object);
if (nextObject == null) {
nextObject = defaultValue.get();
setter.accept(object, nextObject);
}
return new MutableGetter<>(nextObject);
}
public T get()
{
return object;
}
private static <U> Supplier<U> getDefaultValue(Method getterMethod)
{
return () -> {
try {
Constructor<?> constructor = getterMethod.getReturnType().getConstructor();
constructor.setAccessible(true);
return (U) constructor.newInstance();
} catch (Exception e) {
throw new IllegalStateException(e);
}
};
}
private static <T, U> BiConsumer<T,U> getSetter(Method getterMethod)
{
return (obj, arg) -> {
Method setterMethod = getSetterFromGetter(getterMethod);
setterMethod.setAccessible(true);
try {
setterMethod.invoke(obj, arg);
} catch (Exception e) {
throw new IllegalStateException(e);
}
};
}
private static Method getSetterFromGetter(Method getter)
{
if (!getter.getName().startsWith("get")) {
throw new IllegalStateException("The getter method must start with 'get'");
}
String setterName = getter.getName().replaceFirst("get", "set");
Method[] methods = getter.getDeclaringClass().getMethods();
for (Method method: methods) {
if (method.getName().equals(setterName)) {
return method;
}
}
throw new IllegalStateException(String.format("Couldn't find setter in class %s with name %s", getter.getDeclaringClass(), setterName));
}
private static <T, U> Method getGetterMethod(Class<?> clazz, Function<T, U> getter)
{
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setSuperclass(clazz);
MethodRecorder methodRecorder = new MethodRecorder();
T proxy;
try {
proxy = (T) proxyFactory.create(new Class<?>[0], new Object[0], methodRecorder);
} catch (Exception e) {
throw new IllegalStateException(e);
}
getter.apply(proxy);
return methodRecorder.getLastInvokedMethod();
}
private static class MethodRecorder implements MethodHandler
{
#Getter
private Method lastInvokedMethod;
#Override
public Object invoke(Object self, Method thisMethod, Method proceed, Object[] args)
{
this.lastInvokedMethod = thisMethod;
return null; // the result is ignored
}
}
}
Let me know if you have any suggestions

Related

Using Generics to retrieve a list of classes of type Generic

I'm relatively new to generics in Java, so I apologize if this is something common that gets taught in schools (I'm pretty much self-taught). Let's say I have the interface and abstract class below
public interface IChallenge<T> {
boolean handle(T e);
Class<? extends T> getType();
}
public abstract class AbstractChallenge<T> implements IChallenge<T> {
protected Class<T> clazz;
#Override
public Class<? extends T> getType() {
return this.clazz;
}
}
For every class that extends AbstractChallenge, the handle method takes in the parameter that is specified for the generic. So if I had an event class that gets triggered when Event happens, I would have
public class EventChallenge extends AbstractChallenge<Event> {
public EventChallenge() {
super(Event.class);
}
#Override
public boolean handle(Event e) {}
}
My problem comes when I'm trying to pass a specific class to the handle method. Since the generic can be any class, and there can be multiple challenges with the same type, I have the challenges stored in a map with their type as the key.
private Map<Something, List<AbstractChallenge<Something>> challenges = new HashMap<>();
With the ultimate hope of achieving something along the lines of
List<AbstractChallenge<A>> specificChallenges = this.challenges.get(A.class);
specificChallenges.removeIf(challenge -> challenge.handle(A));
But I'm having a hard time figuring out what goes in the 'Something'. If I put the wildcard ? symbol, then IntelliJ says that handle must take in a parameter of the requirement: capture of ? when I pass it class A. The best I've gotten to is to not specify the type for AbstractChallenge but I'd like a better solution.
Any ideas? Thanks!
What you seek is something like that (I took the comment here):
private Map<Class<?>, List<IChallenge<?>> challenges = new HashMap<>();
A a = ...;
challenges.get(a.getClass())
.removeIf(challenger -> challenger.handle(a));
This is unsafe as it can be and you can't do much because you don't know the actual type of T (the compiler does not, so the much it can do is infer it, and in this case, the type would be Object):
The key can be any type, for example Integer.class
The value can be any type IChallenge<T> and if T is not Integer (or Number, Object, eg: any type in the hierarchy of T), it may fail if the implementation use the object it handles and do some cast.
When you add:
challenges.get(Integer.class).add((Number a) -> a.intValue() > 10); // #1
challenges.get(Integer.class).add((Integer a) -> a.intValue() > 10); // #2
challenges.get(Integer.class).add((Object a) -> a != null); // #3
challenges.get(Integer.class).add((String a) -> a.length() > 10); // #4
Here is an example:
Integer a = Integer.valueOf(5);
// #1 -> ok: a is a Number
challenges.get(a.getClass()).removeIf(c -> c.handle(a));
// #2 -> ok: a is an Integer
challenges.get(a.getClass()).removeIf(c -> c.handle(a));
// #3 -> ok: a is an Object
challenges.get(a.getClass()).removeIf(c -> c.handle(a));
// #4 ->ko: a is not a String
challenges.get(a.getClass()).removeIf(c -> c.handle(a));
If you wish to avoid that, but still be able to handle anything challenge, you should ensure that the class holding/building the challenges do it correctly:
public <T> void addChallenge(Class<T> type, IChallenge<T> challenge) {
challenges.computeIfAbsent(type, ignored -> new ArrayList<>()).add(challenge);
}
While you could use the getType() your defined in IChallenge, I wanted to show you how to enforce that the type (the key) and the IChallenge (the value) can be secured: normally, unless you gave write access to the map to other classes, this should be safe because the compiler validate the type at insertion.
Therefore, when you remove them, you should never have a ClassCastException due to the type parameter of IChallenge.
You could also try playing with ? super T and ? extends T but that's another challenge.
--
Regarding your comment:
I'm not entirely sure how to go about using the addChallenge method you specified. Right now, I have a list of Class> for every challenge created, and when a specific challenge should be loaded, the program instantiates using .newInstance(). Should I be doing it differently? I only need a certain amount of challenges loaded at once, not all – DeprecatedFrank
I am not telling to load all challenges at once, I am merely telling your to use OOP to ensure that no one, but your challenge holder (let call it ChallengeHolder) manage the map, and manage it so that you avoid generics pitfall:
class ChallengeHolder {
private final Map<Class<?>, List<IChallenge<?>>> challenges;
public ChallengeHolder() {
this.challenges = new HashMap<>();
}
public <T> void addChallenge(Class<T> type, IChallenge<T> challenge) {
challenges.computeIfAbsent(type, ignored -> new ArrayList<>()).add(challenge);
}
public boolean handle(Object a) {
List<IChallenge<T>> challengers = challenges.get(a);
if (challengers == null) return false;
return challengers.removeIf(c -> c.handle(a));
}
}
Since there are no public access to challenges beyond what the ChallengeHolder class provides, there should be no problem with using Object or Class<T>.
If you need to create IChallenge on demand, then you could perhaps an implementation like this:
public class LazyChallenge<T> implements IChallenge<T> {
private final Class<IChallenge<T>> impl;
private IChallenge<T> value;
public LazyChallenge(IChallenge<T> impl) {
this.impl = impl;
}
public boolean handle(T o) {
if (value == null) {
try {
value = impl.getConstructor().newInstance();
} catch (java.lang.ReflectiveOperationException e) { // ... a bunch of exception your IDE will fill in ...
throw new IllegalStateException(e);
}
}
return value.handle(o);
}
}
You would then add it to ChallengeHolder:
challengeHolder.addChallenge(String.class, new LazyChallenge<>(StringChallenge.class));
Or you could use lambda to avoid the reflection:
public class LazyChallenge<T> implements IChallenge<T> {
private final Class<IChallenge<T>> supplier;
private IChallenge<T> value;
public LazyChallenge(Supplier<IChallenge<T>> supplier) {
this.supplier = supplier;
}
public boolean handle(T o) {
if (value == null) {
value = supplier.get();
}
return value.handle(o);
}
}
And:
challengeHolder.addChallenge(String.class, new LazyChallenge<>(StringChallenge::new));
And after though, you may directly use Supplier in place of IChallenge in ChallengeHolder:
class ChallengeHolder {
private final Map<Class<?>, List<Supplier<IChallenge<?>>>> challenges;
public ChallengeHolder() {
this.challenges = new HashMap<>();
}
public <T> void addChallenge(Class<T> type, Supplier<IChallenge<T>> challenge) {
challenges.computeIfAbsent(type, ignored -> new ArrayList<>()).add(challenge);
}
public boolean handle(Object a) {
List<IChallenge<T>> challengers = challenges.get(a);
if (challengers == null) return false;
return challengers.removeIf(c -> c.get().handle(a));
}
}
StringChallenge existing = ... ;
// always reuse an existing
challengeHolder.addChallenge(String.class, () -> existing);
// bring a new challenge each time that ChallengeHolder::handle is called
challengeHolder.addChallenge(String.class, StringChallenge::new);
If I were to implements it, I would use the lambda way because you avoid reflection pitfalls (the try catch, the visibility problems especially given that Java 9++ introduced modules, ...).
The LazyChallenge defined above may help to avoid creating the StringChallenge more than one. In that case, it would be best to have it implements Supplier<T> instead of IChallenge<T>.
This whole digression does not change what I pointed out earlier: ensure that only ChallengeHolder read/write the map.

Trying to modify Java Vector's get() to make new T() if the element is null

I'm Trying to modify Java Vector to raise size if im accessing an element bigger than the vector's size. And to insert a new element if im accessing a not initialized element.
Eclipse throws cannot instantiate the type Obj.
public static class Vec<Obj> extends Vector<Obj> {
#Override
public Obj set(int a, Obj b) {
if (super.size()<=a) super.setSize(a+1);
return (Obj) super.set(a,b);
}
#Override
public Obj get(int a) {
if (super.size()<=a) super.setSize(a+1);
if (super.get(a)==null) super.insertElementAt( new Obj() , a);
return (Obj) super.get(a);
}
public Vec () {
super();
}
}
There is no guarantee that T has a no-args constructor. Also, people like to use interfaces, so there's a good chance T wont be concrete.
So, supply an abstract factory to the construction of your Vec. A suitable type is java.util.function.Supplier<T>.
private final Supplier<T> dflt;
public Vec(Supplier<T> dflt) {
super();
this.dflt = Objectes.requireNonNull(dflt);
}
...
if (super.get(a)==null) {
super.insertElementAt(dflt.get(), a);
}
Construct as:
Vec<Donkey> donkeys = new Vec<>(BigDonkey::new);
java.util.Vector methods should be synchronized, although such locking isn't really useful and ArrayList should generally be used instead. Even then, subclassing like this breaks LSP.

Singleton Factory - Implementation using Java 8

I want to implement a generic singleton factory pattern where I pass the Class of the required object as a parameter and the factory class should check in the map if there's already an object created for it, if its, return the object from map. If not, create a new instance, put it in the map and return the instance.
I can have a generic return type as Object, but I don't want to cast the returned object at every place I call the get instance method.
The below is the code: I get a compilation error at the line c.cast(instance);
We do not use spring/dependency injection, but trying implement common class to take care of creating all singleton objects.
public class SingletonFactory {
public static Map<String,Object> objectFactory = new HashMap<String, Object>();
public static <T extends Object> T getInstance(Class<?> c){
String key = c.toString();
Object instance= objectFactory.get(key);
if (instance == null) {
synchronized (c) {
try {
instance = c.newInstance();
objectFactory.put(key, instance);
} catch(IllegalAccessException | InstantiationException e) {
throw new RuntimeException("Exception while creating singleton instance for class : "+key+" - Exception Message : "+e);
}
}
}
return c.cast(instance);
}
}
First, I can point out that <T extends Object> can be replaced with just <T> because everything in Java, involving generics, must be an Object.
The second part that you're really close on is Class<?> c. That says that you can pass any class in and it will return whatever type T is. c.cast(instance) can be replaced with (T) instance if you think that looks better but, there's actually a difference which goes into more detail here: Java Class.cast() vs. cast operator .
The final code looks like this:
public class SingletonFactory {
public static Map<String,Object> objectFactory = new HashMap<String, Object>();
public static <T> T getInstance(Class<T> c){
synchronized (c) {
String key = c.toString();
Object instance= objectFactory.get(key);
if (instance == null) {
try {
instance = c.newInstance();
objectFactory.put(key, instance);
} catch(IllegalAccessException | InstantiationException e){
throw new RuntimeException("Exception while creating singleton instance for class : "+key+" - Exception Message : "+e);
}
}
return c.cast(instance);
// or
return (T) instance;
}
}
}
Also if you really wanted to, you could keep everything in your original code and cast instance to T at the end of the method and it should work. The only thing is your method calls would look like SingletonFactory.getInstance<Foo>(Foo.class) instead of SingletonFactory.getInstance(Foo.class). That is because of the Class<?> in your original code instead of Class<T>.
EDIT: I also changed the code to synchronize earlier thanks #Khan9797
Firstly, you need to synchronize much earlier, you should simply synchronize the method, otherwise, you can create extra instance in a race condition.
Secondly, you should define the generic of the method like this:
public static <T> T getInstance(Class<? extends T> c)
First of all, getInstance() is not thread-safe in terms of creating the new instance. There is a chance that you could create multiple instances of a given class when multiple threads running simultaneously and variable == null is true.
public class SingletonFactory {
private static Map<Class, Object> objectHolder = new HashMap<>();
public <T> T getInstance(Class<T> clazz) {
Object instance = objectHolder.get(clazz);
if(instance == null) {
synchronized (clazz) {
if(instance == null) {
try{
instance = clazz.newInstance();
objectHolder.put(clazz, instance);
} catch (Exception e) {
// do some logging and maybe exit the program. Since the it would affect how whole system works.
}
}
}
}
return clazz.cast(instance);
}
}
But the better approach would be using eager initialization instead of lazy initialization. The reason why we need to synchronize the critical section is that we are creating those instances when we need it. So it became a readers-writers problem. But if we only do reading process then we don't need to synchronize since we are not going to modify its value. If you know all the classes which are going to be created and need to be accessed we could just initialize them in the first place. So that we would get rid off the synchronized performance drawback
public class SingletonFactory {
private static Map<Class, Object> objectHolder = new HashMap<>();
private Map<Class, Object> initialize() {
Map<Class, Object> objectHolder = new HashMap<>();
// create some objects and put it into Map
return objectHolder;
}
public <T> T getInstance(Class<T> clazz) {
Object instance = objectHolder.get(clazz);
return clazz.cast(instance);
}
}

Java: Instantiate a generic type by returning a Supplier vs returning a new instance

I was reading how to instantiate a generic and after reading and applying this answer; I would like to know what would be the differences between expecting a Supplier<T> vs. expecting a new instance of T.
Example:
abstract class AbstractService<T extends AbstractEntity> {
protected Supplier<T> makeNewThing(); // supplier is expected
public T myMethod(){
T object = makeNewThing().get(); // local object by calling supplier
object.doStuff();
return object;
}
}
class CarService extends AbstractService<Car> {
public Supplier<Car> makeNewThing(){
return Car::new;
}
}
vs.
abstract class AbstractService<T extends SomeAbstractEntity> {
protected T makeNewThing(); // object is expected, newness is assumed
public T myMethod(){
T object = makeNewThing(); // local object by calling constructor
object.doStuff();
return object;
}
}
class CarService extends AbstractService<Car> {
public Car makeNewThing(){
return new Car();
}
}
The only thing I can think of is that expecting a supplier ensures that a new object will be created, but when expecting an object we can only assume that the implementing classes are calling the constructor and not re-using an existing instance.
I'd like to know of other objective differences and possible use cases, if any. Thanks in advance.
Using a Supplier postpones the creation of the instance.
This means that you might avoid a creation of an unnecessary instance.
For example, suppose you pass the output of makeNewThing() to some method.
public void makeNewThingSometimes (T newInstance)
{
if (someCondition) {
this.instance = newInstance;
}
}
public void makeNewThingSometimes (Supplier<T> supplier)
{
if (someCondition) {
this.instance = supplier.get();
}
}
Calling the first variant requires creating an instance of T even if you are not going to use it.
Calling the second variant only creates an instance of T when necessary.
Using a Consumer can save both storage (if the create instance requires a significant amount of memory) and time (if the execution of the constructor is expansive).
The only thing I can think of is that expecting a supplier ensures
that a new object will be created,
Not necessarily.
You implement the Supplier in this way :
return SomeEntityImplementation::new;
But you could have implemented it in this other way :
if (myCachedObject != null){
return (()-> myCachedObject);
}
return SomeEntityImplementation::new;
Both ways may be used to return a cached object or create a new one.
One of Supplier advantages is the case of Supplier creating an object : this one is actually created only as the Supplier.get() method is invoked.
Note that in your example, using Supplier doesn't bring any advantage as in both cases (with or without Supplier) the object creation is already performed in a lazy way : as the factory method is invoked.
To take advantage of it, you should have a method that provides a Supplier<T> as parameter as in the Eran and Dasblinkenlight examples.
Another Supplier advantage is its ability to implement factory that may return multiple of things.
Using Supplier allows to have a shorter and more readable code and besides that doesn't rely on Java Reflection.
Supposing that you want to create the object from an Enum value, you could so write :
public enum MyBaseClassFactory {
ENUM_A (A::new),
ENUM_B (B::new),
ENUM_C (C::new),
ENUM_D (D::new);
private Supplier<BaseClass> supplier;
MyBaseClassFactory (Supplier<BaseClass> supplier){
this.supplier = supplier;
}
public BaseClass createObject(){
return supplier.get();
}
}
You could so use it :
BaseClass base = MyBaseClassFactory.ENUM_A.createObject();
Without Supplier, you will have to use Reflection (that may fail at runtime) or write a verbose and unmaintainable code.
For example with Reflection :
public enum MyEnumFactoryClass {
ENUM_A(A.class), ENUM_B(B.class), ENUM_C(C.class), ENUM_D(D.class);
private Class<BaseClass> clazz;
MyEnumFactoryClass(Class<BaseClass> clazz) {
this.clazz = clazz;
}
public BaseClass createObject() {
return clazz.newInstance();
}
}
For example without reflection but with more verbose code :
public enum MyEnumFactoryClass {
ENUM_A {
#Override
public BaseClass createObject() {
return new A();
}
},
ENUM_B {
#Override
public BaseClass createObject() {
return new B();
}
},
ENUM_C {
#Override
public BaseClass createObject() {
return new C();
}
},
ENUM_D {
#Override
public BaseClass createObject() {
return new D();
}
};
public abstract BaseClass createObject();
}
You could of course take advantage in a close way of Supplier by using it with a Map<String, Supplier<BaseClass>>.
The first solution is more flexible, because an extra level of indirection in object creation lets users of your class library change the source of new items independently of ServiceImpl<SomeEntityImplementation> class.
You can make a new Supplier<T> instance without subclassing or recompiling ServiceImpl, because there is an extra level of indirection. ServiceImpl could be implemented as follows:
class ServiceImpl<SomeEntityImplementation> {
private final Supplier<SomeEntityImplementation> supplier;
public Supplier<T> makeNewThing(){
return supplier;
}
public ServiceImpl(Supplier<SomeEntityImplementation> s) {
supplier = s;
}
}
This makes it possible for users of ServiceImpl to provide their own Supplier<T>, which is not possible using the second approach, in which the source of new items is merged into the implementation of service itself.

How to put all String constants declared in a class and its inner classes in a single keySet

Perhaps the hidden question is which structure to use for keys that have a sort of hierarchy (therefore my attempt in using classes and inner classes, so that a test on specific subsets is possible). I'm looking for a structure where I can add a new key to the appropriate place and having automaticallly this key in the appropriate keySet. Here my actual try:
Now I work with keys as static final String and a corresponding keySet.
I often need to test if a certain key is contained in the set of keys (public static final String) declared in some other class.
Therefore I extend all classes with keys from a class Keys1 which has a method keySet() that gives the set of keys. That works fine.
public class Keys1
{
private TreeSet<String> m_keySet = new TreeSet<String>();
public Keys1()
{
initKeySet();
}
private void initKeySet()
{
Field[] felder = this.getClass().getFields();
for (Field f : felder)
{
if (Modifier.isFinal(f.getModifiers()))
{
try
{
if (f.get(f) instanceof String)
{
m_keySet.add(f.get(f).toString());
}
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
}
public TreeSet<String> keySet()
{
return m_keySet;
}
}
Now I try in vain to code a similar functionality in a class Keys2 where the keySet should also contain keys that are declared in inner classes of type Keys2.
public class Keys2 extends Keys1
{
#Override
protected void initKeySet()
{
super.initKeySet();
Class<?>[] innerClasses = this.getClass().getDeclaredClasses();
for (Class<?> innerClass : innerClasses )
{
if (innerClass.getClass().isInstance(Keys1.class))
{
Keys1 newKeys;
try
{
newKeys = (Keys1) innerClass.newInstance(); // Doesn't work
keySet().addAll(newKeys.keySet());
}
catch (InstantiationException e)
{
e.printStackTrace();
}
catch (IllegalAccessException e)
{
e.printStackTrace();
}
}
}
}
}
If I'm not mistaken at first you need to get declared constructor of inner class. Than invoke it with an instance of outer class as an argument.
Since you said, you are looking for public static final String fields only, you are doing unnecessary work. You are not filtering the fields to access static fields only, further, you are querying the field and checking the result’s type instead of checking the field’s type in the first place.
Also, you don’t need an object instance to retrieve a static field. If you write the code in a way that it operates on a Class, it can be used to process inner classes just as discovered, without instantiating them.
Since this procedure doesn’t need an object instance, there is also no reason to repeat that operation for every instance nor to store the result in an instance field. You only need to remember the result on a per-class basis and, thankfully, there is a class named ClassValue which provides this for free.
Putting it together, you can implement it as
public class Keys1 {
static final ClassValue<TreeSet<String>> KEYS = new ClassValue<TreeSet<String>>() {
#Override protected TreeSet<String> computeValue(Class<?> type) {
final int desired=Modifier.PUBLIC|Modifier.STATIC|Modifier.FINAL;
Field[] fields=type.getDeclaredFields();
TreeSet<String> set = new TreeSet<>();
for(Field f: fields) {
if((f.getModifiers()&desired)==desired && f.getType()==String.class) try {
set.add((String)f.get(null));
} catch(IllegalAccessException ex) {
throw new AssertionError(ex);
}
}
for(Class<?> inner: type.getDeclaredClasses()) {
set.addAll(get(inner));
}
type = type.getSuperclass();
if(type != null && type != Object.class) set.addAll(get(type));
return set;
}
};
public TreeSet<String> keySet() {
return KEYS.get(getClass());
}
}
The ClassValue takes care of the caching. When you call get, it checks whether there is already a computed value for the specified class, otherwise, it calls computeValue. The computeValue method in this solution utilizes this itself for processing the super class fields, so if you call it for different subclasses, they will share the result for the common base class instead of repeating the work.
The subclass doesn’t need to do anything here, the inherited keySet() method is sufficient, as it uses getClass(), which returns the actual class.
As shown in this ideone demo.
When you are running in a Java version before Java 7, you may use the following ersatz, which you should replace with the real thing as soon as you migrate to a newer Java version.
/**
* TODO: replace with {#code java.lang.ClassValue<T>} when migrating to >=7.
*/
abstract class ClassValue<T> {
private final ConcurrentHashMap<Class<?>,T> cache=new ConcurrentHashMap<Class<?>,T>();
protected abstract T computeValue(Class<?> type);
public final T get(Class<?> key) {
T previous = cache.get(key);
if(previous != null) return previous;
T computed = computeValue(key);
previous = cache.putIfAbsent(key, computed);
return previous!=null? previous: computed;
}
}
The only change needed by the solution itself, is replacing the diamond operator use
new TreeSet<>() with the explicitly typed new TreeSet<String>(). Then, it should work in Java 6.
Make your inner class static or as already briarheart mentioned create nested instance through the instance of outer class (see Instantiating inner class).
Consider using enums instead of String constants.
You can use something like:
public enum A {
A1,
A2;
public static enum B {
B1,
B2
}
public static enum C {
C1,
C2
}
static Set<Enum> allValues() {
Set<Enum> allValues = new HashSet<>();
allValues.addAll(Arrays.asList(A.values()));
allValues.addAll(Arrays.asList(A.B.values()));
allValues.addAll(Arrays.asList(A.C.values()));
return allValues;
}
}
This solution may be improved depending on your needs.
For example you can implement interface with the method
boolean contains(Enum e);
for each enum to check inclusion of arbitrary value in any enum
and its nested enums.

Categories