Given my own array implementation MyArray<T>
, how can I make it known to Jackson, so that it is able to deserialize from a JSON Array into MyArray<T>
? So far I am only getting this exception:
com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize instance of MyArray out of START_ARRAY token
As Dariusz mentioned, it's good to take advantage of the fact that Array
class has constructor accepting normal array.
Look, if you use default serializer - your array serialized to JSON would look like:
{"items":["item1","item2"],"size":2,"ordered":true}
it's clearly a waste of space, unless you want size
and ordered
fields to be preserved.
I suggest you changing the way you serialize your object so that it would look more like normal array, on the other end - deserialization can build Array
object again.
If you add following pair of serializer and 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);
you will have transparent conversion between these types
The Array class from libgdx has a constructor which accepts an array: public Array (T[] array)
.
Instead of trying to serialize libgdx array use a simple class with an array as a base for serialization/desrialization, and then create a libgdx array based on the deserialized data.
In general it is a good rule to serialize only POJO-type objects.
In short:
{
//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!
}
One way to do it is to write a serializer like
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();
}
}
And a deserializer like
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
}
}
Then annotate the property that holds such an array with @JsonSerialize(using = MyArraySerializer.class) @JsonDeserialize(using = MyArrayDeserializer.class)
.
If you use your array implementation directly, instead of inside a container class, this page has an example of how to register serialization handlers at run-time http://wiki.fasterxml.com/JacksonHowToCustomSerializers
I should note that in this answer I am using the Jackson 1.9 API and the 2.x may be slightly different. According to http://wiki.fasterxml.com/JacksonUpgradeFrom19To20 the most noticeable differences are the changes in package names and where some classes are located. Otherwise this code should be unaffected.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With