使用Gson解析List时,将类作为参数?

时间:2017-02-14 11:52:14

标签: java json gson typetoken

我需要将JSON对象数组解析为列表。我会通过

Class<?> classToParse 

作为参数。根据{{​​3}},我需要像

这样的东西
Type listType =  new TypeToken<List<ExampleClass>>() {}.getType();

一起使用
 gsonInstance.fromJson(output, listType);

但是如何指定我的&#34; classToParse&#34; (参数)而不是硬编码的ExampleClass?我无法按原样插入。

1 个答案:

答案 0 :(得分:0)

您无法使用运行时调用替换编译类型的type参数 - 类型信息以及类型参数由Java编译器在编译时生成。

首先请注意如何声明 Gson.fromJson(...)重载:既没有使用TypeToken作为参数,但是他们可以接受Type - 这很好,因为TypeToken必须解析参数化类型JSON,类型只是重要的。其次,非常好将现成的Type个实例传递给fromJson方法:

final Foo foo = gson.fromJson(..., Foo.class);
final List<Foo> foos = gson.fromJson(..., new TypeToken<List<Foo>>(){}.getType());

请注意,在两个案例中都会传递文字:第二个文字只会更长,并且每次执行该行时都会创建。 Type接口不提供任何mutator方法,因此您可以将其视为可以视为常量的东西(以及其他值类型ilke String s,Integer和等等):

static final TypeToken<List<Foo>> fooListTypeToken = new TypeToken<List<Foo>>(){};
...
final List<Foo> foos = gson.fromJson(..., fooListTypeToken.getType());

甚至更短(但我更喜欢以前的方式 - 我会向你推荐[你可以重复使用类型令牌而不会失去它]):

static final Type fooListType = new TypeToken<List<Foo>>(){}.getType();
...
final List<Foo> foos = gson.fromJson(..., fooListTypeToken);

fooListTypeTokenFoo.class与程序化观点有多大差异?嗯,基本上没有区别(除了第一个代表一个列表,而后者代表一个具体的类,当然)。两者都是价值观。

但是,如果您希望获得任何必须原因的给定元素类(或更好的类型)的动态类型,那么您可以自己创建Type个实例并只传递它们到fromJson

static ParameterizedType createJavaUtilListParameterizedType(final Type elementType) {
    return new ParameterizedType() {
        @Override
        public Type getRawType() {
            return List.class;
        }

        @Override
        public Type[] getActualTypeArguments() {
            return new Type[]{ elementType };
        }

        @Override
        public Type getOwnerType() {
            return null;
        }
    };
}

该方法只创建ParameterizedType的匿名实现,其中:

  • getRawType() - 必须返回java.util.List.class,容器参数化类型
  • getActualTypeArguments() - 必须返回元素类型;请注意,它总是必须返回一个新数组,以免在别处被损坏(因为它不是0长度数组)
  • getOwnerType() - 在这种情况下未实现,可以安全地返回null

所以现在替换在运行时可用:

final List<Foo> foos = gson.fromJson(..., createJavaUtilListParameterizedType(Foo.class));

final List<Foo> foos = gson.fromJson(..., createJavaUtilListParameterizedType(new TypeToken<GenericElement<String, Integer>>(){}.getType()));

用于参数化类型。好吧,与保持static final对类型标记的引用以及稍后从中提取类型相比仍然没有太大差别。从语义上讲,它与编译器在编译时的作用相同。

修改

Gson TypeToken还提供static TypeToken<?> getParameterized(Type rawType, Type... typeArguments),可以使用static ParameterizedType createJavaUtilListParameterizedType(final Type elementType) { return (ParameterizedType) TypeToken.getParameterized(List.class, elementType).getType(); } 代替自己实现的参数化类型,如:

class Dog
  attr_accessor :name
  def initialize()
    @name = "Denver"
  end
end

def rename_dog(dog)
  dog.name = "New_Dog_Name"
  return
end

dog = Dog.new
puts "Dog's initial name: #{dog.name}" # => Dog's initial name: Denver
rename_dog(dog)
puts "Dog's New name: #{dog.name}" # => Dog's New name: New_Dog_Name