I am with a sort of trouble when using java generics in the visitor pattern.
My code is something like that:
public interface MyInterfaceVisitor<A, B> {
public A visitMyConcreteObject(MyConcreteObject object, B parameter);
}
public interface MyObject {
public <A, B> A accept(MyInterfaceVisitor<A, B> visitor, B parameter);
}
public class MyConcreteObject implements MyObject {
@Override
public <A, B> A accept(MyInterfaceVisitor<A, B> visitor, B parameter) {
return visitor.visitMyConcreteObject(this, parameter);
}
}
public class MyConcreteVisitor implements MyInterfaceVisitor<????> {
@Override
public <X extends C> X visitMyConcreteObject(MyConcreteObject object, Class<X> parameter) {
// Do a lot of things.
// Return an instance of the given class.
}
// This method is the entry point of the MyConcreteVisitor.
public <X extends C> void someOtherMethod(Class<X> parameter) {
MyObject m = ...;
X x = m.accept(this, parameter);
...;
}
}
public class C {}
public class Dog extends C {}
public class Cat extends C {}
public class Client {
public static void main(String... args) {
MyConcreteVisitor v = new MyConcreteVisitor();
v.someOtherMethod(Cat.class);
v.someOtherMethod(Dog.class);
}
}
// We have other implementations of the visitor that does not matters, like this one.
public class SomeOtherConcreteVisitor implements MyInterfaceVisitor<String, Integer> {
@Override
public String visitMyConcreteObject(MyConcreteObject object, Integer parameter) {
return "foo";
}
}
I need to find what is the generic signature in the ???? that makes the code compilable allowing the overriden method in MyConcreteVisitor class to match the signature in MyInterfaceVisitor interface.
I can’t change the signature of the visitMyObject in the MyInterfaceVisitor interface, nor its generics. This happens because others implementations of MyInterfaceVisitor exists and their generics have nothing to with the ones from MyConcreteVisitor.
The MyConcreteVisitor class should not have a generic per-se, so the compiler must allow a MyConcreteVisitor v = new MyConcreteVisitor(); without generating the unchecked or rawtypes warning.
If I change the concrete visitMyObject to public C visitMyObject(MyObject object, Class<? extends C> parameter) and declare the ???? as <C, Class<? extends C>>, I would need to add a cast in the someOtherMethod.
How to define the generic type making it compilable without getting the unchecked or rawtypes warning, changing the interface or adding a cast? Is this even possible in java or I am abusing the generics too much?
The issue is that your implementation is trying to introduce another type parameter
X extends Cto the methodvisitMyConcreteObjectand resolve theBparameter with it. You can’t makevisitMyConcreteObjectgeneric withXbut try to resolveBwith a type parameterized byX, e.g.Class<X>, becauseBis resolved at the class declaration butXis only declared by a method of the class.From what I can see, you have two options. Either make
MyConcreteVisitorgeneric onX:Or get rid of
Xand lose type safety (beyond the concrete typeC):