如何用Gson替换Guava中的TypeToken(特别是在使用通用类型时)

时间:2018-10-30 08:22:00

标签: java generics reflection gson guava

我目前正在尝试重构项目,以避免不得不使用番石榴作为依赖项。 我主要将其用于反射相关的功能,但是在大多数情况下,我可以找到一种替代方法。

但是,我目前无法解决一种情况: 我尝试检索当前类的通用参数的类。

使用Guava可以正常工作,因为TokenType返回的Type可以强制转换为Class。

番石榴:

(Class<I>) new com.google.common.reflect.TypeToken<I>(getClass()) {}.getType();

我尝试使用TypeToken中的Gson代替此调用,但是显然有关我的信息丢失了,并且此调用的结果是TypeVariable,而不是保留为执行后的类:

Gson:

(Class<I>) new com.google.gson.reflect.TypeToken<I>() {}.getType();

据我所知,getClass()参数是为什么不保留上下文的线索。 当我使用具有相同签名的Guava时:

(Class<I>) new com.google.gson.reflect.TypeToken<I>() {}.getType();

我收到此错误消息:

  

java.lang.IllegalStateException:无法为类型变量构造TypeToken。   您可能打算调用可以为您解析类型变量的新TypeToken(getClass())。   如果确实需要创建类型变量的TypeToken,请改用TypeToken.of()。

我也将Gson视为(受软件包保护的)构造函数,并使用Type作为参数。

有没有办法仅使用Gson获取通用参数的类?

编辑#1:

更好地理解这个问题,我可以说区别似乎在于这两个方法返回的基础Type实现中。

番石榴可以投给Class<I>,而格森人则不能。我不确定Guava的基础实现是什么,但是Gson使用了TypeVariable

目前,我发现的解决方法是通过将Gson TypeToken(类型)的结果与使用当前类作为上下文的此方法合并来利用Guava使用的两种信息(类型+当前类):

public static Type getActualType(Class context, Type parameterizedType) {
    if (parameterizedType instanceof TypeVariableImpl) {
        TypeVariable[] genericParameters = context.getSuperclass().getTypeParameters();
        Type[] implementations = ((ParameterizedTypeImpl) context.getGenericSuperclass()).getActualTypeArguments();
        for (int i = 0; i < genericParameters.length; i++) {
            if (genericParameters[i].getName().equals(((TypeVariableImpl) parameterizedType).getName())) {
                return implementations[i];
            }
        }
    }
    return parameterizedType;
}

(此实现来自buremba/netty-rest project

这使我可以通过调用以下方法检索所需的类:

(Class<I>) getActualType(getClass(), new com.google.gson.reflect.TypeToken<I>() {}.getType());

这似乎有些费力,但我不确定这是否是最好的方法。

注意:该问题也被提出为a Github issue on the Gson Project

0 个答案:

没有答案