2012-06-15 4 views
5

У меня возникли некоторые проблемы с десериализации массив JSON, который имеет следующий формат:Само циклическая ссылка в Gson

[ 
{ 
    "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, учитывая, что я не могу предположить, сколько уровней категорий есть? Спасибо заранее.

Edit: Только в случае, если кто-то имеет такую ​​же проблему, на основе Спаета ответ я приспособил решение в более общем случае, с помощью отражения. Единственное требование состоит в том, что список объектов, представленных массивом 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

Может быть, вы могли бы попробовать это:

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

Спасибо. Тип TypeToken работал отлично, хотя мне пришлось немного адаптировать ваш ответ к моему делу, поскольку ArrayOfCategory и Category были всего лишь одним примером, но мне пришлось рассмотреть более общий случай. Если вам интересно, я обновил свой вопрос. Cheers – jlordiales

1

Посмотрите на GraphAdapterBuilder. Вам нужно будет включить его в свое приложение, но оно может сериализовать произвольные графики объектов.

+0

Оказывается, вам действительно не нужен GraphAdapterBuilder для десериализации, но только для сериализации (по крайней мере, в моем случае). Спасибо в любом случае за то, что указали мне на интересную и, возможно, полезную библиотеку. – jlordiales

Смежные вопросы