I am developing a framework for building generified menus for a Selenium testing framework, and I've been using Guava TypeToken to resolve the types of generic parameters, but now I've run into a problem where the type token doesn't resolve a parameter:
I have an abstract base class for a builder that generates a menu option:
public abstract class AbstractMenuOptionBuilder<O extends IClickable> {
protected final TypeToken<AbstractMenuOptionBuilder<O>> typeToken = new
TypeToken<AbstractMenuOptionBuilder<O>>(getClass()) { };
public abstract O create();
}
This is a concrete class for a builder:
public class MenuOptionBuilder<O extends IClickable> extends AbstractMenuOptionBuilder<O> {
public O create() {
TypeToken<?> genericOptionParam = typeToken.resolveType(AbstractMenuOptionBuilder.class.getTypeParameters()[0]);
Class<O> optionClass;
try {
optionClass = (Class<O>) Class.forName(genericOptionParam.getType().getTypeName());
<.... snip ....>
} catch(ClassNotFoundException e) {
log.catching(e);
return null;
}
}
}
I have an abstract base class for menus which has a method to return a list of menu options:
public abstract class AbstractMenu<O extends IClickable> {
public final List<O> getOptions() {
//This is where my plan doesn't work. The runtime type is given by
//a concrete menu class which extends AbstractMenu, but that runtime
//type doesn't seem to pass through to the abstract base class for the builder.
MenuOptionBuilder<O> builder = new MenuOptionBuilder<O>(new MenuOptionBean()){};
<.... snip ....>
}
}
And I have a concrete menu class that extends it:
//The runtime type of 'Link' is not known by the type token that is supposed to
//resolve it in the abstract builder base class.
public SimpleMenu extends AbstractMenu<Link> {
<.... snip ....>
}
I was expected that the variable genericOptionParam in MenuOptionBuilder would resolve to Link, but it doesn't Instead, it resolved to O, the name of the generic type parameter instead of its runtime type of Link. If I create an additional base class like this, the generic parameter resolves correctly:
public abstract class AbstractSimpleLinkedMenu extends AbstractMenu<Link> {
public final List<Link> getOptions() {
MenuOptionBuilder<Link> builder = new MenuOptionBuilder<Link>(new MenuOptionBean()){};
<.... snip ....>
}
}
I would prefer not to have to add additional base classes like AbstractSimpleLinkedMenu, so is there something I have missed or done incorrectly here? I thought that the anonymous inner class for the abstract builder would know the runtime type, expect that it doesn't if the builder is declared with a generic parameter. The runtime type is specified by the concrete menu class, SimpleMenu, but it doesn't seem to filter through to the abstract builder class for menu options.