Gson deserialization List <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 Какие-нибудь лучшие варианты?

Solutions Collecting From Web of "Gson deserialization List <String> в realmList <RealmString>"

Сообщение об ошибке « 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; } 

Позвольте мне знать, если это помогает.

Лучше использовать JsonSerializer и JsonDeserializer вместо TypeAdapter для вашего RealmObject причинам:

  1. Они позволяют вам делегировать (де) сериализацию для вашего RealmObject в сериализатор по умолчанию Gson (de), что означает, что вам не нужно самостоятельно писать шаблон .

  2. В Gson 2.3.1 есть странная ошибка, которая может вызвать StackOverflowError во время десериализации (я сам TypeAdapter подход TypeAdapter и столкнулся с этой ошибкой).

Вот как (замените Tag своим классом RealmObject ):

( gson.toJson gson.fromJson , что 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(); 

Мой gson typeAdapter был виновником. Вышеприведенная ошибка была замечена как я не десериализовал json в RealmPerson правильно, первое поле не является строкой, следовательно

in.nextString ()

Был увязан.

Я посмотрел на примерный код, и он ударил меня, мне не пришлось использовать

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

}

Надеюсь, это поможет кому-то.