Deserialización de Gson de List en realmList

Estoy usando retrofit con gson para deserializar mi json en objetos de reino. Esto funciona muy bien en su mayor parte. Surgen problemas cuando se trata de

RealmList (String (o cualquier otro tipo de datos básicos))

Como Realm no es compatible con RealmList, donde E no extiende el objeto Realm, envolví String en un RealmObject.

public class RealmString extends RealmObject { private String val; public String getValue() { return val; } public void setValue(String value) { this.val = value; } } 

Mi reino Objeto es el siguiente

  public class RealmPerson extends RealmObject { @PrimaryKey private String userId; ... private RealmList stringStuff; private RealmList otherStuff;  } 

SimpleRealmObj funciona bien, ya que solo tiene elementos de cadena

  public class SimpleRealmObj extends RealmObject { private String foo; private String bar; ... } 

¿Cómo puedo deserializar stringStuff? Intenté usar un TypeAdapter gson

 public class RealmPersonAdapter extends TypeAdapter { @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; } 

Sin embargo, todavía golpeo la IllegalStateException

2334-2334 / com.qualcomm.qlearn.app E // PersonService.java: 71: main com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Se esperaba una cadena pero era NAME en la línea 1 columna 3 ruta $.

Probé el adaptador RealmList, RealmString antes en vano. La única solución que logré encontrar hasta ahora es https://github.com/realm/realm-java/issues/620#issuecomment-66640786 ¿ Alguna mejor opción?

El mensaje de error ” Expected a string but was NAME ” se puede resolver recuperando el nombre del objeto json en JsonReader antes del objeto json real (que es una String en su caso).

Puede echar un vistazo a la documentación de Android para JsonReader . Tiene una explicación detallada y un fragmento de código. También puede echar un vistazo al método readMessage en el fragmento de código de muestra en la documentación.

He modificado tu método de read para lo que creo que debería ser. NOTA: No probé el código, por lo que puede haber algunos errores menores en él.

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

Déjeme saber si esto ayuda.

Es mejor usar JsonSerializer y JsonDeserializer lugar de TypeAdapter para su RealmObject , debido a 2 razones:

  1. Le permiten delegar (de) serialización para su RealmObject en el serializador Gson (de) predeterminado, lo que significa que no necesita escribir el texto repetitivo usted mismo .

  2. Hay un error extraño en Gson 2.3.1 que podría causar un StackOverflowError durante la deserialización ( TypeAdapter enfoque TypeAdapter y encontré este error).

Así es como (reemplace Tag con su clase RealmObject ):

( NOTA que context.serialize y context.deserialize continuación son equivalentes a gson.toJson y gson.fromJson , lo que significa que no necesitamos analizar la clase Tag nosotros mismos).

Analizador + serializador para RealmList :

 public class TagRealmListConverter implements JsonSerializer>, JsonDeserializer> { @Override public JsonElement serialize(RealmList src, Type typeOfSrc, JsonSerializationContext context) { JsonArray ja = new JsonArray(); for (Tag tag : src) { ja.add(context.serialize(tag)); } return ja; } @Override public RealmList deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { RealmList tags = new RealmList<>(); JsonArray ja = json.getAsJsonArray(); for (JsonElement je : ja) { tags.add((Tag) context.deserialize(je, Tag.class)); } return tags; } } 

Clase de etiqueta:

 @RealmClass public class Tag extends RealmObject { private String value; public String getValue() { return value; } public void setValue(String value) { this.value = value; } } 

Luego registre su clase de convertidor con Gson:

 Gson gson = new GsonBuilder() .registerTypeAdapter(new TypeToken>() {}.getType(), new TagRealmListConverter()) .create(); 

Mi adaptador de tipo gson fue el culpable. El error anterior se vio como que no deserializaba el json en RealmPerson correctamente, el primer campo no es una cadena, por lo tanto,

in.nextString ()

estaba borking.

Miré un código de ejemplo y me di cuenta, no tuve que usar

in.beginObject () y in.endObject ()

deserializar una Cadena. El siguiente código funciona.

 public class QLRealmStringAdapter extends TypeAdapter { @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; } 

}

Espero que esto ayude a alguien.

Necesito un serializador y deserializador de jackson para Converting Arraylist en RealmList