2015-04-28 3 views
4

Рассмотрит эту простую JSon:GSON - Deserialize примитивного массив

{ 
    "test": [ 
     0, 
     3 
    ] 
} 

Теперь я десериализация его в простом целочисленном массиве, так для этого я использую пользовательский десериализатор:

class ArrayDeserializer implements JsonDeserializer<int[]> { 
    @Override 
    public int[] deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { 
     return context.deserialize(json.getAsJsonObject().getAsJsonArray("test"), int[].class); 
    } 
} 

и затем:

Gson gson = new GsonBuilder().registerTypeAdapter(int[].class, new ArrayDeserializer()).create(); 
int[] arr = gson.fromJson(json, int[].class); 

, который бросает:

Exception in thread "main" com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Not a JSON Object: [0,3] 

Однако, когда я делаю это:

class ArrayDeserializer implements JsonDeserializer<int[]> { 

    private static final Gson gson = new Gson(); 

    @Override 
    public int[] deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { 
     return gson.fromJson(json.getAsJsonObject().getAsJsonArray("test"), int[].class); 
    } 
} 

это работает, и я получаю ожидаемый результат. Зачем?

ответ

3

Давайте перепишем ваш ArrayDeserializer в к эквивалентной форме, но более выразительного

class ArrayDeserializer implements JsonDeserializer<int[]> { 
    @Override 
    public int[] deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { 
     JsonArray jsonArray = json.getAsJsonObject().getAsJsonArray("test"); 
     return context.deserialize(jsonArray, int[].class); 
    } 
} 

В JsonDeserializationContext#deserialize Javadoc состояния

вызывающих десериализации по умолчанию на указанном объекте. Он должен никогда не вызываться на элементе, полученном в качестве параметра метода JsonDeserializer.deserialize(JsonElement, Type, JsonDeserializationContext). Это приведет к бесконечному циклу , так как Gson в свою очередь снова вызовет пользовательский десериализатор .

Так что, даже если бы это сработало, у вас, скорее всего, был бы стековый поток на ваших руках.

Так почему же это не сработало?

Вы назвали (в псевдокоде)

deserialize {test:[0,3]} as int[] 
// --> Gson finds ArrayDeserializer mapped to int[] 
take given JSON as an object (OK), extract 'test' as JSON array (OK) 
deserialize [0,3] as int[] 
// --> Gson finds ArrayDeserializer mapped to int[] 
take given JSON as an object (FAIL) 

Это последний раз, когда вы повторялись, то JSON уже в виде массива JSON, но ваш ArrayDeserializer ожидал объект JSON.

В вашей второй попытке

return gson.fromJson(json.getAsJsonObject().getAsJsonArray("test"), int[].class); 

вы снова извлекая массив JSON «теста» и подачи его на новый Gson экземпляр, на котором вы не зарегистрированы ваш ArrayDeserializer. В сущности, вы вызываете

new Gson().fromJson("[0,3]", int[].class); 

, которая поддерживается из коробки и возвращает int[] с двумя элементами 0 и 3, как и ожидалось.


Простые решения.

Определение простого типа POJO

class Pojo { 
    private int[] test; 
    public int[] getTest() { 
     return test; 
    } 
    public void setTest(int[] test) { 
     this.test = test; 
    } 
} 

и десериализации к нему

Pojo pojo = new Gson().fromJson(json, Pojo.class); 
int[] arr = pojo.getTest(); 

Или

Gson gson = new Gson(); 
JsonArray jsonArray = gson.toJsonTree(json).getAsJsonObject().get("test").getAsJsonArray(); 
int[] arr = gson.fromJson(jsonArray, int[].class); 
0

Ну, глядя на нужной версии класса ArrayDeserializer:

class ArrayDeserializer implements JsonDeserializer<int[]> { 
    @Override 
    public int[] deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { 
     return context.deserialize(json.getAsJsonObject().getAsJsonArray("test"), int[].class); 
    } 
} 

Внутри deserialize метод вы звоните снова deserialize, поэтому на второй вызов, вы будете не иметь массив ... то есть причина, почему у вас есть IllegalStateException.

Ваш метод должен создать массив int[] (с соответствующими преобразованиями), а затем вернуть его. Вот почему ваша вторая версия, с gson.fromJson работает, потому что fromJson десериализуется до int[]. Возможно, вы продолжаете использовать это, чтобы сделать работу по переработке грязи.

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