Convertir json a objeto Map.Entry con Gson
VERSIÓN FÁCIL
Si le pido a Gson que convierta algún json válido en MyMap no tiene ningún problema para hacerlo
- Nullpointerexception al intentar obtener json array o json object de json string
- SDK de Android: Análisis de JSON de la URL mediante GSON
- Cómo probar si un JSONObject es nulo o no existe
- Renovación de la referencia $ ref de objeto deserializante de JSON a su copia original
- JSON Cadena devuelta desde el servicio web SOAP que no contiene registros para la tabla
public class MyMap{ Map<Long,String> content; } MyMap myMap = gson.fromJson(json, new TypeToken<MyMap>() {}.getType());
VERSIÓN DIFÍCIL:
¿Cómo obtengo que Gson haga lo siguiente?
public class MyDS{ Map<Map.Entry<Long,String>,Map<Long,String>> content; } MyDS myDS = gson.fromJson(json, new TypeToken<MyDS>() {}.getType());
Ejemplo json si realmente lo necesita.
"content": { "[1, dog]": { "1": "max", "2": "pi", "3": "robot", "4": "catcher", "5": "reaper" }, "[2, cat]": { "6": "black", "7": "white", "8": "meow", "9": "mice", "10": "rat" }, "[3, rabbit]": { "16": "bunny", "17": "ears", "28": "burgerbun", "39": "alice", "50": "tweak" } }
Más notas
Para una buena medida, intento ejecutar una prueba de unidad donde todo lo que hago es intentar leer el json con Gson, y consigo el rastro del error siguiente:
at sun.misc.Unsafe.allocateInstance(Native method) java.lang.reflect.Method.invoke!(Native method) com.google.gson.internal.UnsafeAllocator$1.newInstance(UnsafeAllocator.java:48) com.google.gson.internal.ConstructorConstructor$14.construct(ConstructorConstructor.java:223) com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:207) com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.read(TypeAdapterRuntimeTypeWrapper.java:40) com.google.gson.internal.bind.MapTypeAdapterFactory$Adapter.read(MapTypeAdapterFactory.java:186) com.google.gson.internal.bind.MapTypeAdapterFactory$Adapter.read(MapTypeAdapterFactory.java:145) com.google.gson.Gson.fromJson(Gson.java:861) com.google.gson.Gson.fromJson(Gson.java:826) com.google.gson.Gson.fromJson(Gson.java:775)
No importa si las teclas son de la forma "[3, rabbit]"
para "{3, rabbit}"
- ¿Cómo manejar parámetros que pueden ser ARRAY u OBJECT en Retrofit en Android?
- Diferentes formas de publicar valores json en Server
- Android Retrofit sin respuesta
- Cómo convertir HttpEntity en JSON?
- Conversión de JSONArray a matriz normal
- Cómo analizar los resultados de JSON de Unirest llamada
- Tipo de incompatibilidad de JSON o org.json.jsonecxeption
- Utilizar GSON para analizar un JSON con "clave" dinámica y "valor" en android
Suponiendo que tiene un contenido JSON
válido del tipo:
{ "content": { "[1, dog]": { "1": "max", "2": "pi", "3": "robot", "4": "catcher", "5": "reaper" }, "[2, cat]": { "6": "black", "7": "white", "8": "meow", "9": "mice", "10": "rat" }, "[3, rabbit]": { "16": "bunny", "17": "ears", "28": "burgerbun", "39": "alice", "50": "tweak" } } }
Para lograr lo que quieres, simplemente puedes implementar tu propio Map.Entry
Deserializer
ya que no se puede deserializar fuera de la caja porque no es una matriz y {3, rabbit}
no es un objeto JSON
válido.
Así que su Deserializer
podría confiar en una expresión regular para extraer la clave y el valor a continuación, crear una instancia de AbstractMap.SimpleEntry
utilizando los valores extraídos, algo así como:
public class MapEntryDeserializer implements JsonDeserializer<Map.Entry<Long, String>> { /** * Pattern corresponding to: * Starts with [ * <a non empty sequence of digit characters>, * <a non empty sequence of any characters * Ends with ] */ private static final Pattern PATTERN = Pattern.compile("^\\[(\\d+), ?(.+)\\]$"); public Map.Entry<Long, String> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { // Extract the key/value pair from Strings of type [3, rabbit] String value = json.getAsString(); Matcher matcher = PATTERN.matcher(value); if (!matcher.find()) { throw new JsonParseException( String.format("The map entry doesn't have the expected format: %s", value) ); } return new AbstractMap.SimpleEntry<>( Long.valueOf(matcher.group(1)), matcher.group(2) ); } }
Entonces puedo deserializar mi contenido de JSON
con:
Type type = new TypeToken<MyDS>() {}.getType(); Gson gson = new GsonBuilder() .registerTypeAdapter(Map.Entry.class, new MapEntryDeserializer()) .create(); MyDS myDS = gson.fromJson(json, type);
Según la documentación de Map.Entry:
La única manera de obtener una referencia a una entrada de mapa es del iterador de esta vista de colección.
https://docs.oracle.com/javase/8/docs/api/java/util/Map.Entry.html
Esto significa que no puede obtener Map.Entry hasta que haya creado el Mapa inicial. Para lograr lo que quieres, necesitas analizar el JSON en un Mapa, luego iterar sobre él para insertarlo en tu objeto MyDS.
Dicho esto, dependiendo de su uso final, podría haber mejores formas de reorganizar / introducir los datos después de analizarlos.
- E / S de archivo en un dispositivo de almacenamiento USB montado en modo host USB (Android 3.1 y versiones posteriores)
- Cómo responder automáticamente llamadas y reproducir sonido pregrabado a la persona que llama y DTMF en Android