Gson中的自循环引用

时间:2012-06-15 21:32:09

标签: java json gson circular-reference

我有一些问题要反序列化遵循这种格式的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数组表示的对象列表包装在另一个类中(如我的例子中的Category和ArrayOfCategory)。使用以下代码应用于我的原始示例,您只需调用“deserializeJson(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 个答案:

答案 0 :(得分:2)

也许你可以试试这个:

    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);

你会得到一个好结果。

“神奇”出现在这里:new TypeToken<Collection<Category>>() {}.getType()

整个代码是:

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
}
]

答案 1 :(得分:1)

看看GraphAdapterBuilder。您需要将它包含在您的应用中,但它可以序列化对象的任意图形。