我正在开发一个用于为Selenium测试框架构建通用菜单的框架,我一直在使用Guava TypeToken来解析通用参数的类型,但是现在我遇到了类型问题令牌没有解析参数:
我有一个abstract
基础class
,用于生成菜单选项的构建器:
public abstract class AbstractMenuOptionBuilder<O extends IClickable> {
protected final TypeToken<AbstractMenuOptionBuilder<O>> typeToken = new
TypeToken<AbstractMenuOptionBuilder<O>>(getClass()) { };
public abstract O create();
}
这是构建器的具体class
:
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;
}
}
}
我有一个abstract
基础class
用于菜单,其中包含返回菜单选项列表的方法:
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 ....>
}
}
我有一个具体的菜单class
extends
:
//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 ....>
}
我预计genericOptionParam
中的变量MenuOptionBuilder
将解析为Link
,但事实并非如此,而是将其解析为O
,其名称为泛型类型参数,而不是其Link
的运行时类型。如果我像这样创建一个额外的基数class
,则通用参数会正确解析:
public abstract class AbstractSimpleLinkedMenu extends AbstractMenu<Link> {
public final List<Link> getOptions() {
MenuOptionBuilder<Link> builder = new MenuOptionBuilder<Link>(new MenuOptionBean()){};
<.... snip ....>
}
}
我不想添加像AbstractSimpleLinkedMenu
这样的其他基类,那么我在这里错过了什么或做错了吗?我认为抽象构建器的匿名内部类将知道运行时类型,如果使用泛型参数声明构建器,则期望它不会。运行时类型由具体菜单class
,SimpleMenu
指定,但它似乎没有过滤到abstract
构建器类的菜单选项。
答案 0 :(得分:4)
这就是TypeToken
“hack”的工作方式。它使用Class#getGenericSuperclass()
(或getGenericSuperInterface
)。它的javadoc陈述
如果超类是参数化类型,则返回
Type
个对象 必须准确反映源中使用的实际类型参数 代码。强>
在这种情况下,这是O
,这里是
public abstract class AbstractMenuOptionBuilder<O extends IClickable>
您将获得源代码中的硬编码内容。如果您将Link
硬编码为类型参数,就像在此处一样
MenuOptionBuilder<Link> builder =
new MenuOptionBuilder<Link>(new MenuOptionBean()) {};
然后你会得到Link
。
在这种情况下
MenuOptionBuilder<O> builder =
new MenuOptionBuilder<O>(new MenuOptionBean()){};
你已经硬编码O
,这就是你将得到的。
以下是关于类型代币主题的更多内容: