2012-04-07 2 views
0

У меня возникли проблемы с разбором JSON, который я получаю из своей БД к моему приложению Java (Android). Я надеюсь, что вы можете помочь мне:Json Gson binding not working (Объект исключения/Строка)

Это Json, что у меня есть:

<br> 
[{<br> 
    "ID" : "1",<br> 
    "name" : "Test name",<br> 
    "type" : "1",<br> 
    "Desc" : "blablabla",<br> 
    "minNum" : "0",<br> 
    "maxNum" : "12",<br> 
    "Num" : "8",<br> 
    "bool1" : "0",<br> 
    "bool2" : "1",<br> 
    "bool3" : "1",<br> 
    "date" : "2012-04-01 23:00:00",<br> 
    "double1" : "39.47208",<br> 
    "doubl2" : "-0.3556063",<br> 
    "someText" : "ajayeah",<br> 
    "number" : "15",<br> 
    "anotherNumber" : "1234"<br> 
}, {"ID" : "2",<br> 
    "name" : "Test name",<br> 
    "type" : "1",<br> 
    "Desc" : "blablabla",<br> 
    "minNum" : "0",<br> 
    "maxNum" : "12",<br> 
    "Num" : "8",<br> 
    "bool1" : "0",<br> 
    "bool2" : "1",<br> 
    "bool3" : "1",<br> 
    "date" : "2012-04-01 23:00:00",<br> 
    "double1" : "39.47208",<br> 
    "doubl2" : "-0.3556063",<br> 
    "someText" : "ajayeah",<br> 
    "number" : "15",<br> 
    "anotherNumber" : "1234"<br> 
}]<br> 

(Имена ovbiously не те, которые я писал здесь: P)

У меня есть все, что, как Строка (отмечена, ОК), например, в переменной с именем responseString;

, а затем я пробовал все возможные способы сделать преобразование, но он всегда терпит неудачу. Я пытался получить его как объект удаления «[» «]», как Array (вещи, которые я достиг, а затем эта линия не может):

MyClassList MyClas = new Gson().fromJson(responseString, MyClassList.class); 

Ошибка:

com.google.gson.JsonSyntaxException: 
java.lang.IllegalStateException: Expected BEGIN_OBJECT but was BEGIN_ARRAY 

(с другими тестами, которые преобразуют его сначала в объект или массив, ошибка связана с BEGIN_STRING)

Может быть, потому, что я использую логические значения и тип календаря (в дате), и это не поддерживается библиотекой Gson?

Ну, надеюсь, вы можете убрать меня отсюда, потому что я схожу с ума.

Спасибо :)


Не используйте календарь, это была моя проблема. Вместо этого вы можете использовать Date, и он работает. Кроме того, я не знаю, почему, булевы типа «0» | «1» не работают. Как «true» | «false» да.

ответ

1

Проблема в том, что вы пытаетесь десериализовать массив в класс, который не является массивом, и это не будет работать по понятным причинам. Поскольку вы знаете тип массива, просто используйте любой экземпляр MyClass [], чтобы получить класс. Вы можете создать его в любое время. Поочередно проходят в MyClass[].class (т.е. MyClass.class не то же самое, как MyClass[].class)

Вот пример, который будет работать из коробки, если вы создаете файл log4j.properties (или преобразовать лесорубов в Системные выходы:

package com.techtrip.test; 

import java.io.Serializable; 

import org.slf4j.Logger; 
import org.slf4j.LoggerFactory; 

import com.google.gson.Gson; 

public class GsonTest { 

    private static Logger logger = LoggerFactory.getLogger(GsonTest.class); 

    static ToSerialize t1 = new ToSerialize("1", "Test 1"); 
    static ToSerialize t2 = new ToSerialize("2", "Test 2"); 

    static ToSerialize target[] = {t1,t2} ; 


    /** 
    * @param args 
    */ 
    public static void main(String[] args) { 
     // TODO Auto-generated method stub 

     Gson gson = new Gson(); 

     String jsonStr = gson.toJson(target); 

     logger.info(String.format("Target As String\n: %s", jsonStr)); 

     // This will work as well --> ToSerialize test[] = gson.fromJson(jsonStr, target.getClass()); 
     ToSerialize test[] = gson.fromJson(jsonStr, ToSerialize[].class); 

     for (ToSerialize deserialized: test){ 
      logger.info(String.format("From JSON\n: %s", deserialized.toString())); 
     } 
    } 

} 

class ToSerialize implements Serializable { 

    /** 
    * 
    */ 
    private static final long serialVersionUID = 1L; 


    private String iD; 
    private String name; 


    public ToSerialize() { 
     // TODO Auto-generated constructor stub 
    } 

    public ToSerialize(String iD, String name) { 
     super(); 
     this.iD = iD; 
     this.name = name; 
    } 

    public String getiD() { 
     return iD; 
    } 
    public void setiD(String iD) { 
     this.iD = iD; 
    } 
    public String getName() { 
     return name; 
    } 
    public void setName(String name) { 
     this.name = name; 
    } 
    @Override 
    public int hashCode() { 
     final int prime = 31; 
     int result = 1; 
     result = prime * result + ((iD == null) ? 0 : iD.hashCode()); 
     result = prime * result + ((name == null) ? 0 : name.hashCode()); 
     return result; 
    } 
    @Override 
    public boolean equals(Object obj) { 
     if (this == obj) 
      return true; 
     if (obj == null) 
      return false; 
     if (getClass() != obj.getClass()) 
      return false; 
     ToSerialize other = (ToSerialize) obj; 
     if (iD == null) { 
      if (other.iD != null) 
       return false; 
     } else if (!iD.equals(other.iD)) 
      return false; 
     if (name == null) { 
      if (other.name != null) 
       return false; 
     } else if (!name.equals(other.name)) 
      return false; 
     return true; 
    } 

    @Override 
    public String toString() { 
     return "ToSerialize [iD=" + iD + ", name=" + name + "]"; 
    } 
} 
+0

Боюсь, что это не сработало. Я получаю Json в String, хорошо сформированный как структура, которую я написал ранее, но делая это: MyClass test [] = gson.fromJson (responseString, MyClass []. Class); Не работает. Наконец-то я нахожу синтаксический анализатор самостоятельно, потому что, похоже, я не работаю так. Спасибо за ответ, хотя это не сработало для меня. – Sento

+0

Извините, глупый телефон отрезал мой ответ. Вы пытались сделать это inline, как в моем примере, и сравнить строки json? Вам не нужно писать собственный синтаксический анализатор, поскольку это может ограничивать совместимость. Возможно, чтобы даты были временными, мы удаляем их в качестве теста. – TechTrip

+0

Да, я нахожусь, но да. Структура Json одинакова (за исключением имен, но они соответствуют классу). Теперь я попытаюсь изменить дату Date Calendar и вырвать каждый странный персонаж (ú). Я скажу вам, что произошло за несколько минут – Sento

0

UPDATE: Я хотел добавить следующее в качестве комментария, но он слишком длинный. Ок, я думаю, что знаю, что вызывает это. Глядя на исключение "Expected BEGIN_OBJECT but was BEGIN_ARRAY", это происходит одним из двух способов, поскольку Гсэн заглядывает, чтобы получить следующее значение BEGIN_OBJECT представлен {, а BEGIN_ARRAY - [.

По какой-то причине анализатора для обработки вашей строки JSON, как будто она начинается следующим образом: "[[{\"ID\"

Это может произойти, когда приходишь через Javascript или что-то, что действительно является добавлением дополнительных скобок в попытке избежать его, как JSON когда это он уже находится в формате JSON.

Конечно, когда я изменить строку быть настроена именно таким образом я получаю:

Exception in thread "main" com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was BEGIN_ARRAY at line 1 column 3

Вы не отправлял все исключения, но я видел преобразования, как это произошло. Я опасаюсь, что вы напишете собственный парсер JSON, когда парсер не будет проблемой.

================ Оригинал ответа Ниже ===================

Я изменил мой оригинал класс, чтобы отразить вашу строку JSON, и она работает отлично. Я не на Android и, возможно, вы ловите что-то конкретное, чтобы вызвать проблемы в этой среде. Если датой была проблема, вы woild получите непроверяемую дату как исключение JSON, что имеет место в моей настройке, где "2012-04-01 23:00:00" терпит неудачу, но Apr 7, 2012 3:07:40 PM этого не делает.

Вот как это выглядит:

String testString = "[{\"ID\" : \"1\",\"name\" : \"Test name\",\"type\" : \"1\",\"Desc\" : \"blablabla\",\"minNum\" : \"0\",\"maxNum\" : \"12\",\"Num\" : \"8\",\"bool1\" : \"0\",\"bool2\" : \"1\",\"bool3\" : \"1\",\"date\" : \"Apr 7, 2012 3:07:40 PM\",\"double1\" : \"39.47208\",\"doubl2\" : \"-0.3556063\",\"someText\" : \"ajayeah\",\"number\" : \"15\",\"anotherNumber\" : \"1234\"}, {\"ID\" : \"2\",\"name\" : \"Test name\",\"type\" : \"1\",\"Desc\" : \"blablabla\",\"minNum\" : \"0\",\"maxNum\" : \"12\",\"Num\" : \"8\",\"bool1\" : \"0\",\"bool2\" : \"1\",\"bool3\" : \"1\",\"date\" : \"Apr 7, 2012 3:07:40 PM\",\"double1\" : \"39.47208\",\"doubl2\" : \"-0.3556063\",\"someText\" : \"ajayeah\",\"number\" : \"15\",\"anotherNumber\" : \"1234\"}]"; 

    ToSerialize test2[] = gson.fromJson(testString, ToSerialize[].class); 

    for (ToSerialize deserialized : test2) { 
     logger.info(String.format("From JSON\n: %s", 
       deserialized.toString())); 
    } 

Вот выход:

ToSerialize [ID=2, name=Test name, Desc=blablabla, minNum=0, maxNum=12, Num=8, bool1=false, bool2=false, bool3=false, date=Sat Apr 07 15:07:40 CDT 2012, double1=39.47208, doubl2=-0.3556063, someText=ajayeah, number=15, anotherNumber=1234] 

А вот определение класса (сокращенная) Я даже бросил в булевой для улыбок)

class ToSerialize { 
    int ID; 
    String name; 
    String Desc; 
    int minNum; 
    int maxNum; 
    int Num; 
    Boolean bool1; 
    boolean bool2; 
    boolean bool3; 
    Date date; 
    double double1; 
    double doubl2; 
    String someText; 
    int number; 
    int anotherNumber; 
    ...... 

По всем счетам это должно сработать.

Я использую последнюю версию GSON версии 2.1. Это может быть ошибка где-то, поскольку она должна работать для вас.

+0

Ive уже написал мой синтаксический анализатор, но я попытаюсь выяснить, может ли это решить проблему, с которой я столкнулся, и может помочь кому-то еще с этой проблемой. Я сообщу вам, как только закончу ваш новый ответ. Спасибо за ваше время, очень благодарен :) – Sento

+0

Я использую ту же версию, что и вы (2.1), скопировал свой ответ в мой проект, и он работает, хотя логическое значение должно быть определено как «true» | «false» not «0» | «1» Другое дело, что я использую Calendar, а не Date, и если я перехожу в «Календарь», это генерирует исключение (даже если я изменил формат с Json). Если я смогу решить, что я буду использовать его и на всякий случай сохранить свой собственный парсер. Я очень ценю вашу помощь, большое вам спасибо за ваше время и усилия. – Sento

+0

О, мужик, на эту тему есть так много. Как вы выяснили Даты с трудом справляются. Проблема идет между читаемой человеком формой, которая у вас есть, и машинным временем. У вас также нет часового пояса или видимой системы календаря в вашей строке. (Вот почему дата работает, хотя, вероятно, будет неправильной) Даты очень сложны. В весеннем мире я использую парсер Jackson JSON, который, как оказалось, имеет сериализатор DateTime для выполнения таких действий. Это не тривиально. См. Здесь, чтобы узнать, почему это такая сложная проблема: http://wiki.fasterxml.com/JacksonFAQDateHandling – TechTrip

2

Наконец, я знаю, что это мой третий ответ, но, как вы видите, проблема настолько сложна из-за календаря, что существует несколько ответов.

Использование GSON не будет работать из коробки. Я настоятельно рекомендую отказаться от Календаря и переехать в JODA по причинам, изложенным ранее.

Проблема, с которой вы имеете дело, является вопросом сериализации по датам. К счастью, GSON позволяет вам регистрировать специальные сериализаторы для этой цели (еще одна причина не использовать собственный синтаксический анализатор). Вы можете написать один для Календаря или искать тот, который уже был написан.

К счастью, это уже сделано для JODA DateTimes и предлагает синюю печать для тех из вас, кто хочет писать самостоятельно.

Смотрите здесь: https://sites.google.com/site/gson/gson-type-adapters-for-common-classes

Я реализовал это как так:

package com.techtrip.test; 

import java.lang.reflect.Type; 

import org.joda.time.DateTime; 

import com.google.gson.JsonDeserializationContext; 
import com.google.gson.JsonDeserializer; 
import com.google.gson.JsonElement; 
import com.google.gson.JsonParseException; 
import com.google.gson.JsonPrimitive; 
import com.google.gson.JsonSerializationContext; 
import com.google.gson.JsonSerializer; 

public class DateTimeTypeConverter implements JsonSerializer<DateTime>, JsonDeserializer<DateTime> { 
     // No need for an InstanceCreator since DateTime provides a no-args constructor 
     @Override 
     public JsonElement serialize(DateTime src, Type srcType, JsonSerializationContext context) { 
     return new JsonPrimitive(src.toString()); 
     } 
     @Override 
     public DateTime deserialize(JsonElement json, Type type, JsonDeserializationContext context) 
      throws JsonParseException { 
     return new DateTime(json.getAsString()); 
     } 
} 

совершенны, так что теперь все, что вам нужно сделать, это зарегистрировать его с застройщиком GSON и поместите его в качестве замены для вашего целевой класс (в данном случае DateTime.class). Таким образом, это будет сериализовать каждый DateTime, используя этот класс. Совершенно блестяще.

Вот как его использовать:

public static void main(String[] args) { 
    // TODO Auto-generated method stub 

    GsonBuilder gsonBuilder = new GsonBuilder(); 
    gsonBuilder.registerTypeAdapter(DateTime.class, new DateTimeTypeConverter()); 

    Gson gson = gsonBuilder.create(); 
    String jsonStr = gson.toJson(target); 

    logger.info(String.format("Target As String\n: %s", jsonStr)); 

    // This will work as well --> ToSerialize test[] = 
    // gson.fromJson(jsonStr, target.getClass()); 
    ToSerialize test[] = gson.fromJson(jsonStr, ToSerialize[].class); 

    for (ToSerialize deserialized : test) { 
     logger.info(String.format("From JSON\n: %s", 
       deserialized.toString())); 
    } 

    String testString = "[{\"ID\" : \"1\",\"name\" : \"Test name\",\"type\" : \"1\",\"Desc\" : \"blablabla\",\"minNum\" : \"0\",\"maxNum\" : \"12\",\"Num\" : \"8\",\"bool1\" : \"0\",\"bool2\" : \"1\",\"bool3\" : \"1\",\"date\" : \"2012-04-08T07:50:01.600-05:00\",\"double1\" : \"39.47208\",\"doubl2\" : \"-0.3556063\",\"someText\" : \"ajayeah\",\"number\" : \"15\",\"anotherNumber\" : \"1234\"}, {\"ID\" : \"2\",\"name\" : \"Test name\",\"type\" : \"1\",\"Desc\" : \"blablabla\",\"minNum\" : \"0\",\"maxNum\" : \"12\",\"Num\" : \"8\",\"bool1\" : \"0\",\"bool2\" : \"1\",\"bool3\" : \"1\",\"date\" : \"2012-04-08T07:50:01.600-05:00\",\"double1\" : \"39.47208\",\"doubl2\" : \"-0.3556063\",\"someText\" : \"ajayeah\",\"number\" : \"15\",\"anotherNumber\" : \"1234\"}]"; 

    ToSerialize test2[] = gson.fromJson(testString, ToSerialize[].class); 

    for (ToSerialize deserialized : test2) { 
     logger.info(String.format("From JSON\n: %s", 
       deserialized.toString())); 
    } 
} 

Есть некоторые предостережения, и вы должны понять это. Сначала вам нужно будет указать полный формат даты, например 2012-04-08T07:50:01.600-05:00.

Во-вторых, вам понадобится DateTimeFormatter, например, многие предоставленные JODA, чтобы распечатать их. Вы также можете получить Календарь из JODA, если хотите.

Я уверен, что с некоторыми работами это можно сделать и для Java-календаря. Кто-то, вероятно, уже справился с этим. Удачи!