Gson десериализация списка <String> в realmList <RealmString>
Я использую модификацию с помощью gson для десериализации моего json в объекты сферы. Это работает очень хорошо по большей части. Проблемы возникают при работе с
RealmList (String (или любой другой базовый тип данных))
Так как Realm не поддерживает RealmList, где E не расширяет объект Realm, я завернул String в объект RealmObject.
public class RealmString extends RealmObject {
private String val;
public String getValue() {
return val;
}
public void setValue(String value) {
this.val = value;
}
}
Объект моего объекта ниже
public class RealmPerson extends RealmObject {
@PrimaryKey
private String userId;
...
private RealmList<RealmString> stringStuff;
private RealmList<SimpleRealmObj> otherStuff;
<setters and getters>
}
SimpleRealmObj отлично работает, поскольку он содержит только элементы String
public class SimpleRealmObj extends RealmObject {
private String foo;
private String bar;
...
}
Как я могу десериализовать stringStuff? Я попытался использовать gson TypeAdapter
public class RealmPersonAdapter extends TypeAdapter<RealmPerson> {
@Override
public void write(JsonWriter out, RealmPerson value) throws IOException {
out.beginObject();
Log.e("DBG " + value.getLastName(), "");
out.endObject();
}
@Override
public RealmPerson read(JsonReader in) throws IOException {
QLRealmPerson rList = new RealmPerson();
in.beginObject();
while (in.hasNext()) {
Log.e("DBG " + in.nextString(), "");
}
in.endObject();
return rList;
}
Однако я все еще попадал в IllegalStateException
2334-2334/com.qualcomm.qlearn.app E//PersonService.java: 71: main com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: ожидается строка, но была ИМЯ в строке 1 столбец 3 пути $.
Я попробовал RealmList, адаптер RealmString раньше безрезультатно.
Единственное обходное решение, которое мне удалось найти, - https://github.com/realm/realm-java/issues/620#issuecomment-66640786
Любые лучшие варианты?
Ответы
Ответ 1
Сообщение об ошибке "Expected a string but was NAME
" может быть разрешено путем извлечения имени объекта json в JsonReader
перед фактическим json-объектом (который является String
в вашем случае).
Вы можете посмотреть документацию для Android для JsonReader. Он содержит подробное объяснение и фрагмент кода. Вы также можете взглянуть на метод readMessage
в фрагменте кода примера в документации.
Я изменил ваш метод read
на то, что я думаю, что это должно быть. ПРИМЕЧАНИЕ: Я не тестировал код, поэтому в нем могут быть небольшие ошибки.
@Override
public RealmPerson read(JsonReader in) throws IOException {
RealmPerson rList = new RealmPerson();
in.beginObject();
String name = "";
while (in.hasNext()) {
name = in.nextName();
if (name.equals("userId")) {
String userId = in.nextString();
// update rList here
} else if (name.equals("otherStuff")) {
// since otherStuff is a RealmList of RealmStrings,
// your json data would be an array
// You would need to loop through the array to retrieve
// the json objects
in.beginArray();
while (in.hasNext()) {
// begin each object in the array
in.beginObject();
name = in.nextName();
// the RealmString object has just one property called "value"
// (according to the code snippet in your question)
if (name.equals("val")) {
String val = in.nextString();
// update rList here
} else {
in.skipValue();
}
in.endObject();
}
in.endArray();
} else {
in.skipValue();
}
}
in.endObject();
return rList;
}
Сообщите мне, если это поможет.
Ответ 2
Лучше использовать JsonSerializer
и JsonDeserializer
, а не TypeAdapter
для вашего RealmObject
, из-за 2 причины:
-
Они позволяют вам делегировать (де) сериализацию для вашего RealmObject
стандартным сериализатором Gson (de), что означает, что вам не нужно самостоятельно писать шаблон.
-
странная ошибка в Gson 2.3.1, которая может вызвать StackOverflowError
во время десериализации (я попробовал TypeAdapter
подходите к себе и сталкиваетесь с этой ошибкой).
Здесь (замените Tag
на ваш класс RealmObject
):
( ПРИМЕЧАНИЕ, что context.serialize
и context.deserialize
ниже эквивалентны gson.toJson
и gson.fromJson
, что означает, что нам не нужно самостоятельно анализировать класс Tag
.)
Parser + serializer для RealmList<Tag>
:
public class TagRealmListConverter implements JsonSerializer<RealmList<Tag>>,
JsonDeserializer<RealmList<Tag>> {
@Override
public JsonElement serialize(RealmList<Tag> src, Type typeOfSrc,
JsonSerializationContext context) {
JsonArray ja = new JsonArray();
for (Tag tag : src) {
ja.add(context.serialize(tag));
}
return ja;
}
@Override
public RealmList<Tag> deserialize(JsonElement json, Type typeOfT,
JsonDeserializationContext context)
throws JsonParseException {
RealmList<Tag> tags = new RealmList<>();
JsonArray ja = json.getAsJsonArray();
for (JsonElement je : ja) {
tags.add((Tag) context.deserialize(je, Tag.class));
}
return tags;
}
}
Класс тегов:
@RealmClass
public class Tag extends RealmObject {
private String value;
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
Затем зарегистрируйте свой класс конвертора с помощью Gson:
Gson gson = new GsonBuilder()
.registerTypeAdapter(new TypeToken<RealmList<Tag>>() {}.getType(),
new TagRealmListConverter())
.create();
Ответ 3
My gson typeAdapter был виновником.
Вышеприведенная ошибка рассматривалась как я не десериализовал json в RealmPerson правильно, первое поле не является строкой, следовательно
in.nextString()
был borking.
Я посмотрел на некоторый пример кода, и он ударил меня, мне не пришлось использовать
in.beginObject() и in.endObject()
для десериализации строки. Ниже приведен код.
public class QLRealmStringAdapter extends TypeAdapter<QLRealmString> {
@Override
public void write(JsonWriter out, QLRealmString value) throws IOException {
Log.e("DBG " + value.getValue(), "");
out.value(value.getValue());
}
@Override
public RealmString read(JsonReader in) throws IOException {
RealmString rString = new RealmString();
if (in.hasNext()) {
String nextStr = in.nextString();
System.out.println("DBG " + nextStr);
rString.setValue(nextStr);
}
return rString;
}
}
Надеюсь, это поможет кому-то.
Ответ 4
Мне нужен сериализатор джексона и десериализатор для преобразования Arraylist в RealmList