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))
- Intenta invocar método de interfaz en una referencia de objeto nulo finishComposingText ()
- Java / Android: clases locales anónimas vs clases nombradas
- Android Studio en mac: no puedo encontrar el compilador del sistema
- StandardCharsets.UTF_8 en API inferior a 19
- Java.lang.IllegalStateException: Se esperaba BEGIN_ARRAY pero era BEGIN_OBJECT en la línea 1 de la columna 2
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?
- Cómo cambiar programatically Edittext Cursor Color en android?
- Forzar dirección de texto para LeadingMarginSpan2
- Bug con Android spinner en 2.2 relacionado con el arreglo de disposición
- Biblioteca FFT en android Sdk
- Dagger 2 "Dagger" prefijo componente no es capaz de compilar? Clase generada automáticamente
- Módulos gradol de Android con el mismo nombre
- Abrir un cuadro de diálogo de entrada en Android
- Cómo enviar una cookie junto con HttpGet en Java
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:
-
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 . -
Hay un error extraño en Gson 2.3.1 que podría causar un
StackOverflowError
durante la deserialización (probé el métodoTypeAdapter
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.
- ¿Cómo crear una vista que es más grande que la pantalla?
- Cómo convertir automáticamente if-else if statement to switch