2015-04-05 7 views
1

ответов на REST API всегда возвращает JSON со следующей структурой:Deserialize ответа JSON с Gson, содержащим полем переменного типа

{ 
    "status": "<status_code>", 
    "data": <data_object> 
} 

Моей проблема заключается в том, что значение data не имеет уникальный тип, но это может быть String, JSON Object или JSON Array, в зависимости от вызываемой конечной точки. Я не могу понять, как десериализации его в правильном направлении, чтобы создать различные объекты Java ...

К примеру, я уже подготовил несколько POJO,: корневой элемент

public class ApiResult { 

    @SerializedName("status") 
    public String status; 

    @SerializedName("data") 
    public JsonElement data; // should I define it as a JsonElement?? 
} 

и два объекты, которые отражает две конечные точки:

// "data" can be a list of NavItems 
public class NavItem { 

    @SerializedName("id") 
    public String id; 

    @SerializedName("name") 
    public String name; 

    @SerializedName("icon") 
    public String icon; 

    @SuppressWarnings("serial") 
    public static class List extends ArrayList<NavItem> {} 
} 

и

// "data" can be a single object representing a Profile 
public class Profile { 

    @SerializedName("id") 
    public String id; 

    @SerializedName("fullname") 
    public String fullname; 

    @SerializedName("avatar") 
    public String avatar; 
} 

Чтение некоторые StackO вопросы, я видел, я должен использовать интерфейс JsonDeserializer<T>. Но как, если тип data в ApiResult является переменной?

+0

Если бы подобный вопрос [здесь] (http://stackoverflow.com/q/12450404/823393), но который использовал Джексон, и в данных были намеки на его структуру. – OldCurmudgeon

+0

На самом деле, я думаю, что понял это с помощью Gson, я отправлю ответ позже – TheUnexpected

ответ

0

мне удалось заставить его работать, как я хотел, и без использования каких-либо пользовательских десериализатор!

Для каждой конечной точки я жду ответа (кстати, я использую Volley), затем сначала создаю «корневой» объект ApiResult, проверяю, является ли состояние «ОК», а затем я создаю экземпляр поля данных в качестве запрошенного тип.

POJO - то же самое. В ApiResult «данные» - это JsonElement.

// ... called the endpoint that returns a NavItem list 
public void onResponse(String response) { 
    ApiResult rootResult = gson.fromJson(response.toString(), ApiResult.class); 
    if (rootResult.status.equals(STATUS_OK)) { 
     Log.d(LOG_TAG, response.toString()); 
     NavItem.List resData = gson.fromJson(rootResult.data, NavItem.List.class); // <-- !!!!! 
     callback.onSuccess(resData); 
    } 
    else { 
     Log.e(LOG_TAG, response.toString()); 
     callback.onError(-1, null); 
    } 
} 

Очевидно, что единственное, что нужно изменить на «Профиль» конечной точкой является линия с !!!!!

3

Вы должны использовать аа обычай JsonDeserializer и писать всю логику там, как этот

ApiResult.java

public class ApiResult { 

    @SerializedName("status") 
    public String status; 

    @SerializedName("data") 
    public Object data; 
} 

ApiResultDeserializer.java

import java.lang.reflect.Type; 
import java.util.List; 

import com.google.gson.JsonDeserializationContext; 
import com.google.gson.JsonDeserializer; 
import com.google.gson.JsonElement; 
import com.google.gson.JsonObject; 
import com.google.gson.JsonParseException; 
import com.google.gson.reflect.TypeToken; 


public class ApiResultDeserializer implements JsonDeserializer<ApiResult> { 

    private Type listType = new TypeToken<List<NavItem>>(){}.getType(); 

    @Override 
    public ApiResult deserialize(JsonElement value, Type type, 
      JsonDeserializationContext context) throws JsonParseException { 

     final JsonObject apiResultJson = value.getAsJsonObject(); 

     final ApiResult result = new ApiResult(); 
     result.status = apiResultJson.get("status").getAsString(); 

     JsonElement dataJson = apiResultJson.get("data"); 

     if(dataJson.isJsonObject()) { 
      result.data = context.deserialize(dataJson, NavItem.class); 
     } else if(dataJson.isJsonPrimitive()) { 
      result.data = context.deserialize(dataJson, String.class); 
     } else if(dataJson.isJsonArray()) { 
      result.data = context.deserialize(dataJson, listType); 
     } 

     return result; 
    } 

} 

и попытаться создавать различные виды data (), Object или String), как вы упомянули

Main.java

Gson gson = new GsonBuilder() 
     .registerTypeAdapter(ApiResult.class, new ApiResultDeserializer()) 
     .create(); 

     List<NavItem> navItems = new ArrayList<NavItem>(); 

     for(int i = 1 ; i < 6 ; ++i) { 
      navItems.add(new NavItem(i+"", "Name-" + i, "Icon-" + i)); 
     } 

     ApiResult result = new ApiResult(); 
     result.status = "OK"; 
     result.data = navItems; 

     // Serialization 
     System.out.println(gson.toJson(result)); // {\"status\":\"OK\",\"data\":[{\"id\":\"1\",\"name\":\"Name-1\",\"icon\":\"Icon-1\"},{\"id\":\"2\",\"name\":\"Name-2\",\"icon\":\"Icon-2\"},{\"id\":\"3\",\"name\":\"Name-3\",\"icon\":\"Icon-3\"},{\"id\":\"4\",\"name\":\"Name-4\",\"icon\":\"Icon-4\"},{\"id\":\"5\",\"name\":\"Name-5\",\"icon\":\"Icon-5\"}]} 

     result.data = navItems.get(0); 

     System.out.println(gson.toJson(result)); // {\"status\":\"OK\",\"data\":{\"id\":\"1\",\"name\":\"Name-1\",\"icon\":\"Icon-1\"}} 

     result.data = "Test"; 

     System.out.println(gson.toJson(result)); // {\"status\":\"OK\",\"data\":\"Test\"} 


     // Deserialization 
     String input = "{\"status\":\"OK\",\"data\":[{\"id\":\"1\",\"name\":\"Name-1\",\"icon\":\"Icon-1\"},{\"id\":\"2\",\"name\":\"Name-2\",\"icon\":\"Icon-2\"},{\"id\":\"3\",\"name\":\"Name-3\",\"icon\":\"Icon-3\"},{\"id\":\"4\",\"name\":\"Name-4\",\"icon\":\"Icon-4\"},{\"id\":\"5\",\"name\":\"Name-5\",\"icon\":\"Icon-5\"}]}"; 

     ApiResult newResult = gson.fromJson(input, ApiResult.class); 

     System.out.println(newResult.data); // Array 

     input = "{\"status\":\"OK\",\"data\":{\"id\":\"1\",\"name\":\"Name-1\",\"icon\":\"Icon-1\"}}"; 

     newResult = gson.fromJson(input, ApiResult.class); 

     System.out.println(newResult.data); // Object 

     input = "{\"status\":\"OK\",\"data\":\"Test\"}"; 

     newResult = gson.fromJson(input, ApiResult.class); 

     System.out.println(newResult.data); // String 
Смежные вопросы