2016-11-15 4 views
8

EASY VERSIONConvert json zu Map.Entry Objekt mit Gson

Wenn ich frage Gson einige gültige Json konvertieren myMap es kein Problem hat es

public class MyMap{ 
    Map<Long,String> content; 
} 


MyMap myMap = gson.fromJson(json, new TypeToken<MyMap>() {}.getType()); 

HARD VERSION tun:

Wie Bekomme ich Gson, um folgendes zu tun?

public class MyDS{ 
    Map<Map.Entry<Long,String>,Map<Long,String>> content; 
} 

MyDS myDS = gson.fromJson(json, new TypeToken<MyDS>() {}.getType()); 

Beispiel json, wenn Sie es wirklich brauchen.

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

mehr Noten

Für eine gute Maßnahme, ich versuche, einen Komponententest zu laufen, wo alles, was ich versuche zu tun ist, um die json mit Gson zu lesen, und ich erhalte die folgende Fehlertrace:

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) 

Es spielt keine Rolle, wenn die Schlüssel der Form "[3, rabbit]" für "{3, rabbit}"

+0

Können Sie das Beispiel json für dieses zeigen? – notionquest

+1

Fixieren Sie Ihre Angebote. – shmosel

+0

Die Zitate sind nur so, weil ich in einen TextEditor einfügen. Aber es geht ihnen gut. Wie gesagt, es funktioniert, bis ich einen Eintrag für den Schlüssel brauche. –

Antwort

4

Unter der Annahme, dass Sie einen gültigJSON Inhalt des Typs haben:

{ 
    "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" 
     } 
    } 
} 

Um das zu erreichen, was Sie wollen, können Sie einfach Ihre eigenen implementieren Map.EntryDeserializer, da es nicht aus dem Kasten heraus deserialisiert werden kann, weil es kein Array und {3, rabbit} ist kein gültiges JSON Objekt.

So Ihre Deserializer auf einen regulären Ausdruck verlassen konnte den Schlüssel und der Wert dann eine Instanz von AbstractMap.SimpleEntry unter Verwendung der extrahierten Werte, so etwas wie zu extrahieren:

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

dann kann ich JSON Inhalt deserialisieren meinen mit:

Type type = new TypeToken<MyDS>() {}.getType(); 
Gson gson = new GsonBuilder() 
    .registerTypeAdapter(Map.Entry.class, new MapEntryDeserializer()) 
    .create(); 

MyDS myDS = gson.fromJson(json, type); 
+0

Schöne Lösung, ich bekomme nicht die zweite Gruppe der Regex '([^]] +)' Könnten Sie es bitte erklären? – AxelH

+2

@AxelH es bedeutet eine Sequenz von beliebigen Zeichen außer ']' –

+0

Ich denke, wir sind fast da. Aber ich bekomme immer den folgenden Fehler: "Der Karteneintrag hat nicht das erwartete Format: 1 = Hund" –

1

nach th sind e Dokumentation für Map.Entry:

The only way to obtain a reference to a map entry is from the iterator of this collection-view.

https://docs.oracle.com/javase/8/docs/api/java/util/Map.Entry.html

Dies bedeutet, dass Sie nicht die Map.Entry erhalten können, bis Sie die erste Map erstellt haben. Um zu erreichen, was Sie wollen, müssen Sie den JSON in eine Map einlesen und dann darüber iterieren, um sie in Ihr MyDS-Objekt einzufügen.

Nachdem dies gesagt wurde, könnte es je nach Endnutzung bessere Möglichkeiten geben, die Daten nach dem Parsen neu zu organisieren.

+0

Die Dokumentation bezieht sich auf die konventionelle Verwendung für Einträge in einer Map, aber nichts hindert Sie daran, eine Instanz von 'Map.Entry' zu erstellen, und es gibt sogar Utility-Implementierungen wie' AbstractMap.SimpleEntry' und 'AbstractMap.SimpleImmutableEntry' . – shmosel