2016-03-03 6 views
8

Gegeben meine eigene Array-Implementierung MyArray<T>, wie kann ich es Jackson bekannt machen, so dass es aus einem JSON-Array in MyArray<T> deserialisieren kann? Bisher habe ich nur bin immer diese Ausnahme:Wie bekomme ich Jackson zur Deserialisierung in meine eigene Array-Implementierung

com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize instance of MyArray out of START_ARRAY token 
+8

zwischen diesen Arten transparente Konvertierung haben mehr Code, schreiben die 'MyArray' Klasse benötigt wird. – Dariusz

+0

Es ist LibGDX 'Array-Implementierung: https://github.com/libgdx/libgdx/blob/master/gdx/src/com/badlogic/gdx/utils/Array.java – tyrondis

+0

auch wo die Deserialisierung passieren vielleicht – valepu

Antwort

2

Wie Dariusz erwähnt, ist es gut, die Tatsache zu nutzen, dass Array Klasse Konstruktor akzeptiert normalen Array hat.

Schauen Sie, wenn Sie den Standard-Serializer verwenden - Ihr Array zu JSON serialisiert würde wie folgt aussehen:

{"items":["item1","item2"],"size":2,"ordered":true} 

es eindeutig eine Verschwendung von Platz ist, es sei denn, Sie size und ordered Felder wollen bewahrt werden.

Ich schlage vor, Sie ändern die Art, wie Sie Ihr Objekt serialisieren, so dass es mehr wie normale Array aussehen würde, auf der anderen Seite - Deserialisierung kann wieder Array Objekt erstellen.

Wenn Sie fügen folgende Paar Serializer und Deserializer:

SimpleModule module = new SimpleModule(); 
module.addDeserializer(Array.class, new StdDelegatingDeserializer<>(
    new StdConverter<Object[], Array>() { 
     @Override 
     public Array convert(Object[] value) { 
      return new Array(value); 
     } 
})); 

module.addSerializer(Array.class, new StdDelegatingSerializer(
    new StdConverter<Array, Object>() { 
     @Override 
     public Object convert(Array value) { 
      return value.toArray(); 
     } 
})); 

ObjectMapper mapper = new ObjectMapper(); 
mapper.registerModule(module); 

Sie

+0

Danke! Ich mag das am meisten. – tyrondis

2

Die Array-Klasse von Libgdx einen Konstruktor hat, die ein Array akzeptiert: public Array (T[] array).

Anstatt das libgdx-Array zu serialisieren, verwenden Sie eine einfache Klasse mit einem Array als Basis für die Serialisierung/Desrialisierung und erstellen dann ein libgdx-Array basierend auf den deserialisierten Daten.

Im Allgemeinen ist es eine gute Regel, nur POJO-Objekte zu serialisieren.

Kurz:

{ 
    //serialize: 
    com.badlogic.gdx.utils.Array<MyObj> arr = ...; 
    MyObj[] myArr = arr.toArray(); 
    MyCustomContainer cont = new MyCustomContainer(myArr); 
    String serializedData = mapper.writeValueAsString(cont); 
    // do sth with the data 
} 
{ 
    //deserialize 
    MyCusomContainer cont = mapper.readValue(..., MyCustomContainer.class); 
    com.badlogic.gdx.utils.Array<MyObj> arr = new com.badlogic.gdx.utils.Array<MyObj>(cont.getArray()); 
    // done! 
} 
+0

Das mache ich gerade, aber ich dachte, es wäre eleganter, das LibGDX-Array direkt zu verwenden, anstatt es hin und her zu konvertieren. – tyrondis

+1

Sie müssten den Code für libgdx Array ändern, ich denke - markieren Sie nur benutzerdefinierte Methoden für die Serialisierung mit entsprechenden Anmerkungen. Oder benutze einen XmlAdapter, ich denke, es funktioniert für Json, ich bin mir aber nicht sicher. – Dariusz

1

Eine Möglichkeit, zu tun, ist es eine Serializer wie

import java.io.IOException; 

import org.codehaus.jackson.JsonGenerationException; 
import org.codehaus.jackson.JsonGenerator; 
import org.codehaus.jackson.map.SerializerProvider; 
import org.codehaus.jackson.map.ser.std.SerializerBase; 

public class MyArraySerializer extends SerializerBase<MyArray> { 

    protected MyArraySerializer() { 
     super(MyArray.class); 
    } 

    @Override 
    public void serialize(MyArray myArray, JsonGenerator gen, SerializerProvider p) 
      throws IOException, JsonGenerationException { 
     gen.writeStartArray(); 
     Iterator<MyObject> it = myArray.iterator(); 
     while (it.hasNext()) { 
      MyObject ob = it.next(); 
      gen.writeObject(p); 
      if (it.hasNext()) { 
       gen.writeRaw(','); 
      } 
     } 
     gen.writeEndArray(); 
    } 
} 

Und ein Deserializer wie

import java.io.IOException; 

import org.codehaus.jackson.JsonParser; 
import org.codehaus.jackson.JsonProcessingException; 
import org.codehaus.jackson.map.DeserializationContext; 
import org.codehaus.jackson.map.JsonDeserializer; 

public class MyArrayDeserializer extends JsonDeserializer<MyArray> { 

    @Override 
    public MyArray deserialize(JsonParser parser, DeserializationContext ctx) 
      throws IOException, JsonProcessingException { 
     MyObject[] obs = parser.readValueAs(MyObject[].class); 
     return new MyArray(obs); //presuming you have a copy-constructor 
    } 
} 

Dann kommentieren die Eigenschaft zu schreiben, so hält ein Array mit @JsonSerialize(using = MyArraySerializer.class) @JsonDeserialize(using = MyArrayDeserializer.class).
Wenn Sie Ihre Array Implementierung direkt verwenden, statt in einer Container-Klasse hat diese Seite ein Beispiel, wie die Serialisierung-Handler zur Laufzeit http://wiki.fasterxml.com/JacksonHowToCustomSerializers

ich, dass in dieser Antwort beachten registrieren soll ich der Jackson 1.9 verwende API und das 2.x können etwas anders sein. Die auffälligsten Unterschiede sind laut http://wiki.fasterxml.com/JacksonUpgradeFrom19To20 die Änderungen in den Paketnamen und wo sich einige Klassen befinden. Ansonsten sollte dieser Code nicht betroffen sein.