当前位置: 首页 > 知识库问答 >
问题:

Gson 中的自循环引用

谷梁嘉运
2023-03-14

我在反序列化遵循以下格式的Json数组时遇到了一些问题:

[
{
  "ChildList":[
     {
        "ChildList":[

        ],
        "Id":110,
        "Name":"Books",
        "ApplicationCount":0
     }
  ],
  "Id":110,
  "Name":"Books",
  "ApplicationCount":0
}
]

它基本上是一个类别数组,其中每个类别也可以有一个子类别列表,依此类推。我的类模型看起来有点像这样:

public class ArrayOfCategory{
    protected List<Category> category;
}

public class Category{

    protected ArrayOfCategory childList;
    protected int id;
    protected String name;
    protected int applicationCount;
}

现在,Gson显然抱怨循环引用。有没有办法解析这个Json输入,因为我不能假设有多少个类别级别?提前感谢。

编辑:以防万一有人有类似的问题,根据Spaeth的回答,我将解决方案调整为使用反射的更一般的情况。唯一的要求是JSON数组表示的对象列表包装在另一个类中(如我的示例中的类别和ArrayOf类别)。通过将以下代码应用于我的原始示例,您可以调用“反序列化Json(jsonString,ArrayOfCategory.class)”,它将按预期工作。

private <T> T deserializeJson(String stream, Class<T> clazz) throws PluginException {
    try {
        JsonElement je = new JsonParser().parse(stream);
        if (je instanceof JsonArray) {
            return deserializeJsonArray(clazz, je);
        } else {
            return new GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE).create().fromJson(stream, clazz);         
        }
    } catch (Exception e) {
        throw new PluginException("Failed to parse json string: " + ((stream.length() > 20) ? stream.substring(0, 20) : stream) + "... to class " + clazz.getName());
    }       
}

private <T> T deserializeJsonArray(Class<T> clazz, JsonElement je) throws InstantiationException, IllegalAccessException {
    ParameterizedType listField = (ParameterizedType) clazz.getDeclaredFields()[0].getGenericType();
    final Type listType = listField.getActualTypeArguments()[0];
    T ret = clazz.newInstance();
    final Field retField = ret.getClass().getDeclaredFields()[0];
    retField.setAccessible(true);
    retField.set(ret, getListFromJsonArray((JsonArray) je,(Class<?>) listType));
    return ret;
}

private <E> List<E> getListFromJsonArray(JsonArray je, Class<E> listType) {
    Type collectionType = new TypeToken<List<E>>(){}.getType();
    final GsonBuilder builder = new GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE);
    Gson jsonParser = builder.create();
    return jsonParser.fromJson(je, collectionType);
}

共有2个答案

阮健
2023-03-14

看看Graph适配器构建器。您需要将其包含在您的应用程序中,但它可以序列化对象的任意图形。

方波娃
2023-03-14

也许你可以试试这个:

    com.google.gson.Gson gson = new GsonBuilder().create();
    InputStreamReader reader = new InputStreamReader(new FileInputStream(new File("/tmp/gson.txt")));
    Collection<Category> fromJson = gson.fromJson(reader, new TypeToken<Collection<Category>>() {}.getType());
    System.out.println(fromJson);

你会得到一个好结果的。

“神奇”发生在这里:新的TypeToken

整个代码是:

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStreamReader;
import java.util.Collection;
import java.util.List;

import com.google.gson.GsonBuilder;
import com.google.gson.JsonIOException;
import com.google.gson.JsonSyntaxException;
import com.google.gson.reflect.TypeToken;

public class GsonCircularReference {

    public class Category {
        protected List<Category> childList;
        protected int id;
        protected String name;
        protected int applicationCount;

        public List<Category> getChildList() {
            return childList;
        }

        public void setChildList(final List<Category> childList) {
            this.childList = childList;
        }

        public int getId() {
            return id;
        }

        public void setId(final int id) {
            this.id = id;
        }

        public String getName() {
            return name;
        }

        public void setName(final String name) {
            this.name = name;
        }

        public int getApplicationCount() {
            return applicationCount;
        }

        public void setApplicationCount(final int applicationCount) {
            this.applicationCount = applicationCount;
        }

        @Override
        public String toString() {
            return "Category [category=" + childList + ", id=" + id + ", name=" + name + ", applicationCount="
                    + applicationCount + "]";
        }

    }

    public static void main(final String[] args) throws JsonSyntaxException, JsonIOException, FileNotFoundException {
        com.google.gson.Gson gson = new GsonBuilder().create();
        InputStreamReader reader = new InputStreamReader(new FileInputStream(new File("/tmp/gson.txt")));
        Collection<Category> fromJson = gson.fromJson(reader, new TypeToken<Collection<Category>>() {}.getType());
        System.out.println(fromJson);
    }

}

JSON 文件是:

[
{
  "childList":[
     {
        "childList":[
        ],
        "id":110,
        "Name":"Books",
        "applicationCount":0
     }
  ],
  "id":110,
  "name":"Books",
  "applicationCount":0
}
]

 类似资料:
  • 问题内容: 给定一个以复杂的,循环的方式相互引用的类实例的集合:垃圾收集器是否可能无法释放这些对象? 我隐约记得过去这是JVM中的问题,但我 认为 这在几年前已解决。但是,在jhat中进行的一些调查显示,循环引用是我现在面临的内存泄漏的原因。 注意:我一直给人以JVM能够解析循环引用并从内存中释放这种“垃圾岛”的印象。 但是,我提出这个问题只是为了看看是否有人发现了任何异常。 问题答案: 循环引用

  • 本文向大家介绍C++中的循环引用,包括了C++中的循环引用的使用技巧和注意事项,需要的朋友参考一下 虽然C++11引入了智能指针的,但是开发人员在与内存的斗争问题上并没有解放,如果我门实用不当仍然有内存泄漏问题,其中智能指针的循环引用缺陷是最大的问题。 我们可以看到在出main函数作用域之前两个指针指向的内存并没有释放(指针指向的对象没有调用析构函数),我门把当前的引用数打印出来为2这个没有问题,

  • 问题内容: 我有一个带有循环引用的结构。出于调试目的,我想将其转储。基本上是任何格式,但我选择了JSON。 由于可以是任何类,因此我选择了不需要JAXB批注的GSON。 但是GSON击中了循环引用并递归直到。 如何将GSON限制为 忽略某些班级成员?两者和都不服从。 忽略某些对象图路径?例如,我可以指示GSON不要序列化。 最多达到2个级别的深度? 问题答案: 只需将字段设为瞬态(如中的)。GSO

  • 我有一个循环引用的结构。出于调试的目的,我想转储它。基本上可以是任何格式,但我选择了JSON。 由于它可以是任何类,我选择了不需要JAXB注释的GSON。 但是GSON会命中循环引用并递归,直到。 如何将 GSON 限制为 > 忽略某些类成员?不遵守和。 忽略某些对象图路径?例如,我可以指示GSON不要序列化< code > release . custom fields . product 。

  • 由于几个循环引用,我遇到了通过GoogleGSON序列化Java对象的问题。我的所有尝试都以StackOverflowException结束,因为GSON无法处理这些循环引用。 作为一个解决方案,我发现了以下: http://code.google.com/p/google-gson/source/browse/trunk/extras/src/main/java/com/google/gson/

  • 问题内容: 在正在进行的项目中,人们编写了服务类来访问DAO。几乎每个业务对象都具有使用自己的DAO的自己的服务。在某些服务上,我们使用对其他服务的引用。目前,人们正在实例化构造函数内部所需的服务。 但是现在,我遇到了麻烦,因为服务A需要服务B而服务B需要服务A,因此对任一构造函数的调用都会导致堆栈溢出… 示例(伪代码): 您将如何解决?使用单例模式? 谢谢 问题答案: Spring框架通过使用依