无法解析来自Guava的泛型参数TypeToken [英] Cannot resolve generic parameter TypeToken from Guava

查看:385
本文介绍了无法解析来自Guava的泛型参数TypeToken的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在开发一个用于构建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 $ $ b

  public 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 in MenuOptionBuilder 会解析为链接,但它不会解析为 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:

这篇关于无法解析来自Guava的泛型参数TypeToken的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆