Deserialización de Gson de List <String> en realmList <RealmString>

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

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

Dado que Realm no soporta RealmList donde E no extiende el objeto Realm, envuelve 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 como abajo

  public class RealmPerson extends RealmObject { @PrimaryKey private String userId; ... private RealmList<RealmString> stringStuff; private RealmList<SimpleRealmObj> otherStuff; <setters and getters> } 

SimpleRealmObj funciona bien ya que sólo tiene elementos String

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

¿Cómo puedo deserializar stringStuff? He intentado usar un 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; } 

Sin embargo todavía golpeé el IllegalStateException

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

Intenté RealmList, RealmString adaptador antes de nada. La única solución que logré encontrar hasta ahora es https://github.com/realm/realm-java/issues/620#issuecomment-66640786 ¿ Hay mejores opciones?

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

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

He modificado tu método de read a 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 utilizar JsonSerializer y JsonDeserializer lugar de TypeAdapter para su RealmObject , debido a dos razones:

  1. Le permiten delegar la serialización (de) de su RealmObject al serializador de Gson (de) predeterminado, lo que significa que no necesita escribir el boilerplate usted mismo .

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

Así es como (reemplace la 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.)

Parser + serializer para 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; } } 

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

A continuación, registre su clase de convertidor con Gson:

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

Mi gson typeAdapter fue el culpable. El error anterior fue visto como yo no estaba deserializando el json en RealmPerson correctamente, el primer campo no es una cadena, por lo tanto

In.nextString ()

Estaba borking.

Miré algún código de ejemplo y me golpeó, no tuve que usar

In.beginObject () y in.endObject ()

Para deserializar una cadena. El siguiente código funciona.

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

}

Espero que esto ayude a alguien.

  • Superpowered SDK Android
  • Android Studio - OpenJDK 1.8 Vs. Oracle JDK
  • Autenticación de Apache HttpClient Digest
  • Android - Obtiene el tipo MIME desde un archivo sin extensión
  • Cómo extraer el valor de la API
  • ¿Cómo obtener una diferencia de tiempo entre dos fechas en la aplicación para Android?
  • Facebook Login no funciona correctamente (Parse)
  • Android Studio v7- Errores de importación para pocas clases (No se puede resolver el símbolo)
  • Integración PayTm Payment Gateway Android
  • Los archivos múltiples dex definen <mi paquete> / BuildConfig, no pueden encontrar la causa:
  • Sabores de productos dependencia Android de Gradle
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.