【问题标题】:Gson deserialize JSON array as ObjectGson 将 JSON 数组反序列化为 Object
【发布时间】:2015-07-23 11:38:39
【问题描述】:

我有一个对象,我需要从 JSON 中反序列化/解组(使用 Gson)。我的问题是我的 JavaBean 中的一个属性是一个复杂对象,但需要从一个 JSON 数字数组中序列化:

JSON 是(有点类似):

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

目标类是(类似于):

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
}

我的 GsonBuilder 配置为:

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

我的 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);
    }
}

但无济于事,因为我不断收到以下 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)

需要反序列化的两个类(包含 Location 实例的类和“包装”对象本身都是简单的 JavaBean(具有适当的 set'er 和 get'er 方法。

没有调用序列化、反序列化或读取的方法,所以我在这里做错了什么?

提前感谢您的帮助!

编辑 #1: 添加了目标类/bean 以阐明我试图反序列化到的对象图。

【问题讨论】:

  • 我不认为你需要一个特别的registerTypeAdapter。只需使用 StringList&lt;String&gt; 创建一个 Location.class
  • @jackk 我怀疑它是重复的——你所指的问题是关于整个响应是一个数组,而 Gson 反序列化机制是针对一个对象的。我的问题是关于解析对象的单个属性。

标签: java android json gson deserialization


【解决方案1】:

这是您需要对您编写的 JSON 进行 ser/des 处理的类:

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

而您编写的类将具有这样的 JSON:

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

最后,这是我对您的代码所做的测试,它运行良好!可能您只需要确保始终使用相同的 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());

【讨论】:

  • 抱歉,我忘记发布我的“目标”对象图了……我已经有了(所以我发布了更新)……不过,感谢您的反馈。
  • 对不起,但我真的想要一个(复杂)对象,而不是浮点数组,因为我的应用程序中的多个对象取决于我的 Location 类的行为。 Location 类也有 distanceTo 方法等(只是遵循健全的 OOP 原则)。
猜你喜欢
  • 1970-01-01
  • 2015-02-24
  • 2011-03-28
  • 1970-01-01
  • 2021-06-14
  • 1970-01-01
  • 1970-01-01
  • 2015-07-11
  • 2017-07-31
相关资源
最近更新 更多