Проблема Google Gson с десериализацией - PullRequest
0 голосов
/ 28 августа 2018

У меня есть класс Java:

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

Я сохранил некоторый экземпляр Object1 в виде строки JSON, используя Gson:

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

А затем я добавил новое поле String в класс Object1:

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

И теперь я не могу десериализовать строку json в экземпляр Object1, используя метод:

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

Из-за исключения Gson:

System.err: com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: ожидаемая строка, но была BEGIN_OBJECT в строке 1 столбца 444 пути $ .c на com.google.gson.internal.bind.ReflectiveTypeAdapterFactory $ Adapter.read (ReflectiveTypeAdapterFactory.java:224) на com.google.gson.Gson.fromJson (Gson.java:887) на com.google.gson.Gson.fromJson (Gson.java:852) на com.google.gson.Gson.fromJson (Gson.java:801) на com.google.gson.Gson.fromJson (Gson.java:773)

Но почему? У меня есть строка JSON без одного поля, и это не может быть проблемой. Почему я не могу десериализовать это?

Ответы [ 3 ]

0 голосов
/ 28 августа 2018

@ user523392 сказал:

переменные-члены должны точно соответствовать тому, что указано в ответе JSON

Это не тот случай.

Существует несколько опций для указания того, как имена полей Java отображаются на имена элементов JSON.

Одно из решений, которое подойдет для случая, описанного в предыдущем вопросе, состоит в том, чтобы аннотировать членов класса Java с помощью @SerializedName, чтобы очень явно объявить, с каким именем элемента 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);
  }
}

Другой подход заключается в создании настраиваемого FieldNamingStrategy для указания того, как имена элементов Java переводятся в имена элементов JSON. В этом примере будет применяться одно и то же сопоставление имен для всех имен членов Java. Этот подход не будет работать для приведенного выше исходного примера, потому что не все имена элементов JSON следуют одному и тому же шаблону именования - они не все начинаются с '@', и некоторые используют именование в случае верблюда вместо разделения частей имени с '- ». Экземпляр этого FieldNamingStrategy будет использоваться при создании экземпляра Gson (gsonBuilder.setFieldNamingStrategy (new MyFieldNamingStrategy ());).

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

Другой подход к управлению отображением имен полей Java на имена элементов JSON заключается в указании FieldNamingPolicy при создании экземпляра Gson, например, gsonBuilder.setFieldNamingPolicy (FieldNamingPolicy.LOWER_CASE_WITH_DASHES) ;. Однако это также не будет работать с исходным примером, поскольку оно применяет одну и ту же политику сопоставления имен для всех ситуаций.

0 голосов
/ 28 августа 2018

Как оказалось, проблема была в запутывании.

Если вы не используете аннотацию @SerializedName, JSON может выглядеть следующим образом:

{"a": 3436213, "b": "некоторая строка", "c": {.............}, "d": true}

Мы не использовали его, потому что это не DTO. В этом случае мы используем JSON просто для хранения неважных внутренних данных. Но это был очень забавный урок для меня.

0 голосов
/ 28 августа 2018

Expected a string but was BEGIN_OBJECT

field4 в вашей строке json не типа String, используйте генератор Json to POJO для создания правильного объекта.

Мне нравится использовать http://www.jsonschema2pojo.org/

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...