У меня проблема с 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.
Спасибо!