简体   繁体   English

使用GSON将集合序列化为JsonObject而不是JsonArray

[英]Serialize collection as JsonObject instead of JsonArray with GSON

My goal is to serialize a class implementing the Collection interface as JSON object instead of a JSON array. 我的目标是序列化一个将Collection接口实现为JSON对象而不是JSON数组的类。 The following class is a simplyfied example: 以下类是一个简单的示例:

public class CollectionImplementation implements Collection<String> {
  private final List<String> _wrappedList = new LinkedList<>();
  private String _otherField = "asdf";

  @Override
  public boolean add(String e) {
    return _wrappedList.add(e);
  }

  @Override
  ...
}

The result of new Gson().toJson(collectionImplementationInstance) is: new Gson().toJson(collectionImplementationInstance)是:

["str1","str2",...]

which misses the other field. 错过了另一个领域。 Instead, I would like to get: 相反,我想得到:

{"_wrappedList":["str1","str2"],"_otherField":"asdf"}

Is there a way without manually adding all fields to the JSON? 有没有一种方法可以不手动将所有字段添加到JSON?

Based on this tutorial you can use a JsonSerializer. 根据本教程,您可以使用JsonSerializer。

Note: in the example below I've renamed your class CollectionImpl. 注意:在下面的示例中,我已将您的类CollectionImpl重命名。

public class CollectionImpl implements Collection<String> {

    private final List<String> _wrappedList = new LinkedList<>();
    private String _otherField = "asdf";

    // ...

    // Note: I've created the class as subclass of CollectionImpl in order to access the
    // private fields without implementing a getter (as you maybe want to keep 
    // your fields completely private)
    public static class CollectionImplJsonSerializer implements JsonSerializer<CollectionImpl> {
        @Override
        public JsonElement serialize(CollectionImpl src, Type typeOfSrc, JsonSerializationContext context) {
            JsonObject jsonColl = new JsonObject();
            JsonArray array = new JsonArray();

            for (String s: src._wrappedList) {
                array.add(s);
            }

            jsonColl.add("_wrappedList", array);
            jsonColl.addProperty("_otherField", src._otherField);


            return jsonColl;
        }
    }
}

Then you can do: 然后,您可以执行以下操作:

CollectionImpl ci = new CollectionImpl();

GsonBuilder builder = new GsonBuilder();
CollectionImpl.CollectionImplJsonSerializer serializer = new CollectionImpl.CollectionImplJsonSerializer();
builder.registerTypeAdapter(CollectionImpl.class, serializer);
Gson gson = builder.create();

String json = gson.toJson(ci);

As a workaround, one can use Reflection to get an instance of the ReflectiveTypeAdapterFactory in an own TypeAdapterFactory : 解决方法是,可以使用ReflectiveTypeAdapterFactory在自己的TypeAdapterFactory获取ReflectiveTypeAdapterFactory的实例:

public class CollectionImplementationTypeAdapterFactory implements TypeAdapterFactory {
  @Override
  public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
    if (!type.getRawType().equals(CollectionImplementation.class)) {
      return null;
    }
    try {
      Field factoriesField = Gson.class.getDeclaredField("factories");
      factoriesField.setAccessible(true);
      @SuppressWarnings("unchecked")
      List<TypeAdapterFactory> factories = (List<TypeAdapterFactory>) factoriesField.get(gson);
      TypeAdapterFactory typeAdapterFactory = factories.stream().filter(f -> f instanceof ReflectiveTypeAdapterFactory).findAny().get();
      return typeAdapterFactory.create(gson, type);
    } catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException exception) {
      return null;
    }
  }
}

This can be registered with 可以注册到

gsonBuilder.registerTypeAdapterFactory(new CollectionImplementationTypeAdapterFactory());

Does someone know a solution without Reflection? 没有反射,有人知道解决方案吗?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM