简体   繁体   English

Google Gson 反序列化问题

[英]Google Gson issue with deserializing

I have a Java class:我有一个 Java 类:

public class Object1 {
    private int field1;
    private String field2;
    private Object2 object2;
    private boolean field3;
}

I've saved some Object1 instance as JSON string using Gson:我使用 Gson 将一些 Object1 实例保存为 JSON 字符串:

    String jsonString = new Gson().toJson(object1, Object1.class);

And then I added new String field to Object1 class:然后我向 Object1 类添加了新的 String 字段:

public class Object1 {
    private int field1;
    private String field2;
    private String field4;
    private Object2 object2;
    private boolean field3;
}

And now I can't to deserialize json string to Object1 instance using method:现在我无法使用方法将 json 字符串反序列化为 Object1 实例:

Object1 obj1 = new Gson().fromJson(jsonString, Object1.class);

Because of Gson throws exception:因为 Gson 抛出异常:

System.err: com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected a string but was BEGIN_OBJECT at line 1 column 444 path $.c at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:224) at com.google.gson.Gson.fromJson(Gson.java:887) at com.google.gson.Gson.fromJson(Gson.java:852) at com.google.gson.Gson.fromJson(Gson.java:801) at com.google.gson.Gson.fromJson(Gson.java:773) System.err: com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: 需要一个字符串,但在第 1 行第 444 列路径 $.c 处为 BEGIN_OBJECT,位于 com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read( ReflectiveTypeAdapterFactory.java:224) at com.google.gson.Gson.fromJson(Gson.java:887) at com.google.gson.Gson.fromJson(Gson.java:852) at com.google.gson.Gson.fromJson (Gson.java:801) 在 com.google.gson.Gson.fromJson(Gson.java:773)

But why?但为什么? I have JSON string without one field and it can't to be a problem.我有没有一个字段的 JSON 字符串,这不会成为问题。 Why I can't deserialize it?为什么我不能反序列化它?

Expected a string but was BEGIN_OBJECT

field4 in your json string is not of type String, use a Json to POJO generator to create a proper object. 您的json字符串中的field4不是String类型,请使用Json to POJO生成器来创建适当的对象。

I like to use http://www.jsonschema2pojo.org/ 我喜欢使用http://www.jsonschema2pojo.org/

@user523392 said: @ user523392说:

the member variables have to match exactly what is given in the JSON response 成员变量必须与JSON响应中给出的完全匹配

This is not the case. 不是这种情况。

There are a few options for specifying how Java field names map to JSON element names. 有一些选项可用于指定Java字段名称如何映射到JSON元素名称。

One solution that would work for the case in the original question above is to annotate the Java class members with the @SerializedName to very explicitly declare what JSON element name it maps to. 在上面原始问题中适用的一种解决方案是用@SerializedName注释Java类成员,以非常明确地声明其映射到的JSON元素名称。

// output: [MyObject: element=value1, elementTwo=value2]

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.annotations.SerializedName;

public class Foo
{
  static String jsonInput =
      "{" +
          "\"element\":\"value1\"," +
          "\"@element-two\":\"value2\"" +
      "}";

  public static void main(String[] args)
  {
    GsonBuilder gsonBuilder = new GsonBuilder();
    Gson gson = gsonBuilder.create();
    MyObject object = gson.fromJson(jsonInput, MyObject.class);
    System.out.println(object);
  }
}

class MyObject
{
  String element;

  @SerializedName("@element-two")
  String elementTwo;

  @Override
  public String toString()
  {
    return String.format(
        "[MyObject: element=%s, elementTwo=%s]",
        element, elementTwo);
  }
}

Another approach is to create a custom FieldNamingStrategy to specify how Java member names are translated to JSON element names. 另一种方法是创建自定义FieldNamingStrategy,以指定如何将Java成员名称转换为JSON元素名称。 This example would apply the same name mapping to all Java member names. 本示例将相同的名称映射应用于所有Java成员名称。 This approach would not work for the original example above, because not all of the JSON element names follow the same naming pattern -- they don't all start with '@' and some use camel case naming instead of separating name parts with '-'. 这种方法不适用于上面的原始示例,因为并非所有JSON元素名称都遵循相同的命名模式-它们并非都以'@'开头,并且有些使用驼峰式命名而不是使用'-来分隔名称部分”。 An instance of this FieldNamingStrategy would be used when building the Gson instance (gsonBuilder.setFieldNamingStrategy(new MyFieldNamingStrategy());). 构建Gson实例(gsonBuilder.setFieldNamingStrategy(new MyFieldNamingStrategy()))时,将使用此FieldNamingStrategy的实例。

class MyFieldNamingStrategy implements FieldNamingStrategy
{
  // Translates the field name into its JSON field name representation.
  @Override
  public String translateName(Field field)
  {
    String name = field.getName();
    StringBuilder translation = new StringBuilder();
    translation.append('@');
    for (int i = 0, length = name.length(); i < length; i++)
    {
      char c = name.charAt(i);
      if (Character.isUpperCase(c))
      {
        translation.append('-');
        c = Character.toLowerCase(c);
      }
      translation.append(c);
    }
    return translation.toString();
  }
}

Another approach to manage how Java field names map to JSON element names is to specify a FieldNamingPolicy when building the Gson instance, eg, gsonBuilder.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_DASHES);. 管理Java字段名称如何映射到JSON元素名称的另一种方法是在构建Gson实例时指定FieldNamingPolicy,例如gsonBuilder.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_DASHES);。 This also would not work with the original example, however, since it applies the same name mapping policy to all situations. 但是,这也不适用于原始示例,因为它将相同的名称映射策略应用于所有情况。

As it turned out problem was in obfuscation. 事实证明,问题在于混淆。

If you're not use @SerializedName annotation result JSON can be like that: 如果您不使用@SerializedName注释结果,JSON可能像这样:

{"a":3436213,"b":"some string","c":{.............},"d":true} {“ a”:3436213,“ b”:“某些字符串”,“ c”:{.............},“ d”:true}

We didn't use it because of it isn't DTO. 我们没有使用它,因为它不是DTO。 In this case we using JSON just to store some unimportant internal data. 在这种情况下,我们仅使用JSON来存储一些不重要的内部数据。 But it was very funny lesson for me. 但这对我来说是非常有趣的一课。

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

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