无法从Guava解析通用参数TypeToken

我正在开发一个用于为Selenium测试框架构建通用菜单的框架,我一直在使用Guava TypeToken来解析通用参数的类型,但现在我遇到了类型令牌无法解析参数的问题:

我有一个生成菜单选项的构建器的abstractclass

 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; } } } 

我有一个菜单的abstractclass ,它有一个返回菜单选项列表的方法:

 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 >?