我在解析从数据库到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”是的。
答案 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.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 + "]";
}
}
答案 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。这可能是一个错误,因为它应该适合你。