无法从Guava解析通用参数TypeToken
我正在开发一个用于为Selenium测试框架构建通用菜单的框架,我一直在使用Guava TypeToken来解析通用参数的类型,但现在我遇到了类型令牌无法解析参数的问题:
我有一个生成菜单选项的构建器的abstract
基class
:
public abstract class AbstractMenuOptionBuilder { protected final TypeToken<AbstractMenuOptionBuilder> typeToken = new TypeToken<AbstractMenuOptionBuilder>(getClass()) { }; public abstract O create(); }
这是构建器的具体class
:
public class MenuOptionBuilder extends AbstractMenuOptionBuilder { public O create() { TypeToken genericOptionParam = typeToken.resolveType(AbstractMenuOptionBuilder.class.getTypeParameters()[0]); Class optionClass; try { optionClass = (Class) Class.forName(genericOptionParam.getType().getTypeName()); } catch(ClassNotFoundException e) { log.catching(e); return null; } } }
我有一个菜单的abstract
基class
,它有一个返回菜单选项列表的方法:
public abstract class AbstractMenu { public final List 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 builder = new MenuOptionBuilder(new MenuOptionBean()){}; } }
我有一个extends
它的具体菜单class
:
//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 { }
我原以为MenuOptionBuilder
中的变量genericOptionParam
将解析为Link
,但它没有解决,而是解析为O
,generics类型参数的名称而不是其运行时类型的Link
。 如果我创建这样的附加基class
,generics参数可以正确解析:
public abstract class AbstractSimpleLinkedMenu extends AbstractMenu { public final List getOptions() { MenuOptionBuilder builder = new MenuOptionBuilder(new MenuOptionBean()){}; } }
我宁愿不必添加像AbstractSimpleLinkedMenu
这样的额外基类,那么我在这里错过或做错了吗? 我认为抽象构建器的匿名内部类将知道运行时类型,如果使用generics参数声明构建器,则期望它不会。 运行时类型由具体菜单class
SimpleMenu
指定,但它似乎不会过滤到菜单选项的abstract
构建器类。
这就是TypeToken
“hack”的工作方式。 它使用Class#getGenericSuperclass()
(或getGenericSuperInterface
)。 它的javadoc说
如果超类是参数化类型,则返回的
Type
对象必须准确反映源代码中使用的实际类型参数。
在这种情况下,这就是O
public abstract class AbstractMenuOptionBuilder
您将获得源代码中的硬编码。 如果您将Link
作为类型参数进行硬编码,就像在此处一样
MenuOptionBuilder builder = new MenuOptionBuilder(new MenuOptionBean()) {};
然后你会得到Link
。
在这种情况下
MenuOptionBuilder builder = new MenuOptionBuilder (new MenuOptionBean()){};
你已经硬编码了O
,这就是你将得到的。
以下是关于类型标记主题的更多内容:
- 具有动态ArrayList项类型的Gson TypeToken
- 是否可以使用Gson.fromJson()来获取ArrayList
>?