2016-12-01 5 views
0

Ich möchte Enum/Bit Flags von Json setzen. Ich habe es geschafft, mein Objekt mit einem HashSet mit meinen Enum-Werten zu serialisieren. Standardmäßig serialisiert LibGDX dies, fügt jedoch dem json ein Klassenfeld mit dem Typ des Satzes hinzu, damit es weiß, was zu tun ist. Ich möchte, dass meine Json sauber und von Java entkoppelt sein, damit ich diese Klasse schrieb:Deserialisieren von Enums als Flags verwenden

public class CriteriaSerializer implements Json.Serializer<HashSet> { 

    @Override 
    public void write(Json json, HashSet object, Class knownType) { 
     json.writeArrayStart(); 
     for (Object o : object) 
     { 
      if (o instanceof Modifier.Criteria) { 
       json.writeValue(o, Modifier.Criteria.class); 
      } 
     } 
     json.writeArrayEnd(); 
    } 

    @Override 
    public HashSet read(Json json, JsonValue jsonData, Class type) { 
     System.out.println("Running!?"); 
     HashSet<Modifier.Criteria> criteriaSet = new HashSet<Modifier.Criteria>(); 

     for (JsonValue entry = jsonData.child; entry != null; entry = entry.next) 
     { 
      criteriaSet.add(Modifier.Criteria.valueOf("ADD"));//Modifier.Criteria.valueOf(entry.asString())); 
     } 

     return criteriaSet; 
    } 
} 

Die Schreibmethode ergibt die folgende Ausgabe:

modifier: { 
    amount: 1 //Other field 
    criteriaSet: [ 
     RED 
     BLUE 
    ] 

Alles was ich brauche ist es, diese Werte als Zeichenfolgen zu erhalten so kann ich etwas in Richtung myCriteriaSet.put(Criteria.valueOf(output) tun. Die Sache ist, das Programm stürzt ab, bevor die Lese-Methode läuft. Ich vermute, das liegt daran, dass in den JSON-Daten ein ArrayList gefunden wird, aber das entsprechende Feld im Objekt ist ein HashSet. Dies ist der Fehler java.lang.IllegalArgumentException: Can not set java.util.Set field com.buckriderstudio.towercrawler.Creature.Modifier.criteriaSet to java.util.ArrayList

Sowohl schreiben und lesen von JSON ist mir wichtig, also brauche ich sie, um miteinander zu arbeiten. Am Ende bin ich nur auf der Suche nach einer sauberen Lösung, um EnumSet oder Bitkombinationen lesbar zu (de) serialisieren. Ich fühle, dass ich in der Nähe bin, aber es könnte eine bessere Technik geben als die, die ich versuche.

Was ich an der LibgDX Json-Implementierung gefällt, ist, dass Felder nicht obligatorisch sind und Standardwerte haben können. Dies räumt die JSON-Daten erheblich auf, da ich viele Felder habe, die optional eingestellt werden können. Deshalb hat diese Bibliothek meine Vorliebe, Jackson zu sagen, aber ich habe nicht so viel mit Jackson gespielt.

EDIT

Dies ist eine Bearbeitung vor allem für Andreas. Soweit ich weiß (aber ich könnte falsch liegen), hat das nichts mit dem eigentlichen Problem zu tun. Andreas erklärt mir, dass die Json-Syntax falsch ist, Tatsache ist, dass es nicht einmal meine read-Methode erreicht und dass die JSON-Bibliothek, die mit LibGDX ausgeliefert wird, nicht 100% korrektes Json schreibt. Muss es? Vielleicht um den Namen Json zu tragen? Muss es funktionieren? Ich denke nicht.

Hier ist mein Test. Alles, was ich mache, ist dieses Creature Objekt zu erstellen und es mit 1 Codezeile zu analysieren. Es gibt keinen persönlichen Code von mir, der dies analysiert.

Creature c = new Creature("MadMenyo"); 
System.out.println(json.prettyPrint(c)); 

//Output 

{ 
name: MadMenyo 
modifier: { 
    amount: 1 
    criteriaSet: { 
     class: java.util.HashSet 
     items: [ 
      VS_NATURE 
      MULTIPLY 
     ] 
    } 
} 
stats: { 
    ENDURANCE: { 
     abbreviation: END 
     displayName: Endurance 
     baseValue: 8 
     finalValue: 8 
    } 
    MAGIC: { 
     abbreviation: MP 
     displayName: Your mana 
     baseValue: 20 
     finalValue: 20 
    } 
    STRENGTH: { 
     baseValue: 6 
     finalValue: 6 
    } 
    HEALTH: { 
     abbreviation: HP 
     displayName: Your life 
     baseValue: 100 
     finalValue: 100 
    } 
} 
} 

//Looks like no valid Json to me. But the following line parses that correctly into a Creature object. 

Creature jsonCreature = json.fromJson(Creature.class, jsonCreature); 

Bevor wir noch weiter driften. Der Grund, warum ich das nicht verwenden möchte, ist, weil es die Klasse class: java.util.HashSet ausgibt, und ich bin ziemlich sicher, dass das unnötig ist.

EDIT

Nachdem Sie die folgenden Zeilen von Code hinzufügen konnte ich richtig json ausgegeben wird. Trotzdem bricht der Code immer noch ab, bevor es zu meiner benutzerdefinierten Lese-Methode kommt. Die Frage bleibt, wie man entweder ein Enumset oder ein anderes, das Enums auf eine andere Weise hält, repariert oder serialisiert, solange es in Json lesbar ist und als Flags verwendet werden kann.

JsonWriter jw = new JsonWriter(new StringWriter()); 
    json.setOutputType(JsonWriter.OutputType.json); 
    json.setWriter(jw); 

//Now outputs proper Json 

{ 
"name": "MadMenyo", 
"modifier": { 
    "amount": 1, 
    "criteriaSet": [ 
     "VS_NATURE", 
     "MULTIPLY" 
    ] 
}, 
"stats": { 
    "ENDURANCE": { 
     "abbreviation": "END", 
     "displayName": "Endurance", 
     "baseValue": 8, 
     "finalValue": 8 
    }, 
    "MAGIC": { 
     "abbreviation": "MP", 
     "displayName": "Your mana", 
     "baseValue": 20, 
     "finalValue": 20 
    }, 
    "STRENGTH": { 
     "baseValue": 6, 
     "finalValue": 6 
    }, 
    "HEALTH": { 
     "abbreviation": "HP", 
     "displayName": "Your life", 
     "baseValue": 100, 
     "finalValue": 100 
    } 
} 
+0

Das ist nicht gültig [JSON] (http://www.json.org/). Es fehlen 2 Kommas und die Array-Werte müssen in Anführungszeichen gesetzt werden. Bevor Sie weitermachen, stellen Sie sicher, dass Sie das Ergebnis verstehen, das Sie versuchen zu bekommen. – Andreas

+0

@Andreas Es ist was meine Schreibmethode ausgibt. Kann wirklich Kommas nicht beeinflussen und zitiert afaik. – Madmenyo

+0

Sie haben die write-Methode geschrieben, wenn Sie also das falsche Ergebnis erhalten, ist es Ihre Aufgabe, das Problem zu beheben. Sie sollten versuchen, Ihre Ausgabe zu testen, z. auf http://jsonlint.com/. Wenn es scheitert, machst du es falsch. Versuchen Sie nicht einmal, die 'read'-Methode zu testen, bis Sie ein gültiges JSON erhalten haben, was bedeutet, dass Ihre' write' Methode zuerst korrigiert werden muss. – Andreas

Antwort

0

Obwohl dies meine Frage nicht genau beantworten, da es abstürzt noch bevor es dem Leseverfahren bekommt, habe ich eine geeignete Arbeit um mit der Jackson Bibliothek gefunden. Ich habe herausgefunden, wie Sie Standardwerte ignorieren können, indem Sie die folgende Annotation für die zu serialisierende Klasse verwenden: . Das bringt mir genau die json-Ausgabe, wie ich es mit dem eingebauten json-Serializer versucht habe.Der einzige Nachteil ist die Geschwindigkeit, Jackson ist etwa 20-mal langsamer auf einem einzelnen Objekt, aber Schleifen, dass ein 1000-mal macht es "nur" etwa 5 mal langsamer.

Für alle, die nicht wissen, das ist, wie man Jackson mit Libgdx integrieren:

In build eine Abhängigkeit zu dem Kernprojekt hinzuzufügen.

compile group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.0.1' 

Starten der Analyse dauert nur ein paar Zeilen mehr.

ObjectMapper mapper = new ObjectMapper(); 
    //Add pretty print indentation 
    mapper.enable(SerializationFeature.INDENT_OUTPUT); 

    //When serializing we have to wrap it in a try/catch signature 
    try { 
     mapper.writeValue(Gdx.files.local("creature.json").file(), creature); 
    } catch (IOException e) { 
     e.printStackTrace(); 
    } 

    //To map it back to a object we do the same 
    Creature jsonCreature = null; 
    try { 
     jsonCreature = mapper.readValue(Gdx.files.local("creature.json").readString(), Creature.class); 
    } catch (IOException e) { 
     e.printStackTrace(); 
    } 

    //Jackson also has control over what you want to serialize 
    mapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY); 
    //Or with annotation in front of the class 
    @JsonIgnoreProperties({"nameOfProperty", "anotherProperty"}) 

Das alles zumindest gibt mir die gleiche Leistung wie die Build-in json Serializer und es serialisiert EnumSet rechts von der Fledermaus.

Wenn jemand weiß, wie ich meine Schreibmethode in der ersten Frage deserialisieren kann, werde ich froh sein, das als Antwort zu akzeptieren.

Verwandte Themen