简体   繁体   English

Gson将JSON数组反序列化为Object

[英]Gson deserialize JSON array as Object

I've got an object, which I need deserialized / unmarshalled from JSON (using Gson). 我有一个对象,需要从JSON中反序列化/解组(使用Gson)。 My problem is that one of the properties, in my JavaBean, is a complex object, but needs to be serialized fron a JSON array of numbers: 我的问题是,JavaBean中的属性之一是一个复杂的对象,但需要从数字的JSON数组进行序列化:

The JSON is (somewhat similar to): JSON是(有点类似于):

{
    "name": "John Doe",
    "location": [
        9.560006,
        55.719474
    ],
}

The targeted classes are (somwaht similar to): 目标类是(类似于):

class UserLocation {
    private String name;
    private Location location;
    // ... "zero-args constructor", get'ers and set'ers
}
class Location {
    private double longitude;
    private double latitude;
    // ... "zero-args constructor", get'ers and set'ers
}

My GsonBuilder is configured as: 我的GsonBuilder配置为:

new GsonBuilder()
    .registerTypeAdapter(Location.class, new LocationTypeConverter())
    .create();

Where my LocationTypeConverter looks like this: 我的LocationTypeConverter如下所示:

public class LocationTypeConverter extends TypeAdapter<Location> implements JsonSerializer<Location>, JsonDeserializer<Location> {
    private static final int LONGITUDE_INDEX = 0;
    private static final int LATITUDE_INDEX = 1;

    @Override
    public JsonElement serialize(Location src, Type srcType, JsonSerializationContext context) {
        JsonArray array = new JsonArray();
        array.set(LATITUDE_INDEX, new JsonPrimitive(src.getLatitude()));
        array.set(LONGITUDE_INDEX, new JsonPrimitive(src.getLongitude()));
        return array;
    }

    @Override
    public Location deserialize(JsonElement json, Type type, JsonDeserializationContext context) throws JsonParseException {
        JsonArray array = json.getAsJsonArray();
        return new Location(array.get(LATITUDE_INDEX).getAsDouble(), array.get(LONGITUDE_INDEX).getAsDouble());
    }

    @Override
    public void write(JsonWriter out, Location value) throws IOException {
        out.beginArray().value(value.getLongitude()).value(value.getLatitude()).endArray();
    }

    @Override
    public Location read(JsonReader in) throws IOException {
        in.beginArray();
        double longitude = in.nextDouble();
        double latitude = in.nextDouble();
        in.endArray();
        return new Location(longitude, latitude);
    }
}

But to no avail, since I keep recieving the following Stacktrace: 但无济于事,因为我一直收到以下Stacktrace:

     retrofit.RetrofitError: com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was BEGIN_ARRAY at line 1 column 85 path $[0].location
            at retrofit.RestAdapter$RestHandler.invokeRequest(RestAdapter.java:377)
            at retrofit.RestAdapter$RestHandler.access$100(RestAdapter.java:220)
            at retrofit.RestAdapter$RestHandler$2.obtainResponse(RestAdapter.java:278)
            at retrofit.CallbackRunnable.run(CallbackRunnable.java:42)
            at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
            at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
            at retrofit.Platform$Android$2$1.run(Platform.java:142)
            at java.lang.Thread.run(Thread.java:818)
     Caused by: retrofit.converter.ConversionException: com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was BEGIN_ARRAY at line 1 column 85 path $[0].location
            at retrofit.converter.GsonConverter.fromBody(GsonConverter.java:67)
            at retrofit.RestAdapter$RestHandler.invokeRequest(RestAdapter.java:362)
            at retrofit.RestAdapter$RestHandler.access$100(RestAdapter.java:220)
            at retrofit.RestAdapter$RestHandler$2.obtainResponse(RestAdapter.java:278)
            at retrofit.CallbackRunnable.run(CallbackRunnable.java:42)
            at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
            at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
            at retrofit.Platform$Android$2$1.run(Platform.java:142)
            at java.lang.Thread.run(Thread.java:818)
     Caused by: com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was BEGIN_ARRAY at line 1 column 85 path $[0].location
            at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:200)
            at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.read(ReflectiveTypeAdapterFactory.java:103)
            at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:196)
            at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.read(TypeAdapterRuntimeTypeWrapper.java:40)
            at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.read(CollectionTypeAdapterFactory.java:81)
            at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.read(CollectionTypeAdapterFactory.java:60)
            at com.google.gson.Gson.fromJson(Gson.java:810)
            at com.google.gson.Gson.fromJson(Gson.java:775)
            at retrofit.converter.GsonConverter.fromBody(GsonConverter.java:63)
            at retrofit.RestAdapter$RestHandler.invokeRequest(RestAdapter.java:362)
            at retrofit.RestAdapter$RestHandler.access$100(RestAdapter.java:220)
            at retrofit.RestAdapter$RestHandler$2.obtainResponse(RestAdapter.java:278)
            at retrofit.CallbackRunnable.run(CallbackRunnable.java:42)
            at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
            at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
            at retrofit.Platform$Android$2$1.run(Platform.java:142)
            at java.lang.Thread.run(Thread.java:818)
     Caused by: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was BEGIN_ARRAY at line 1 column 85 path $[0].location
            at com.google.gson.stream.JsonReader.beginObject(JsonReader.java:387)
            at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:189)

The two classes that needs to be deserialized (the one containing the Location instance and the "wrapping" object itself are both simple JavaBean (with appropriate set'er and get'er methods. 需要反序列化的两个类(一个包含Location实例和“包装”对象本身的类)都是简单的JavaBean(具有适当的set'er和get'er方法)。

None of the methods serialize, deserialize nor read are being called, so what am I doing wrong here? 没有调用序列化,反序列化或读取的方法,所以我在这里做错了什么?

Thanks in advance, for your help! 在此先感谢您的帮助!

EDIT #1: Added target classses / beans to clarify the object graph I'm trying to deserialize to. 编辑#1:添加了目标类/ bean,以阐明我要反序列化的对象图。

This is the class that you need to ser/des the JSON that you wrote: 这是您需要Ser / des编写的JSON的类:

MyObject {
    public String name;
    public float[] location;

    public float getLatitude() {
        if (location != null) return location[0];
        return 0;
    }
    public float getLongitude() {
        if (location != null) return location[1];
        return 0;
    }
}

while the Classes that you wrote will have a JSON like this: 而您编写的类将具有以下JSON:

{
    "name": "John Doe",
    "location": {
        "longitude": 9.560006,
        "latitude": 55.719474
    }
}

And finally, this is the test I did with your code, and it works fine! 最后,这是我对您的代码所做的测试,并且工作正常! Probably you just need to be sure you're using always the same Gson object (the one you get from GsonBuilder.create)? 也许您只需要确保始终使用相同的Gson对象(从GsonBuilder.create获得的对象)?

    Gson gson = new GsonBuilder()
            .registerTypeAdapter(Location.class, new LocationTypeConverter())
            .setPrettyPrinting()
            .create();

    UserLocation userLocation = new UserLocation();
    userLocation.name = "ciao";
    userLocation.location = new Location(1.0, 3.0);
    String json = gson.toJson(userLocation);
    System.out.println(json);

    UserLocation newlocation = gson.fromJson(json, UserLocation.class);
    System.out.print(newlocation.location.getLatitude());

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM