Ошибка сериализации в gson при использовании только JsonDeserilization и @JsonAdapter - PullRequest
0 голосов
/ 21 января 2019

У меня проблема с Gson и полевыми аннотациями, касающимися сериализации при аннотировании @JsonAdapter и реализации только JsonDeserializer.

Например, у меня есть простой интерфейс и реализация

public interface IMyJob
{
  String getJobName();
  String getJobId();
}

public class MyJobImpl implements IMyJob
{
  final String jobName;
  final String jobId;

  public MyJobImpl(String jn, String ji)
  {
    this.jobName = jn;
    this.jobId = ji;
  }

  @Override
  public String getJobId()
  {
    return jobId;
  }

  @Override
  public String getJobName()
  {
    return jobName;
  }
}

Затем я хочу использовать этот интерфейс в другом классе:

public interface IStatus
{
  String getStatus();
  IMyJob getJob();
}
public class Status implements IStatus
{
  private final String status;
  private final IMyJob job;

  /* package */ Status(String status,
                 IMyJob job)
  {
    this.status = status;
    this.job = job;
  }

  @Override
  public String getStatus()
  {
    return status;
  }

  @Override
  public IMyJob getJob()
  {
    return job;
  }

  // really from a factory, but example for SO
  public static IStatus create(String status, IMyJob job)
  {
    return new Status(status, job);
  }
}

Я делаю простой тест в / из json:

IMyJob job = new MyJobImpl("Hello World", "123");
IStatus status = Status.create("Getting Warmer", job);
// To there
String json = new Gson().toJson(status);
// And back
// use builder so can later add the examples
GsonBuilder gb = new GsonBuilder();
IStatus chk = gb.create().fromJson(json, Status.class);

Без каких-либо изменений, я получаю(как и ожидалось) при выполнении to / from json

java.lang.RuntimeException: Невозможно вызвать конструктор без аргументов для интерфейса com.example.explore.IMyJob.Регистрация InstanceCreator в Gson для этого типа может решить эту проблему.
на com.google.gson.internal.ConstructorConstructor \ $ 14.construct (ConstructorConstructor.java:228)
на com.google.gson.internal.bind,internal.bind.ReflectiveTypeAdapterFactory $ Adapter.read (ReflectiveTypeAdapterFactory.java:222)
в com.google.gson.Gson.fromJson (Gson.java:927)
в com.google.gson.Gson.fromJson (Gson.java:892)
на com.google.gson.Gson.fromJson (Gson.java:841)
на com.google.gson.Gson.fromJson (Gson.java:813)
...

Поэтому я пишу простой десериализатор:

public class MyJobDeserializer
    implements JsonDeserializer<IMyJob>
{
 @Override
  public IMyJob deserialize(JsonElement json,
                            Type typeOfT,
                            JsonDeserializationContext context)
    throws JsonParseException
  {
    JsonObject jsonObj = json.getAsJsonObject();
    return new MyJobImpl(jsonObj.get("jobName").getAsString(),
        jsonObj.get("jobId").getAsString());
  }
}

И добавляю в GsonBuilder до вызова .fromJson(...):

JsonDeserializer<IMyJob> imyjobD = new MyJobDeserializer();
gb.registerTypeAdapter(IMyJob.class, imyjobD);

Иуспех!Пока все хорошо.

Javadocs gson 2.8.5 для состояния @ JsonAdapter :

Класс, на который ссылается эта аннотация, должен быть либо TypeAdapter или TypeAdapterFactory, или должны реализовывать одно или оба из JsonDeserializer или JsonSerializer.(выделение добавлено)

Итак, я удаляю JsonDeserializer из GsonBuilder и добавляю аннотацию в классе Status, так:

public class Status implements IStatus
{
  private final String status;

  @JsonAdapter(MyJobDeserializer.class)
  private final IMyJob job;
  ...

Но когда этот подход выполняетсязначения для объекта job не записываются в строку json при первом вызове.Таким образом, вывод из .toJson(...) выше дает такой вывод (информация о задании отсутствует):

{"status":"Getting Warmer","job":{}}

Я могу разрешить ситуацию, добавив JsonSerializer<IMyJob> в класс MyJobDeserializer, или , написав новый класс, который реализует TypeAdapter<IMyJob>.

Но javadocs, кажется, подразумевают, что я должен быть в состоянии передать класс, который просто реализует JsonDeserializer<IMyJob>.Поскольку я могу использовать только MyJobDeserializer с GsonBuilder.registerTypeAdapter(...), класс выглядит нормально.

Что я делаю не так?Было бы намного лучше использовать аннотации и стандартную сериализацию Gson.

Спасибо!

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