2013-10-03 4 views
1

Я анализирую серверный ответ JSON с библиотекой GSON. Иногда ребята говорят мне: «Мы не можем указать тип переменной в JSON по какой-то причине» (старый php, они не знают, как это сделать и т. Д. И т. Д.). GSON любит сильную типизацию в своей объектной модели. Поэтому я не могу разобрать объект как String.GSON parsing неопределенный тип переменной

GSON ждать:

{ 
    "service":{ 
     "description":null, 
     "name":"Base", 
     "id":"4c7a90410529" 
    } 
} 

Но он получает (пустые данные):

"service": "" 

И я получаю

java.lang.IllegalStateException: Expected BEGIN_OBJECT but was STRING at line 1 column 1396 

Что является лучшей практикой для анализа такого ответа?

Другой вопрос: Как я могу построить объект, он может распознавать переменную Integer, которая время от времени возвращалась как Integer или String? Тот же вопрос на стороне сервера.

"data": "1" 

или

"data": 1 

Я знаю - мы должны использовать определенные типы в Java. Но иногда стоит сделать уступки,
Благодаря

EDIT: Мое решение основано на ответ Java разработчика.
Класс ServiceDeserializer десериализует каждый объект в зависимости от его внутреннего значения.

public class ServiceDeserializer implements JsonDeserializer<ServiceState>{ 

    @Override 
    public ServiceState deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { 

     String name = ""; 
     String uuid = ""; 
     String description = ""; 

     if (json.isJsonObject()) { 
      JsonObject obj = json.getAsJsonObject(); 

      if (!obj.get("name").isJsonNull()) { 
       name = obj.get("name").getAsString(); 
      } 
      if (!obj.get("uuid").isJsonNull()) { 
       uuid = obj.get("uuid").getAsString(); 
      } 
      if (!obj.get("description").isJsonNull()) { 
       description = obj.get("description").getAsString(); 
      } 
     } 
     return new ServiceState(name, uuid, description); 
    } 

} 

И мой конструктор GSON с адаптером типа для ServiceState.

Gson gson = new GsonBuilder() 
    .registerTypeAdapter(ServiceState.class, new ServiceDeserializer()) 
    .create(); 
+0

Можете ли вы разместить код, который вы используете для десериализации этой части JSON. – David

ответ

0

Если вы хотите придерживаться строго gson вы можете предоставить пользовательские deserializer. Поскольку мы знаем, что service является либо свойством базы json, либо встроено в некоторые другие property, мы можем использовать десериализатор для пошагового анализа нарушителей и обработки их соответственно.

public class MyJsonDeserializer implements JsonDeserializer<YourParsedData> { 

    @Override 
    public YourParsedData deserialize(final JsonElement je, final Type type, final JsonDeserialization Context jdc) throws JsonParseException 
    { 
     final JsonObject obj = je.getAsJsonObject(); //our original full json string 
     final JsonElement serviceElement = obj.get("service"); 


    //here we provide the functionality to handle the naughty element. It seems emtpy string is returned as a JsonPrimitive... so one option 
    if(serviceElement instanceOf JsonPrimitive) 
    { 
     //it was empty do something 
    } 

    return YourParsedData.create(); //provide the functionality to take in the parsed data 
    } 
} 

Обычай десериализатор будет называться следующим образом:

final Gson gson = new GsonBuilder().registerTypeAdapter(YourParsedData.class, new MyJsonDeserializer()).create(); 
gson.fromJson("{service: ''}", YourParsedData.class); 

я напечатал все это так, если я пропустил какой-то синтаксис мои извинения.

0

Ваш JSON является недействительным, и любом Json анализатор не сможет разобрать синтаксический неправильный JSON:

"service": { 
     "description": null, 
     "name": "Base", 
     "id": "4c7a90410529" 
    } 

должен быть заключен в фигурных скобках, как указано здесь:

{ 
    "service": { 
     "description": null, 
     "name": "Base", 
     "id": "4c7a90410529" 
    } 
} 
0

Структура json заключена в пределах {}. Ваш ответ, кажется, отсутствует. Вы можете вручную добавить { и } в начале и конце строки, чтобы превратить ее в действительную структуру json.

Как только это будет сделано, вы можете использовать Gson для правильного анализа вашего ответа json.

Какова наилучшая практика для анализа такого ответа?

Использовать достаточно хороший парсер Json. Этого более чем достаточно. И попробуйте иметь класс, представляющий ту же структуру, что и ответ, чтобы избежать разбора уровня ответов json по уровню вручную.

+0

благодарим вас за комментарий, моя вина - я предоставил только внутреннюю часть JSON. Но это не проблема. – dimetil

1

Вам необходимо очистить ответ JSON, прежде чем пытаться десериализовать его в свой объект Java Response. Вы можете использовать парсер Java org.json, чтобы убедиться, что объект service действительно существует и исправить его иначе.

String json = "{\"service\":{\r\n" + 
     " \"description\":null,\r\n" + 
     " \"name\":\"Base\",\r\n" + 
     " \"id\":\"4c7a90410529\"\r\n" + 
     "}}"; 
String json2 = "{\"service\":\"\"}"; 

JSONObject root = new JSONObject(json); 
// JSONObject root = new JSONObject(json2); 
if (root.optJSONObject("service") == null) { 
    root.put("service", new JSONObject()); 
} 

Gson gson = new Gson(); 
Response response = gson.fromJson(root.toString(), Response.class); 

System.out.println(response.getService()); 

Выход:

// for JSONObject root = new JSONObject(json); 
Service [id=4c7a90410529, name=Base, description=null] 

// for JSONObject root = new JSONObject(json2); 
Service [id=null, name=null, description=null] 

Во-вторых, Gson достаточно умен, чтобы делать простые преобразования, как String к Integer и т.д. Таким образом, десериализации такие JSON свойства не должны давать вам какие-либо проблемы.

System.out.println(gson.fromJson("10", Integer.class)); // 10 
System.out.println(gson.fromJson("\"20\"", Integer.class)); // 20 
Смежные вопросы