I have a class hierarchy where cousins share very similar functionality. For example:
Node
Statement
FunctionCallStatement
Expression
FunctionCallExpression
FunctionCallStatement and FunctionCallExpression share a very similar API, but I cannot express that in pure class terms with a single-inheritance hierarchy. So, I've created an IsFunctionCall Interface which both of these implement. I can now declare a method which takes either a FunctionCallStatement or a FunctionCallExpression as follows:
void <T extends Node & IsFunctionCall> doSomething(T node) { ... }
This all works very nicely.
Unfortunately, I've now found myself faced with a rather awkward problem. I have a Node; I know dynamically that it must be either a FunctionCallStatement or a FunctionCallExpression; I need to pass that Node into the doSomething()
method above. I cannot find a way to upcast it to an appropriate type.
Right now I'm using a chain of instanceof to determine which class the Node is and to cast it to the appropriate concrete type, but that's butt-ugly. The only other way I know to make this work is to make an IsNode interface and have everything that currently expects a Node expect an IsNode instead; this would allow me to declare a union interface that implements IsNode and IsFunctionCall and let me do away without the generics above. But that's a hell of a lot of work and is still pretty ugly.
Is there an alternative way to do this?
(Note: example above is a simplified version of my actual code.)
Update: I tried the following piece of evil:
@SuppressWarnings("unchecked")
private <S extends Node & IsFunctionCall> S castNode(Node node)
{
return (S) node;
}
and then:
doSomething(castNode(node));
I got some very strange error messages. It would appear that the type inference used to determine the S of castNode()
will not match against the T in the declaration of doSomething()
; it's using the concrete type only and setting S to Node. Which of course does not match doSomething()
's declared type. Very peculiar.
Update update:
This appears to be a close duplicate of How should I cast for Java generic with multiple bounds?. My situation is slightly different because my bounds include an object and an interface, while the one in the other question has two interfaces, but it's still applicable.
Looks like I need to go and reengineer my entire application. Sigh.
Any admin, feel free to close this as a duplicate...