使用 Gson 反序列化 ImmutableList

发布于 2024-12-08 19:56:00 字数 255 浏览 3 评论 0原文

我正在使用相当多的不可变集合,我很好奇如何使用 Gson 反序列化它们。由于没有人回答并且我自己找到了解决方案,因此我正在简化问题并提出我自己的答案。

我有两个问题:

  • 如何编写一个适用于所有 ImmutableListDeserializer
  • 如何为所有ImmutableList注册它?

I'm using quite a few immutable collections and I'm curious how to deserialize them using Gson. As nobody answered and I've found the solution myself, I'm simplifying the question and presenting my own answer.

I had two problems:

  • How to write a single Deserializer working for all ImmutableList<XXX>?
  • How to register it for all ImmutableList<XXX>?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

有深☉意 2024-12-15 19:56:00

更新:https://github.com/acebaggins/gson-serializers涵盖了许多番石榴集合:

  • ImmutableList
  • ImmutableSet
  • ImmutableSortedSet
  • ImmutableSortedMap
  • ImmutableSortedMap

如何编写一个适用于所有 ImmutableList 的反序列化器?

想法很简单,将传递的表示 ImmutableListType 转换为表示 ListType >,使用内置的 Gson 功能创建 List 并将其转换为 ImmutableList

class MyJsonDeserializer implements JsonDeserializer<ImmutableList<?>> {
    @Override
    public ImmutableList<?> deserialize(JsonElement json, Type type, JsonDeserializationContext context) throws JsonParseException {
        final Type type2 = ParameterizedTypeImpl.make(List.class, ((ParameterizedType) type).getActualTypeArguments(), null);
        final List<?> list = context.deserialize(json, type2);
        return ImmutableList.copyOf(list);
    }
}

我使用的 Java 库中有多个 ParameterizedTypeImpl 类,但它们都不供公共使用。我使用 sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl 对其进行了测试。

如何为所有ImmutableList注册它?

这部分很简单,注册的第一个参数是 java.lang.reflect.Type,它误导我使用 ParameterizedType,而只是使用 Class做的工作:

final Gson gson = new GsonBuilder()
    .registerTypeAdapter(ImmutableList.class, myJsonDeserializer)
    .create();

Update: There's https://github.com/acebaggins/gson-serializers which covers many guava collections:

  • ImmutableList
  • ImmutableSet
  • ImmutableSortedSet
  • ImmutableMap
  • ImmutableSortedMap

How to write a single Deserializer working for all ImmutableList?

The idea is simple, transform the passed Type representing an ImmutableList<T> into a Type representing List<T>, use the build-in Gson's capability to create a List and convert it to an ImmutableList.

class MyJsonDeserializer implements JsonDeserializer<ImmutableList<?>> {
    @Override
    public ImmutableList<?> deserialize(JsonElement json, Type type, JsonDeserializationContext context) throws JsonParseException {
        final Type type2 = ParameterizedTypeImpl.make(List.class, ((ParameterizedType) type).getActualTypeArguments(), null);
        final List<?> list = context.deserialize(json, type2);
        return ImmutableList.copyOf(list);
    }
}

There are multiple ParameterizedTypeImpl classes in Java libraries I use, but none of them intended for public usage. I tested it with sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl.

How to register it for all ImmutableList?

That part is trivial, the first argument to register is java.lang.reflect.Type which mislead me to using ParameterizedType, where simply using Class does the job:

final Gson gson = new GsonBuilder()
    .registerTypeAdapter(ImmutableList.class, myJsonDeserializer)
    .create();
黎歌 2024-12-15 19:56:00

另一种没有 ParameterizedTypeImpl 的实现

@Override
public ImmutableList<?> deserialize(final JsonElement json, final Type type, final JsonDeserializationContext context) throws JsonParseException {
    @SuppressWarnings("unchecked")
    final TypeToken<ImmutableList<?>> immutableListToken = (TypeToken<ImmutableList<?>>) TypeToken.of(type);
    final TypeToken<? super ImmutableList<?>> listToken = immutableListToken.getSupertype(List.class);
    final List<?> list = context.deserialize(json, listToken.getType());
    return ImmutableList.copyOf(list);
}

One more implementation without ParameterizedTypeImpl

@Override
public ImmutableList<?> deserialize(final JsonElement json, final Type type, final JsonDeserializationContext context) throws JsonParseException {
    @SuppressWarnings("unchecked")
    final TypeToken<ImmutableList<?>> immutableListToken = (TypeToken<ImmutableList<?>>) TypeToken.of(type);
    final TypeToken<? super ImmutableList<?>> listToken = immutableListToken.getSupertype(List.class);
    final List<?> list = context.deserialize(json, listToken.getType());
    return ImmutableList.copyOf(list);
}
紫﹏色ふ单纯 2024-12-15 19:56:00

@maaartinus 已经涵盖了第二个问题,因此我将针对第一个问题发布一个基于 Guava 的补充解决方案,该解决方案不需要 ParametrizedTypeImpl

public final class ImmutableListDeserializer implements JsonDeserializer<ImmutableList<?>> {
  @Override
  public ImmutableList<?> deserialize(final JsonElement json, final Type type,
                                      final JsonDeserializationContext context)
      throws JsonParseException {
    final Type[] typeArguments = ((ParameterizedType) type).getActualTypeArguments();
    final Type parameterizedType = listOf(typeArguments[0]).getType();
    final List<?> list = context.deserialize(json, parameterizedType);
    return ImmutableList.copyOf(list);
  }

  private static <E> TypeToken<List<E>> listOf(final Type arg) {
    return new TypeToken<List<E>>() {}
        .where(new TypeParameter<E>() {}, (TypeToken<E>) TypeToken.of(arg));   
  }
}

@maaartinus already covered the second question, so I'll post a complementary Guava-based solution to the first question which doesn't require ParametrizedTypeImpl

public final class ImmutableListDeserializer implements JsonDeserializer<ImmutableList<?>> {
  @Override
  public ImmutableList<?> deserialize(final JsonElement json, final Type type,
                                      final JsonDeserializationContext context)
      throws JsonParseException {
    final Type[] typeArguments = ((ParameterizedType) type).getActualTypeArguments();
    final Type parameterizedType = listOf(typeArguments[0]).getType();
    final List<?> list = context.deserialize(json, parameterizedType);
    return ImmutableList.copyOf(list);
  }

  private static <E> TypeToken<List<E>> listOf(final Type arg) {
    return new TypeToken<List<E>>() {}
        .where(new TypeParameter<E>() {}, (TypeToken<E>) TypeToken.of(arg));   
  }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文