I have code that has a Map of (Message)Handlers. I'm trying to make the handlers generified (as seen by the interface Handler). Without generics the handlers all need to cast from Object to the respective class, which would be nice to avoid (but everything works). For each message class (Foo below) I have a handler class.
How can I keep a Map of any kind of Class to any kind of Handlers and get/call with "just" an Object? (the parameter to handleMessage(Object) can't be restricted)
See MWE below.
import java.util.*;
public class Logic
{
Map<Class<?>, Handler<?>> handlers = new HashMap<Class<?>, Handler<?>>();
public void run()
{
handlers.put(Foo.class, new FooHandler());
}
public void handleMessage(Object msg)
{
Handler<?> handler = handlers.get(msg.getClass());
if (handler != null) {
handler.execute(msg);
}
}
private interface Handler<T>
{
public void execute(T msg);
}
private class FooHandler implements Handler<Foo>
{
public void execute(Foo msg) {}
}
private class Foo {}
}
This code produces:
Logic.java:16: execute(capture#x of ?) in Logic.Handler cannot be applied > to (java.lang.Object)
handler.execute(msg);
How can this be repaired to work while still keeping the Handler interface generic?
You can't define the relationship between the key and the value in a field, but you can use accessor methods to enforce it, provided only these methods are used to access the map.
private final Map<Class, Handler> handlers = new HashMap<Class, Handler>();
public <T> void addHandler(Class<T> clazz, Handler<T> handler) {
handlers.put(clazz, handler);
}
#SuppressWarnings("unchecked")
public <T> Handler<T> getHandler(Class<T> clazz) {
return (Handler<T>) handlers.get(clazz);
}
#SuppressWarnings("unchecked")
public <T> Handler<T> getHandlerFor(T t) {
return getHandler((Class<T>) t.getClass());
}
public void run() {
addHandler(Foo.class, new FooHandler());
}
public <T> void handleMessage(T msg) {
Handler<T> handler = getHandlerFor(msg);
if (handler != null) {
handler.execute(msg);
}
}
The problem is that execute() takes a certain parameter type, that is more specific than Object.
However, in your handleMessage() method, the compiler doesn't know what type the parameter is. Suppose a case where FooHandler is registered for class Bar (which would be possible).
In that context handler.execute(msg); would actually result in FooHandler#execute(Foo) being called with a Bar argument, which would result in a ClassCastException (unless Bar extends Foo). Thus the compiler refuses to compile that code.
Another answer that wasn't here but it should be - remove all of the generics syntax (i.e. remove all the <?>). Then the parser will revert to JDK1.4 syntax and this will all work fine.
Related
I have an abstract class that looks like this:
abstract class Handler<T> {
Handler(Class<T> clazz) {
// ...
}
abstract void handle(T object);
}
I'm trying to extent it, where T is a type with a wildcard generic parameter (for the sake of the example, say List<?>). What I want to be able to do is something like:
class MyHandler extends Handler<List<?>> {
MyHandler() {
super(List.class);
// ^ Compiler error: The constructor Handler<List<?>>(Class<List>) is undefined
// super(List<?>.class); is also a compiler error
}
void handle(List<?> object) {
// ...
}
}
As far as I can tell the above is totally safe, so I'm not sure why the compiler doesn't allow it. My current solution involves the use of raw types, unsafe casting and suppression of the warnings and seems like it can't be solution the language intends me to use:
class MyHandler extends Handler<List> { // Warning: List is a raw type
MyHandler() {
super(List.class);
}
void handle(List objectRaw) { // Warning: List is a raw type
List<?> object = (List<?>) objectRaw;
// ...
}
}
This needs to be a singleton so I can't add generic parameters to MyHandler. How do I avoid all these bad practices (raw types and the cast)? Theres no reason this should be unsafe and I'm having a hard time believing there's no way to do this in Java.
You can solve the problem by casting the class object to type Class<List<?>> in the MyHandler constructor:
MyHandler() {
super((Class<List<?>>) (Object) List.class);
}
The problem
The problem is that there is no simple way in Java to express a class literal of type Class<List<?>>. List.class has type Class<List>.
I think there are situations where it would not be safe to the second type to the first one, but in your code there is probable no problem at all.
If, for example, your code uses clazz to check the runtime type of objects using isAssignableFrom you might get it trouble.
Type token
If you use some type-token implementation instead of a java.lang.Class, for example the one in Guava, you will be able to express a literal of the exact right type:
abstract class Handler<T> {
Handler(TypeToken<T> clazz) {
// ...
}
abstract void handle(T object);
}
class MyHandler extends Handler<List<?>> {
MyHandler() {
super(new TypeToken<List<?>>() {});
}
void handle(List<?> object) {
// ...
}
}
You don't need to pass a class object to the Handler constructor.
abstract class Handler<T> {
final Class<T> clazz;
#SuppressWarnings("unchecked")
Handler(T... dummy) {
if (dummy == null || dummy.length > 0)
throw new IllegalArgumentException("Do not specify the 'dummy' argument");
clazz = (Class<T>) dummy.getClass().componentType();
System.out.println("Handler clazz=" + clazz);
}
abstract void handle(T object);
}
class MyHandler extends Handler<List<Integer>> {
void handle(List<Integer> object) {
// ...
}
}
and
MyHandler mh = new MyHandler();
output
Handler clazz=interface java.util.List
You can also implement anonymous inner classes.
Handler<String> h = new Handler<>() {
#Override
void handle(String object) {
// TODO Auto-generated method stub
}
};
output
Handler clazz=class java.lang.String
I know there's many similar question but I had no luck finding a nice and clean solution if it's possible at all.
I'm implementing a generic interface with subclasses of an abstract type. Problem is that when I'm calling them I either must do type cast in a switch/case or cast type in every method inside interface implementations and I can't figure out a nice and clean approach... I'll better just write down a short example.
// An abstract type with 2 implementations...
public abstract class ObjTypeAbstract {}
public class ObjType extends ObjTypeAbstract {}
public class ScriptType extends ObjTypeAbstract {}
Now the processor for both types with an interface
interface ProcessorInterface<T extends ObjTypeAbstract> {
public void abcMethod(T obj);
}
public class ObjProcessor implements ProcessorInterface<ObjType> {
public void abcMethod(ObjType obj) {}
}
public class ScriptProcessor implements ProcessorInterface<ScriptType> {
public void abcMethod(ScriptType obj) {}
}
What I'm struggling with is a way of calling those processors based on ObjAbstractType. I have a single class that servers as middleware?? or how should I call it.:
Idea was to simple get the right processor via a single switch/case:
public class Processor {
private ProcessorInterface objProcessor = new ObjProcessor();
private ProcessorInterface scriptProcessor = new ScriptProcessor();
public methodAbc(ObjAbstractType obj) {
getProcessor(obj).abcMethod(obj);
}
private ProcessorInterface getProcessor(ObjAbstractType obj) {
if (obj instanceof ObjType) {
return objectProcessor;
} else if (obj instanceof ScriptType) {
return scriptProcessor;
}
return nullProcessor;
}
}
This is what I'd like to have, it also takes care of type casting of objAbstract to actual type for abcMethod, problem is that it results in RawType warning which won't break the code, but I'd like to get rid of it.
And thats where I'm stuck... because if I cast processors to specific type like this:
private ProcessorInterface<ObjType> objProcessor = new ObjProcessor();
private ProcessorInterface<ScriptType> scriptProcessor = new ScriptProcessor();
I won't be able to return an abstract one from getProcessor method so I would have to implement those interfaces with an ObjAbstractType with all it's method and have type casting in all methods of every processor like:
public class ScriptProcessor implements ProcessorInterface<ObjAbstractType> {
public void abcMethod(ObjAbstractType obj) {
ScriptType scr = (ScriptType) obj;
}
}
The other solution might be having a switch/case inside Processor middleware class and cast ObjAbstractType in it, but I'd have to write that switch inside abcMethod and all others or from getProcessor method returns both the Processor and casted ObjType... so I'd have to return some dto containing both. :/
Do you have any ideas / patterns that might help me to get rid of RawType call warning without extending the code with more switch/case or type casts?
Wish you a nice day and I'll be glad for any discussion, David.
You need a way to store the mapping between a ObjTypeAbstract class and a ProcessorInterface instance.
You could use a Map that associates ObjTypeAbstracts (as key) to ProcessorInterfaces (as value).
About the raw type issue, you could use ProcessorInterface<? extends ObjTypeAbstract> for the declared variable but you will still need to perform a unsafe cast to ProcessorInterface<ObjTypeAbstract> to be able to invoke ProcessorInterface.abcMethod() with as parameter a ObjTypeAbstract declared type.
This cast is unavoidable with your actual design.
It could give something like :
public class Processor {
private Map<Class<? extends ObjTypeAbstract>, ProcessorInterface<? extends ObjTypeAbstract >> map = new HashMap<>();
public Processor(){
map.put(ObjType.class, new ObjProcessor());
map.put(ScriptType.class, new ScriptProcessor());
}
public void methodAbc(ObjTypeAbstract obj) {
#SuppressWarnings("unchecked")
ProcessorInterface<ObjTypeAbstract> processorInterface = (ProcessorInterface<ObjTypeAbstract>) map.get(obj.getClass());
processorInterface.abcMethod(obj);
}
}
I don't think there is a substantially more elegant way to get around some form of instanceof logic. However, there should not be need for casting, if you add some types to getProcessor.
public <T extends ObjTypeAbstract> ProcessorInterface<T> getProcessor(Class<T> theClass) {
if (theClass.isAssignableFrom(ObjType.class)) {
return objProcessor;
} else if (theClass.isAssignableFrom(ScriptType.class)) {
return scriptProcessor;
}
return null;
}
This can then be called like this:
ProcessorInterface<ScriptType> scriptProcessor = new Processor().getProcessor(ScriptType.class);
ProcessorInterface<ObjType> objProcessor = new Processor().getProcessor(ObjType.class);
[Note: I have looked at all the possible duplicates - none are direct duplicates and none provide an answer to this specific question.]
I want to create a factory for event handlers, where the event handler's generic type parameter is the event type. The event type is only known at runtime.
In code, this is an illustration of what I want to achieve:
public interface Event {
}
public interface EventHandler<T extends Event> {
void handle(T event);
}
public class EventHandlerFactory {
public <T extends Event> EventHandler<T> getHandler(Class<T> eventType) {
return ... // implementation?
}
}
And then be able to consume the events in a type safe way, like so:
Event event = getEvent("some json representation");
factory.getHandler(event.getClass()).handle(event);
Any ideas how I can achieve this (or even something similar if this is not possible)?
Edit:
A concrete event handler might look like this:
public class JobCreatedEventHandler implements EventHandler<JobCreatedEvent>
{
#Override
public void handle(JobCreatedEvent event) {
...
}
}
A solution using the visitor pattern (as requested in the comments):
public interface Event {
...
default void accept(EventHandlerFactory factory) {
factory.defaultHandle(this);
}
}
public class EventA implements Event {
public void accept(EventHandlerFactory factory) {
factory.handleA(this);
}
}
public class EventB implements Event {
public void accept(EventHandlerFactory factory) {
factory.handleB(this);
}
}
...
public class EventHandlerFactory {
public void handleEvent(Event e) {
e.accept(this);
}
public void handleA(EventA e) {
this.handlerA.handle(e);
}
public void handleB(EventB e) {
this.handlerB.handle(e);
}
...
public void defaultHandle(Event e) {
LOG.error("Handler method not defined for" + e.getClass().getSimpleName());
}
}
Notes:
This solution works fine if the set of event types is fixed (and thus, completely inflexible with respect to subclassing)
You should think of organizing the classes/packages/interfaces in such a way as to reduce the visibility of handleA, handleB etc. to the actual client classes of EventFactory
The default Event.accept method is not strictly required; in your use case, I don't think there's a sensible implementation of EventHandlerFactory.defaultHandle
Of course, you could make the Event.handle methods to return the call to an appropriate getter method, e.g. return factory.getEventHandlerForB, if you require that type of indirection
This solution is entirely inflexible (pretty much because the visitor pattern is about the least flexible pattern ever invented), but it gets the job done. Note that no single casting/lookup by class is required.
There rests only
an unsafe map being made safe at runtime, and
the same for handling an event in principle generically.
The unavoidable matter is to hold a map not on Class<T> to EventHandler<T> but on the less type-safe Class<? extends Event> - one cannot map with pairwise type-safeness.
nterface Event {
}
interface EventHandler<T extends Event> {
void handle(T event);
default void handleGen(Event event) {
handle((T)event);
}
}
class A implements Event {
}
class B implements Event {
}
class AHandler implements EventHandler<A> {
#Override
public void handle(A event) {
System.out.println("A");
}
}
class BHandler implements EventHandler<B> {
#Override
public void handle(B event) {
System.out.println("B");
}
}
The factory class:
// No type equality required between key and value handler's parameter.
private Map<Class<? extends Event>, EventHandler<? extends Event>> map = new HashMap<>();
public <T extends Event> void registerHandler(Class<T> eventType,
EventHandler<T> handler) {
map.put(eventType, handler);
}
public void handleEvent(Event event) {
Class<? extends Event> eventType = event.getClass();
EventHandler<? extends Event> handler = map.get(eventType);
if (handler != null) {
handler.handleGen(eventType.cast(event));
}
}
Type-safe usage:
registerHandler(A.class, new AHandler());
registerHandler(B.class, new BHandler());
A a = new A();
handleEvent(a);
The solution is in the handleGen:
handler.handleGen(eventType.cast(event));
The abstract base class can hold a package private generic method handleGen
that delegates to the real handle method. Because of the register method this is safe at run-time.
At some point, some part of the logic needs to recognise that objects of class A are handled by objects of class B and objects of class B need to have a method (for the sake of argument) called handleEvent() which (probably) appears in a common interface called (say) EventHandler.
Whether you implement a type-to-instance map or just hack:
Class<?> c=Class.forName(event.getClass().getName()+"Handler");
Or a long chain of if`else` statements or something similar.
Some kind of mapping must take place.
I don't see a way around that.
I would go for something like this.
public class EventHandlerFactory {
private HashMap<Class, EventHandler> map = new HashMap<>();
#SuppressWarnings("unchecked")
public <T extends Event> EventHandler<T> getHandler(Class<? extends T> eventType) {
return (EventHandler<T>) map.get(eventType);
}
public <T extends Event> setHandler(Class<? extends T> eventType, EventHandler<T> handler) {
map.put(eventType, handler);
}
}
Type safety cannot be enforced by the map, so instead it is enforced by the setter method. An event type can only be mapped to a handler for that class or one of its superclasses.
Please consider the following code:
public abstract class Subject {
private Collection<Observer> observerCollection = new HashSet<>();
// ...
protected void notifyObservers() {
this.observerCollection.stream().filter(Objects::nonNull).forEach(o -> o.update(this));
}
}
public interface Observer<T extends Subject> {
void update(T subject);
}
I am getting the following compile-time warnings:
Observer is a raw type. References to generic type Observer should be parameterized
Type safety: The method update(Subject) belongs to the raw type Observer. References to generic type Observer should be parameterized
One comes at the call to update and for the life of me I can't figure out how to resolve it without using the warning suppressions. I've tried several ways to resolve the warning without luck. Any ideas on how this can be resolved?
Motivation
Consider the following client code:
public class IntegerContainer extends Subject {
private int integer;
public IntegerContainer(int integer) {
this.integer = integer;
}
public int getInteger() {
return this.integer;
} // ...
}
public class IntegerObserver implements Observer<IntegerContainer> {
private int cachedInteger;
#Override
public void update(IntegerContainer subject) {
this.cachedInteger = subject.getInteger(); // avoid cast here.
} // ...
}
The motivation for using generics in the Observer is to avoid a cast of the subject parameter so that the observer can retrieve the state of the subject.
This doesn't have anything to do with streams; it just straight up won't work.
An Observer<? extends Subject> is more or less unusable, because you don't know what subtype of Subject it's an observer of. For all you know, observerCollection only contains an Observer<SomeSubtypeOfSubjectThatNobodyEvenHeardOf>. (See the PECS principle; Observer is a consumer.)
I don't think there's any type-safe way to do this cleanly, frankly, because you can't say in Subject that the attached observers all accept this subtype of Subject, because there's no way to refer to "this subtype of Subject." The closest hack I can think of is
abstract class Subject<T extends Subject<T>> {
private Collection<Observer<? super T>> observers;
protected void notifyObservers() {
this.observerCollection.stream().filter(Objects::nonNull).forEach(o -> o.update((T) this)); // yes, this cast is unchecked
}
}
class SubSubject extends Subject<SubSubject> {
...
}
I'd focus on the value being passed between the Subject and Observer. I.e. both classes have one type parameter and the related methods make sure that the types are compatible:
public interface Observer<T> {
void update(T value); // no subject, but a value
}
public class Subject<T> {
private Collection<Observer<? super T>> observers = new HashSet<>();
protected void notifyObservers() {
this.observers.stream().filter(Objects::nonNull).forEach(o -> o.update(this.getValue()));
}
public void addObserver(Observer<T> observer) { // adding the right kind of observer
observers.add(observer);
}
abstract public T getValue(); // returning the value - this one is abstract
}
The key above is the abstract public T getValue(); method. Here is how you can write an IntegerContainer and and IntegerObserver :
public class IntegerContainer extends Subject<Integer> {
private int value;
public IntegerContainer(int value) {
this.value = value;
}
#Override
public Integer getValue() {
return value; // this is the parameter of the update() call
// you could even compute here something
// you can pass entire objects too, if required
}
}
public class IntegerObserver implements Observer<Integer> {
private int cachedInteger;
#Override
public void update(Integer value) {
this.cachedInteger = value; // no cast here
} // ...
}
You can put them together like this:
IntegerContainer container = new IntegerContainer(3);
IntegerObserver observer = new IntegerObserver();
container.addObserver(observer);
container.notifyObservers();
I have an ArrayList witch constains some instances of different classes ,I want to iterate over a specific type of classes(for example classes tha extend OnRender.class) in a for loop;
I have a working code but the code breaks the OO rules resulting in some warnings.
Can I make this happen or I will be always break OO by downcasting.
Looking back at what I wrote ,I see that I didnt explained it very good ,so check the code below to see what I mean
the code:
public class ListenerManager{
List<Object> listeners=new ArrayList<Object>();
int it;
Class clazz;
public <T extends Object> T begin(Class<T> clazz){
it=-1;
this.clazz=clazz;
return next();
}
public <T extends Object> T next(){
while((++it)<listeners.size()){
if (clazz.isInstance(listeners.get(it))){
return (T)listeners.get(it);
}
}
return null;
}
public void add(Object listener){
listeners.add(listener);
}
}
I use it like that:
ListenerManager lm=new ListenerManager();
lm.add(new OnRenderListener(){
........
});
for(OnRenderListener orl=lm.begin(OnRenderListener.class);orl!=null;orl=lm.next){
.......
}
the warning I get:
Class clazz; -> Class is a raw type. References to generic type Class should be parameterized
return (T)listeners.get(it); -> Type safety: Unchecked cast from Object to T
I don't want to suspend the warnings with just a Suspecnd annotation,I want to follow the OO rules.
If you want to identify particular classes or interfaces, use instanceof:
for (Object o : listeners) {
if (o instanceof X) {
X x = (X)o;
}
}
However this isn't very good at all. You really want to leverage the inheritance and polymorphism of the language. My first thought is that your list should container only Listeners or subtypes e.g.
listeners = new ArrayList<Listener>();
and then you don't require the cast. Everything you pull out from the list will be a Listener (or subtype) and typed as such:
for (Listener l : listeners) {
// listener type functionality here...
}
The Visitor pattern is an option here too. You could pass your visitor object into each listener, and each listener would decide what to do based on its type. The advantage is that as you add subtypes you have to add the appropriate methods - there's no danger of omitting a type from a sequence of class declarations.
Visitor v = new OnlyInterestedInOneTypeOfListener();
for (Listener l : listeners) {
l.useVisitor(v); // different subclasses will call different methods
// on the visitor. Some may be no-ops for different visitor
// implementations
}
(as an aside, I note that you want to discover entries that implement a particular method. This is called duck-typing, and Java doesn't support it. Other languages such as Scala do)
You can use Guava's Iterables.filter() method. It will iterate only on the subtype you want.
for (YourType filteredElement : Iterables.filter(listeners, YourType.class)) {
doSomething(filteredElement);
}
Your ListenerManager should either return a java Iterator, or a filtered Collection (or List). Don't rebuild a iterator concept on your own. Especially having a begin and next on your manager class will introduce unnecessary states there.
With Java 8, your ListenerManager can easily be writte as:
public class ListenerManager {
private final List<Object> listeners = new ArrayList<Object>();
public <T> Collection<T> listenersOf(Class<T> type) {
return listeners.stream()
.filter(type::isInstance)
.map(type::cast)
.collect(Collectors.toList());
}
public void add(Object listener) {
listeners.add(listener);
}
}
If you use a Java version prior to 8, use a good-old for-each instead:
public <T> Collection<T> listenersOf(Class<T> type) {
List<T> result = new ArrayList<T>();
for (Object l : listeners) {
if (type.isInstance(l)) result.add(type.cast(l));
}
return result;
}
This is only a rough (not compilable) way I would do it
public interface Listener{
public boolean canHandle(Event ev);
public void handle(Event ev);
}
public class OnRenderListener implements Listener {
public boolean canHandle(Event ev){
return ev instanceOf OnRenderEvent; // or look for the classname
}
public void handle(Event ev);
}
public class KeyPressListener implements Listener {
public boolean canHandle(Event ev){
return ev instanceOf KeyPressEvent; // or look for the classname
}
public void handle(Event ev){
keyPressed(((KeyPressEvent)ev).getKey());
}
keyPressed(int key){....}
}
public class Event{}
public class KeyPressEvent extends Event{
int key;
}
public class OnRenderEvent extends Event{
//other stuff
}
//Loop to fire an event
for(Listener lis : listeners){
if(lis.canHandle(currentEvent){
lis.handle(currentEvent);
}
}