Gson错误:当Json有一张地图时JsonSyntaxException

时间:2015-07-29 15:59:10

标签: java json scala

我正在阅读一个Json字符串,并使用scala代码将其转换为对象:

function exportcsv(){
var tabledata = $('selectorJquery').DataTable();
var table = tabledata._('tr', {"filter": "applied"});
var columns = tabledata.dataTableSettings[0].aoColumns;
var tableString = "";

//Get the title headers and add to the first line of .csv
$.each(columns, function(i,v) { 
    tableString += v.sTitle+";";
    });
//Add line break and get the length of rows and the length of cols
tableString += "\r\n";
var rowLength = table.length;
var colLength = table[0].length;
//Iterate all rows and cols
for (var j = 0; j < rowLength; j++) {
    for (var k = 0; k < colLength; k++) {
        tableString += (k==colLength)  ?  table[j][k] : table[j][k]+";";
    }
    tableString += "\r\n";
}
  //Put the headers of file, application/csv and charset UTF-8 with BOM and the string with data rows
   csvData = 'data:application/csv;charset=utf-8,\uFEFF' + encodeURIComponent(tableString);
    var d = new Date();
     //Here I put in href attribute of a <a> HTML element and the .csv file starts to download automatically with name=yyyy-mm-dd_hh-mm-ss.csv
     $('selectorJquery').attr({
         'href': csvData,
         'target': '_blank',
         'download': d.getFullYear()+"-"+("0" + d.getMonth()).slice (-2)+"-"+("0" + d.getDate()).slice (-2)+"_"+("0" + d.getHours()).slice (-2)+"-"+("0" + d.getMinutes()).slice (-2)+"-"+("0" + d.getSeconds()).slice (-2)+'.csv'
     });
 }

}

在“myClass”类中添加哈希映射之前,一切正常。然后为以下Json输入(朋友是一个hashMap)

val myInstance = (new Gson()).fromJson(t, classOf[myClass])

然后我在“firstname”属性中收到以下错误,如下所示。有谁有想法吗?非常感谢你!

{"pId":"P:12345","name":"Dan Brown","friends":{"{\"firstname\":\"John\",\"lastname\":\"Smith\"}":1.0}}

这是myClass类:

15/07/29 08:43:05 ERROR Executor: Exception in task 0.0 in stage 0.0 (TID 0)
com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was STRING at line 1 column 51
    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:176)
    at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.read(TypeAdapterRuntimeTypeWrapper.java:40)
    at com.google.gson.internal.bind.MapTypeAdapterFactory$Adapter.read(MapTypeAdapterFactory.java:186)
    at com.google.gson.internal.bind.MapTypeAdapterFactory$Adapter.read(MapTypeAdapterFactory.java:145)

这是myName类:

public final class myClass extends implements Serializable {

    private static final long serialVersionUID = 11271827L;

    private String pId;
    private String name;
    private List<MyPet> pets = new ArrayList<MyPet>();
    private Map<MyName, Double> friends = new HashMap<MyName, Double>();
       :
   //some getter/setter here
}

2 个答案:

答案 0 :(得分:0)

在json中,map的键应该是string。在您的情况下,您使用MyName作为密钥。所以json解析器使用MyName#toString()转换为字符串。

我的建议是正确的MyName#toString()实现,并在MyName类中提供静态方法MyName valueOf(String)

例如:

class MyName{
    private String firstName;
    private String lastName;

    // getters and setters

    @Override
    public String toString(){
        return firstName+" "+lastName;
    }

    public static MyName valueOf(String str){
        int space = str.lastIndexOf(' ');
        if(space==-1)
            throw new IllegalArgumentException();
        MyName myName = new MyName();
        myName.setFirstName(str.subString(0, space));
        myName.setLastName(str.subString(space+1));
        return myName;
    }
}

此处valueOftoString实施应兼容。

上述代码假定lastName

中没有空格

答案 1 :(得分:0)

你在做什么是一个坏主意。不要在JSON名称中提供表示为String的复杂对象结构。

尽管如此,这仍然是一个解决方案。提供并注册自定义JsonDeserializer

Gson gson = new GsonBuilder().registerTypeAdapter(MyName.class, new KeyDeserializer()).create();
...
class KeyDeserializer implements JsonDeserializer<MyName> {
    private Gson gson = new Gson();

    @Override
    public MyName deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
        return gson.fromJson(json.getAsString(), MyName.class);
    }
}

JsonElement将包含JSON字符串(它将是JsonPrimitive)。在其上调用getAsString将返回Java String

{"firstname":"John","lastname":"Smith"}

然后,我们使用单独的Gson实例将其反序列化为具有默认行为的MyName实例。我们需要第二个Gson实例,因为原始实例已经注册KeyDeserializer进行自定义反序列化。