Class<SomeObject<?>> is NOT a superclass of Class<SomeObject<SpecificObject>>? - java

EDIT 1: According to this, despite SomeObject<?> being indeed a superclass of SomeObject<Foo>, Class<SomeObject<?>> is NOT a superclass of Class<SomeObject<Foo>>. The question on how to tackle this specific problem still persists. (adding a method to the Message<T> class that returns Class<Message<T>>, perhaps?)
Original question:
So basically I have a generic Message<T> class that implements a well known design pattern called Command pattern (with a twist: instead of building an object with a reference, the reference is passed as argument of the execute(T objectToCallMethodsOn)) and it looks something like this:
public abstract class Message<T> {
void execute(T obj); //e.g. DoSomethingOnFooMessage implements Message<Foo> to do something on a Foo object
}
so that I can do something like:
public DoSomethingOnFooMessage implements Message<Foo> {
#Override
void execute(Foo obj) {
obj.doSomething(); //doSomething is a method of the Foo class
}
}
Now, I also tried to make a MessageProcessor class with an internal map that maps (E is a type parameter) Class<Message<E>> to a object E executableObject (like Foo in the previous example) and with two methods: a handleMessage(Message<?> msg) that should do a dynamic instanceof of the Message (hence the need for the Class<> objects that let you do a dynamic instanceof and then a dynamic cast) and look for the right executableObject in the map to call the message's execute(E obj) on the right object (if it exists, otherwise the message is discarded), and a addProcessor() to add entries of e.g. Class<Message<Foo>>, Foo to the map:
public class MessageProcessor {
private final Map<Class<Message<?>>, Object> map;
public MessageProcessor() {
map = new HashMap<>();
}
public <E> void addProcessor(Class<Message<E>> messageClass, E executable) {
map.put(messageClass, executable);
}
...
}
So far that's what I wrote but the IDE complains that Class<Message<E>> was given but Class<Message<?>> was needed in addProcessor() and I don't know why; afaik, SomeClass<?> should be a superclass of any SomeClass<SpecificClass>, why isn't it the same for Class<SomeObject<?>> and Class<SomeObject<SpecificObject>>?
Sorry for the verbose question, other than asking a thing about superclassing of generics, I am also asking you guys for (perhaps) a different, more elegant way to do what I'm trying to do, which is find the runtime class of the message so that I can call its execute() with the object that I registered with the addProcessor() as its input.
Also, I reckon this could be easily solvable with raw types (ew)

Related

How can I use generics to provide a "universal getter method"?

This question is more theoretical (what I want to do is more complicated but this is the part I'm stuck on), so apologies for the contrived example which may not make much sense.
Say I have some class that has methods that return its value in different forms:
public class MyObject {
public String getAsString() {...}
public int getAsInt() {...}
// and so on
}
I'm trying to create a single method to allow me to specify which MyObject method to call via its parameters. Something like:
public <T> T getValue(MyObject obj, Class<T> c) {
if (c == String.class) {
return obj.getAsString();
} else if (c == Integer.class) {
return obj.getAsInt();
} // and so on
}
So then I would like to call this method like this, assuming obj is a MyObject:
String s = getValue(obj, String.class);
int i = getValue(obj, Integer.class);
// and so on
I'm getting the compile error "Type mismatch: cannot convert from String to T" (and likewise for Integer) in the getValue method. Clearly I'm just not understanding generics fully, but I thought this was the general idea behind generics - here I'm specifying (or trying to specify, at least) the real type of T via the parameter c. What am I doing wrong?
If you want to to create a single method with really safe casts - then I would suggest to setup a mapping between the expected type and its respective getter.
Given the MyObject class definition as:
public class MyObject {
public int getIntValue() {
return 42;
}
public String getStringValue() {
return "Answer";
}
}
So that the "accessor" class could look as follows (it can be generalized further if needed):
public class MyObjectAccessor {
private final Map<Class<?>, Function<MyObject, ?>> registry = new HashMap<>();
public Accessor() {
registerGetter(Integer.class, MyObject::getIntValue);
registerGetter(String.class, MyObject::getStringValue);
}
private <T> void registerGetter(Class<T> type, Function<MyObject, T> getter) {
registry.put(type, getter);
}
#SuppressWarnings("unchecked")
public <T> Optional<T> getValue(MyObject obj, Class<T> type) {
return (Optional<T>) ofNullable(registry.get(type)).map(getter -> getter.apply(obj));
}
}
This would allow you to make the behavior much more predictable with a control over the unexpected/missing mapping.
(Here it returns an Optional back, but you can also throw an exception or provide a default value or do something else)
Please note that the cast inside getValue is actually a safe checked cast (even though it was marked with #SuppressWarnings) as the "safety" proof here is a little bit beyond current javac's capability of static code analysys.
First of all, if getAsString and getAsInt are not doing any conversion (such as would be the case if all your values were stored as strings), you probably can reduce your method to this:
public <T> T getValue(MyObject obj) {
return (T) obj.value;
}
This will have an unchecked cast warning, but that's not worse than leaving the typing decision to your caller (so I'd just #SuppressWarnings("unchecked") it). If your caller uses the wrong target type, they will get a ClassCastException at runtime, which I assume goes well with your current contract. But you can keep c.cast(obj.getAsX()) if you want the exception to be raised in your own method.
With the above, your callers would just use:
String s = getValue(obj);
int i = getValue(obj);
If, however, you are actually converting data in getAs... methods, then you will need to cast in your generic getter after dispatching to the correct getAsX method, at least as ProGu suggested (i.e., return c.cast(obj.getAsX()) in each branch).

Using Java Generics to make two types the same

Consider the following:
public interface Sendable<T> { T details() }
public interface Receiver<T> { void receive(T details) }
I want to make a mapping from a Sendable of any type to a Receiver of the same type. They need to be the same type because at some point I want to call
receiver.receive(sendable.details());
and the compiler would otherwise reject it. I plan on sending many types. I could do something like :
public class Foo {
Map<Sendable<Integer>, Receiver<Integer>> intmap;
Map<Sendable<String>, Receiver<String>> stringmap;
...
//put a map for each type
}
but then I would have to update this class every time I wanted to send some new type. I want to do something like
public class Foo {
Map<Sendable<?>, Receiver<?>> map;
}
since I would only have to write it once and be done with it forever, but this obviously doesn't work because a ? is not a ?. So how can I make a map from T to T for any T?
No casting, that defeats the point of static typing.

Java: Dynamic Type Contraints

I'm currently working on a protocol handler for a project of mine in Java. I am trying to create a maintainable and extensible API, meaning I do not want to simply hardcode in supported value types.
I have begun designing a 'protocol handler' that given a value (of a supported type) can encode that value according to the specification of the protocol, without the client worrying about the details of the translation process.
Different value types e.g. Strings or Integers necessarily have different encoding processes, but I don't want clients to worry about holding references to a different object for each possible type they may need to encode - as I said I don't want them to worry about the details.
So far I have defined a 'generic' DynamicHandler class that maintains a collection of 'specific' type aware StaticHandlers:
class DynamicHandler
{
Map<Class, StaticHandler> handlers;
<T> void handle(T value)
{
if(handlers.containsKey(value.class))
handlers.get(value.getType()).handle(value);
}
void <T> register(StaticHandler<T> handler)
{
handlers.put(T.class, handler);
}
}
The idea of this class is that a client simply passes a value they want to encode to the handle method and the DynamicHandler looks up and delegates to the StaticHandler.
interface StaticHandler<T>
{
void handle(T value);
}
Here an example of some client that uses this system:
class StringHandler implements StaticHandler<String>
{
void handle(String value)
{
...
}
}
DynamicHandler handler = new DynamicHandler();
handler.register(new StringHandler());
handler.handle("Hello World!");
I have two questions which I am struggling to find an answer to on my own:
In the DynamicHandler.register method, how can I get the type of T without having an instance of T?
Is it possible to implement the DynamicHandler type as a java.util.Map, in order to maximise compatibility with any 3rd party code clients, may use to build or otherwise process such objects?
Edit: Since DynamicHandler is essentially a Map, albeit with some generic trickery going on, is it possible to implement it as: DynamicHandler implements java.util.Map<...,...> (I'm not exactly sure what the Key and Value types should be here).
This is my first time asking a question on here, so I hope that I have been clear enough for you all. If there is anything you think needs clarifying just let me know and I will try my best.
If null values are not handled and that it is designed such that there would never be any value that belongs to multiple classes, then you could do this:
public class DynamicHandler {
Map<Class, StaticHandler> handlers;
public <T> void handle(T value) {
if(value != null) {
handlers.entrySet()
.stream()
.filter(entry ->
entry.getKey().isInstance(value))
.findAny()
.ifPresent(entry ->
entry.getValue().handle(value));
}
}
public void <T> register(StaticHandler<T> handler) {
handlers.put(handler.getHandlingClass(), handler);
}
}
interface StaticHandler<T>
{
void handle(T value);
Class<T> getHandlingClass();
}
public class StringHandler implements StaticHandler<String> {
#Override public void handle(String value) {
...
}
#Override public final Class<String> getHandlingClass() {
return String.class;
}
}
In the DynamicHandler class, how can I get the type of T without having an instance of T?
The common solution for this is to pass it a Class object:
void <T> register(StaticHandler<T> handler, Class<T> clazz)
{
handlers.put(clazz, handler);
}
Just as one example of this in a commonly used library: Gson does something similar to register JSON serializers for specific types with GsonBuilder.registerTypeHierarchyAdapter

Implementing multiple instances of the same generic Java interface with different generic types?

I am designing an event-driven system and am running into some basic API problems regarding generics.
I woud like all events to extend BaseEvent:
// Groovy pseudo-code
abstract BaseEvent {
Date occurredOn
BaseEvent() {
super()
this.occurredOn = new Date() // Now
}
}
And I would like all event listeners to implement some basal interface:
interface EventListener<EVENT extends BaseEvent> {
void onEvent(EVENT event)
}
So this works great for simple listeners that only handle a single type of event:
class FizzEvent extends BaseEvent { ... }
class FizzEventListener implements EventListener<FizzEvent> {
#Override
void onEvent(FizzEvent fizzEvent) {
...
}
}
But I will have some listeners that need to handle multiple types of events:
class BuzzEvent extends BaseEvent { ... }
// So then, ideally:
class ComplexListener implements EventListener<FizzEvent>,
EventListener<BuzzEvent> {
#Override
void onEvent(FizzEvent fizzEvent) {
...
}
#Override
void onEvent(BuzzEvent buzzEvent) {
...
}
}
But this produces compiler errors:
Name clash: The method onEvent(EVENT) of type EventListener has the same erasure as onEvent(EVENT) of type EventListener but does not override it
Any ideas what the solution is for handling multiple events?
The problem you're running into is called Type Erasure, which is how Java implements generics. This means that, for Java, the following lines of code:
#Override
void onEvent(FizzEvent fizzEvent) {
...
}
#Override
void onEvent(BuzzEvent buzzEvent) {
...
}
really look like this:
#Override
void onEvent(BaseEvent fizzEvent) {
...
}
#Override
void onEvent(BaseEvent buzzEvent) {
...
}
Notice that the type information has been 'erased' and only the super type BaseEvent remains as the type parameter for both methods, which causes ambiguity and won't work.
If the extends keyword had not been used, it would only see Object instead, but would still run into the same problem.
This is in contrast to C#, which uses Type Reification to implement generics and can know the difference of types at runtime.
In other words, if you ask Java whether a List<Dog> is the same kind of list as a List<Car>, Java would say "yes" because it doesn't know any better at runtime, while C# would say "no" because it retains type information.
Any ideas what the solution is for handling multiple events?
You will need to use different method names or signatures if you want to use the same listener interface (e.g. onDogBarkEvent(Dog d), onCatMeowEvent(Cat c) or perhaps create separate listener interfaces for different kinds of events (e.g. DogBarkListener, CatMeowListener).
This should point you in the right direction with a few Java options.
That aside, if you really feel strongly about your choice and are also free to choose your programming language, then you could consider taking C# for a spin and see if it works better for you.
a possible solution would be to skip generics and have an explicit "supports" method:
public FooListener implements Listener {
public <T extends BaseEvent> boolean supports(Class<T> clazz) {
//decide
}
public void handle(BaseEvent baseEvent) {
//handle
}
}
this, in combination with some abstract classes with generics for the "simple" cases, should do the trick:
private Class<S> clazz;
public Class<S> getClazz() {
if(clazz==null) {
ParameterizedType superclass =
(ParameterizedType)getClass().getGenericSuperclass();
clazz = (Class<S>) superclass.getActualTypeArguments()[0];
}
return clazz;
}
public boolean supports(Class clazz) {
return clazz!=null && clazz == getClazz();
In java 8
public class ComplexListener
{
public final EventListener<FizzEvent> fizzListener = fizzEvent ->
{
...
}
...
use complexListener.fizzListener whenever an EventListener<FizzEvent> is needed.
(Without java8, you can use anonymous class for the same effect, just more verbose.)
Another way in java8 is through method reference
public class ComplexListener
{
public void handleFizzEvent(FizzEvent fizzListener)
{
...
}
use complexListener::handleFizzEvent whenever an EventListener<FizzEvent> is needed.
In java generics, it is explicitly forbidden that an object can be both Foo<A> and Foo<B> (A!=B); i.e. Foo<A> and Foo<B> are mutually exclusive. Many reasons can be raised, but the most important one I think is because of capture conversion -- given a Foo<?> object, the compiler assumes it is a Foo<X> of a unique X. Therefore no object can be Foo<A> & Foo<B> (irrespective of reification).

Constructing a Java generic with an unknown subtype

I have a method like this:
protected <T> void addThing(T obj) {
process(new Blah<T>(obj));
}
The code that is calling into this doesn't know the exact concrete class of the thing it is calling addThing() on:
Animal f = new Giraffe();
addThing(f);
So what I end up with is Blah<Animal>. But what I actually want to get is Blah<Giraffe>. Is this possible? The only solution I could get so far was kind of awkward. I end up taking the data object into Blah as an Object and downcasting it according to the template:
Blah(Object obj) {
// Undesirable downcast.
this.thing = (T)obj;
}
protected <T> void addThing(Class<T> clazz, Object obj) {
process(new Blah<T>(obj));
}
Animal f = new Giraffe();
addThing(f.getClass(), f);
I guess I'm going to have to do a potentially unsafe downcast somewhere, as I don't know the subtype?
The code that interacts with the
Blah makes use of the T class to do
some reflection. It needs a concrete T
instead of some parent class. –
evilfred
No, the code can't interact with T at runtime, because it never gets to know what T is. Generics are ONLY relevant at compile time. What happens is that generics are preprocessed BEFORE the Java code is compiled into byte code. Byte code knows nothing about generics, ever.
In:
protected <T> void addThing(T obj) {
process(new Blah<T>(obj));
}
Blah[Animal] is fixed at compile-time and you cannot turn the process method's signature into Blah[Giraffe]. Not an option.
What the code deals with at runtime is Blah[Animal], not T (or Blah< T >). Ever. What ever the subtype of what you create with new Blah< T > is, byte code will consider it as Blah[Animal]. You can't create new types at runtime.
Your idea of a solution:
Blah(Object obj) {
// Undesirable downcast.
this.thing = (T)obj;
}
is not going to work, because T will be resolved at compile time.
Now if you want to create Blah[Giraffe], don't delegate the creation of new Blah to the addThing method. Do something like this:
private class Blah<T> { }
private class Giraffe { }
public Test_1() {
Blah<Giraffe> f = new Blah<Giraffe>();
addThing2(f);
}
public <T> void addThing2(Blah<T> obj) {
process(obj);
}
public void process(Blah<?> obj) { }
If you can't modify addThing, then you probably don't need to worry about creating a generic with an unknown subtype at runtime in the first place (because is it is impossible in Java). Your issue is/would actually be a non-problem (for the process method at least).
I thought generic parameter types are allowed in constructors as well?
class B<T> {
private T thing;
// I thought one could do generic parameter types in constructors as well?
public B(T thing) { this.thing = thing; }
}
class C {
public void whatever() {
Animal f = new Giraffe();
addThing(f);
}
protected <K> void addThing(K object) {
// if you need reflection, object.getClass() will be the K type at run time.
process(new B<K>(object));
}
// process method elided
}

Categories