无法解析来自Guava的泛型参数TypeToken [英] Cannot resolve generic parameter TypeToken from Guava
问题描述
我正在开发一个用于构建Selenium测试框架的基本化菜单的框架,并且我一直使用Guava TypeToken来解析泛型参数的类型,但是现在我遇到了一个问题,其中的类型标记没有解析一个参数:
我有一个摘要
base 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>扩展AbstractMenuOptionBuilder< O> {
它:
public O create(){
TypeToken<?> genericOptionParam = typeToken.resolveType(AbstractMenuOptionBuilder.class.getTypeParameters()[0]);
班级< O> optionClass;
try {
optionClass =(Class< O>)Class.forName(genericOptionParam.getType()。getTypeName());
< .... snip ....>
} catch(ClassNotFoundException e){
log.catching(e);
返回null;
$ / code $ / pre
我有一个
b
$ b $ $ bpublic abstract class AbstractMenu< O extends IClickable> {
public final List< O> getOptions(){
//这是我的计划不起作用的地方。运行时类型由
//一个扩展AbstractMenu的具体菜单类给出,但运行时
//类似乎不会传递给构建器的抽象基类。
MenuOptionBuilder< O> builder = new MenuOptionBuilder< O>(new MenuOptionBean()){};
< .... snip ....>
}
}
我有一个具体的菜单
class
extends
//'Link'的运行时类型不被类型标记知道,该标记应该是
//在抽象构建器基类中解析它。
public SimpleMenu扩展AbstractMenu< Link> {
< .... snip ....>
}
我期望变量
genericOptionParam
inMenuOptionBuilder
会解析为链接
,但它不会解析为O
,泛型类型参数的名称,而不是它的运行时类型链接
。如果我像这样创建一个额外的基础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
builder class for menu options。
解决方案c $ c> TypeToken hack的作品。它使用
Class#getGenericSuperclass()
(或getGenericSuperInterface
)。它的javadoc状态
如果超类是参数化类型,则返回
Type
对象
必须准确反映源
代码中使用的实际类型参数。
在这种情况下,这是
O
,这里public abstract class AbstractMenuOptionBuilder< O扩展IClickable>
您可以获得源代码中的硬编码。如果您将
Link
作为类型参数进行硬编码,就像您在这里做的那样
MenuOptionBuilder< LINK> builder =
new MenuOptionBuilder< Link>(new MenuOptionBean()){};
然后您将获得
链接
。
在这种情况下,
MenuOptionBuilder< O> builder =
new MenuOptionBuilder< O>(new MenuOptionBean()){};
你已经硬编码
O
,所以这就是你会得到的。
下面是我写的关于类型标记主题的更多内容:
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.
That's how the TypeToken
"hack" works. It uses Class#getGenericSuperclass()
(or getGenericSuperInterface
). Its javadoc states
If the superclass is a parameterized type, the
Type
object returned must accurately reflect the actual type parameters used in the source code.
In this case, that is O
, here
public abstract class AbstractMenuOptionBuilder<O extends IClickable>
You get what is hard coded in the source code. If you hard code Link
as the type argument, as you do here
MenuOptionBuilder<Link> builder =
new MenuOptionBuilder<Link>(new MenuOptionBean()) {};
then you will get Link
.
In this case
MenuOptionBuilder<O> builder =
new MenuOptionBuilder<O>(new MenuOptionBean()){};
you've hard coded O
, so that's what you will get.
Here are some more things I've written on the subject of type tokens:
- Gson TypeToken with dynamic ArrayList item type
- is it possible to use Gson.fromJson() to get ArrayList<ArrayList<String>>?
这篇关于无法解析来自Guava的泛型参数TypeToken的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!