Let's say I have simple class
public class MyObject {
}
And the handler interface for processing the child classes of MyObject
public interface MyObjectHandler<V extends MyObject>{
List<V> handle(List<V> objects);
}
Suppose, I have BigObjects and SmallObjects (both of them extends MyObject) and I want to have separate handlers for them. So, I create two intefaces of MyObjectHandler with specific generics.
class BigObject extends MyObject {}
class SmallObject extends MyObject {}
// Handlers interfaces
interface BigObjectHandler extends MyObjectHandler<BigObject>{}
interface SmallObjectHandler extends MyObjectHandler<SmallObject>{}
// Concrete handlers
class BigHandler1 implements BigObjectHandler {....}
class BigHandler2 implements BigObjectHandler {....}
class SmallHandler1 implements SmallObjectHandler {....}
class SmallHandler2 implements SmallObjectHandler {....}
Now let's imagine that we have created AbstractHandlerChain<...>
abstract class. So, we can create BigHandlerChain class and inject our BigHandlers (and the same thing with SmallHandlerChain).
class BigHandlerChain extends AbstractHandlerChain<BigObjectHandler> {
// Inject only childs of BigObjectHandler. E.g. via spring @Autowired
public BigHandlerChain(List<BigObjectHandler> handlers) {
this.handlers = handlers;
}
}
The question: is it possible to create perfect AbstractHandlerChain for this case?
Possible solution 1
public abstract class HandlerChain<T extends MyObjectHandler> {
private List<T> handlers;
public HandlerChain(List<T> handlers) {
this.handlers = handlers;
}
public <V extends MyObject> List<V> doChain(List<V> objects) {
for (T handler : handlers) {
objects = handler.handle(objects);
}
return objects;
}
}
This one works, but in handler.handle(objects)
I get Unchecked call to 'handle(List<V>)' as a member of raw type 'MyObjectHandler'
, so I should add @SuppressWarnings("unchecked")
that is not very good.
Possible solution 2
public abstract class HandlerChain<T extends MyObjectHandler<? extends MyObject>> {
...
public <V extends MyObject> List<V> doChain(List<V> objects) {
for (T handler : handlers) {
objects = handler.handle(objects);
}
return objects;
}
}
Doesn't work. In handler.handle(objects)
I get handle (java.util.List<capture<? extends MyObject>>) cannot be applied to (java.util.List<V>)
. Why I can't pass objects to handlers in this case? Wildcard extends MyObject and V extends MyObject. Isn't it enought?
Possible solution 3
public abstract class HandlerChain<T extends MyObjectHandler<V>, V extends MyObject> {
...
public List<V> doChain(List<V> objects) {
for (T handler : handlers) {
objects = handler.handle(objects);
}
return objects;
}
}
This one works, but in this case I should define BigHandlerChain as class BigHandlerChain extends AbstractHandlerChain<BigObjectHandler, BigObject>
. But BigObjectHandler
already contains information about classes, that can be handled by it, so it's information duplication.
Possible solution 4
public abstract class HandlerChain<T extends MyObjectHandler<V extends MyObject>> {
...
public List<V> doChain(List<V> objects) {
for (T handler : handlers) {
objects = handler.handle(objects);
}
return objects;
}
}
Here is a solution, that I expect from java, but it doesn't work! I can't declare class like this ...class HandlerChain<T extends MyObjectHandler<V extends MyObject>
. Why I can use wildcards after MyObjectHandler, but can't use this construction?