Json Gson绑定不起作用(异常对象/字符串)

时间:2012-04-07 14:02:42

标签: java android json gson

我在解析从数据库到Java(Android)应用程序获取的JSON时遇到了一些麻烦。我希望你能帮助我:

这是我拥有的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>

(这些名字不是我在这里写的那些:P)

我把所有这些都作为一个字符串(选中,确定),例如在一个名为responseString的变量中;

然后我尝试了所有可能的方法来进行转换但总是失败。我试图将它作为一个对象删除'['']',作为一个数组(我实现的东西但是这一行失败了):

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库不支持它?

好吧,我希望你能让我离开这里因为我疯了。

谢谢:)


不要使用日历,这是我的问题。相反,你可以使用日期,它的工作原理。另外,我不知道为什么,像“0”|“1”这样的布尔无法正常工作。喜欢“true”|“false”是的。

3 个答案:

答案 0 :(得分: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的日历。有人可能已经解决过了。祝你好运!

答案 1 :(得分:1)

问题是您正在尝试将数组反序列化为不是数组的类,并且由于显而易见的原因而无法工作。因为您知道数组类型只需使用MyClass []的任何实例来获取类。您可以随时创建一个。交替传递MyClass[].class(即MyClass.classMyClass[].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 + "]";
    }
}

答案 2 :(得分:0)

更新:我想添加以下内容作为评论,但它太长了。好吧,我想我知道是什么原因引起的。查看异常"Expected BEGIN_OBJECT but was BEGIN_ARRAY",这有两种方式中的一种,因为Gson会查看下一个值。 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上,也许你正在抓住一些特别是在那个环境中造成问题的东西。如果Date是一个问题,那么你可以将不可解析的日期作为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]

这里是类定义(删节)我甚至投入了一个布尔的grins)

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;
    ......

无论如何,这应该有用。

我正在使用最新的2.1版GSON。这可能是一个错误,因为它应该适合你。