tags:

views:

103

answers:

3

I'm trying to figure out how to structure a program using Java's generics, and wondering if I am doing something fundamentally wrong or just missing a simple bug in my code.

Say I have a generic class:

public interface Handler<T>{ 
 public void process(T t); 
}

Another generic class takes Handler as a generic parameter (pseudo code):

public interface Processor<S extends Handler<T>>{ //<== Error: cannot find symbol 'T'
 public void addHandler(S u); 
 public void process(T t);
}

Abstract implementation providing boiler-plate implementations

public abstract class ProcessorImpl<.....> implements Processor<.....>{
  ...
}

Think of a processor as an object that dispatches requests to process data to any number of handlers. Specific instances can be variations of process pipelines, intercepting filters, event systems, etc.

I'd like to be able to use it like the following:

Handler<String> myHandler1 = new HandlerImpl<String>();
Handler<String> myHandler2 = new HandlerImpl<String>();
Handler<Integer> myHandler3 = new HandlerImpl<Integer>();

Processor<Handler<String>> proc = ProcessorImpl<Handler<String>>();
proc.addHandler(myHandler1);
proc.addhandler(myHandler2);
proc.addhandler(myHandler3);//this should be an error!

I can't get it to work. On paper it looks like it should be trivial, any ideas?

Thanks

A: 

It shouldn't work, as your T=String and handlers of integers are not allowed. At compile time, your class will have method process(String t) and not process(Integer t).

Yoni Roit
+4  A: 

So each type parameter is only defined within the class, thus T isn't defined or available in Processor class.

You probably want to have Processor be:

public interface Processor<T>{
  public void addHandler(Handler<? super T> u); 
  public void process(T t);
}

Here you are declaring a Processor that can only handle events/input of a particular type, e.g. String, Integer, etc. So the following statement will be valid:

Processor<String> proc = ...
proc.addHandler(new Handler<String>());   // valid
proc.addHandler(new Handler<Object>());   // valid, as Strings are Objects too
proc.addHandler(new Handler<Integer>());  // invalid, not a String handler
proc.process("good");     // valid
proc.process(1);          // invalid, not a String

If Processor is intended to handle types at runtime and makes a dynamic dispatch based on the appropriate runtime type, then you can declare proc (in the last example) as Processor<?>. Then all the statements are valid.

notnoop
Why not `public void addHandler(Handler<T> u);`
Harold L
@Harold, this works too, yet it's a bit restrictive. Having `addHandler` accept `Handler<T>` prevents `Processor<String>` from accepting `Handler<Object>`, and this should be valid. Imagine a `LoggerHandler<Object>` that simply prints the argument. You should be able to pass it to any processor I think.
notnoop
+1  A: 

These changes should work:

public interface Processor<T, S extends Handler<T>>

and

class ProcessorImpl<T, S extends Handler<T>>
    implements Processor<T, S>

and

Processor<String, Handler<String>> proc = new ProcessorImpl<String, Handler<String>>();
TofuBeer