JSON-B deklarieren keinen Standardweg von Serialisierung polymorphen Arten geschätzt helfen. Aber Sie können es manuell mit benutzerdefinierten Serializer und Deserializer erreichen. Ich werde es an einer einfachen Probe erklären.
Stellen Sie sich vor, Sie haben Shape
Schnittstelle und zwei Klassen Square
und Circle
implementieren es.
public interface Shape {
double surface();
double perimeter();
}
public static class Square implements Shape {
private double side;
public Square() {
}
public Square(double side) {
this.side = side;
}
public double getSide() {
return side;
}
public void setSide(double side) {
this.side = side;
}
@Override
public String toString() {
return String.format("Square[side=%s]", side);
}
@Override
public double surface() {
return side * side;
}
@Override
public double perimeter() {
return 4 * side;
}
}
public static class Circle implements Shape {
private double radius;
public Circle() {
}
public Circle(double radius) {
this.radius = radius;
}
public double getRadius() {
return radius;
}
public void setRadius(double radius) {
this.radius = radius;
}
@Override
public String toString() {
return String.format("Circle[radius=%s]", radius);
}
@Override
public double surface() {
return Math.PI * radius * radius;
}
@Override
public double perimeter() {
return 2 * Math.PI * radius;
}
}
Sie müssen serialisiert und deserialisiert Liste, die alle Shape
Implementierungen enthalten.
Serialisierung arbeitet aus der Box:
JsonbConfig config = new JsonbConfig().withFormatting(true);
Jsonb jsonb = JsonbBuilder.create(config);
// Create a sample list
List<SerializerSample.Shape> shapes = Arrays.asList(
new SerializerSample.Square(2),
new SerializerSample.Circle(5));
// Serialize
String json = jsonb.toJson(shapes);
System.out.println(json);
Das Ergebnis wird sein:
[
{
"side": 2.0
},
{
"radius": 5.0
}
]
Es ist in Ordnung, aber es wird nicht funktionieren, wenn Sie versuchen, es zu deserialisieren. Während der Deserialisierung muss JSON-B eine Instanz von Square
oder Circle
erstellen, und es gibt keine Informationen zum Objekttyp im JSON-Dokument.
Um es zu beheben, müssen wir diese Informationen dort manuell hinzufügen. Hier helfen Serialisierer und Deserialisierer. Wir können einen Serializer erstellen, der ein serialisiertes Objekt in JSON-Dokument und Deserializer einfügt, das es liest und eine richtige Instanz erstellt. Es kann wie folgt geschehen:
public static class ShapeSerializer implements JsonbSerializer<SerializerSample.Shape> {
@Override
public void serialize(SerializerSample.Shape shape, JsonGenerator generator, SerializationContext ctx) {
generator.writeStartObject();
ctx.serialize(shape.getClass().getName(), shape, generator);
generator.writeEnd();
}
}
public static class ShapeDeserializer implements JsonbDeserializer<SerializerSample.Shape> {
@Override
public SerializerSample.Shape deserialize(JsonParser parser, DeserializationContext ctx, Type rtType) {
parser.next();
String className = parser.getString();
parser.next();
try {
return ctx.deserialize(Class.forName(className).asSubclass(Shape.class), parser);
} catch (ClassNotFoundException e) {
e.printStackTrace();
throw new JsonbException("Cannot deserialize object.");
}
}
}
Jetzt müssen wir es in JSON-B Motor stecken und versuchen, Serialisierung. Sie sollten nicht vergessen, während der Serialisierung/Deserialisierung einen generischen Typ an die JSON-B-Engine zu übergeben. Sonst wird es nicht richtig funktionieren.
// Create JSONB engine with pretty output and custom serializer/deserializer
JsonbConfig config = new JsonbConfig()
.withFormatting(true)
.withSerializers(new SerializerSample.ShapeSerializer())
.withDeserializers(new SerializerSample.ShapeDeserializer());
Jsonb jsonb = JsonbBuilder.create(config);
// Create a sample list
List<SerializerSample.Shape> shapes = Arrays.asList(
new SerializerSample.Square(2),
new SerializerSample.Circle(5));
// Type of our list
Type type = new ArrayList<SerializerSample.Shape>() {}.getClass().getGenericSuperclass();
// Serialize
System.out.println("Serialization:");
String json = jsonb.toJson(shapes);
System.out.println(json);
Das Ergebnis der Serialisierung wird:
[
{
"jsonb.sample.SerializerSample$Square": {
"side": 2.0
}
},
{
"jsonb.sample.SerializerSample$Circle": {
"radius": 5.0
}
}
]
Sie sehen, dass Objekttyp von ShapeSerializer
hinzugefügt wird. Jetzt versuchen wir es und Druckergebnisse deserialisieren:
// Deserialize
List<SerializerSample.Shape> deserializedShapes = jsonb.fromJson(json, type);
// Print results
System.out.println("Deserialization:");
for (SerializerSample.Shape shape : deserializedShapes) {
System.out.println(shape);
}
Das Ergebnis ist:
Square[side=2.0]
Circle[radius=5.0]
So ist es perfekt funktioniert. Ich hoffe es hilft. :)
Ich habe eine [pullrequest] (https://github.com/eclipse/yasson/pull/64) auf Yasson erstellt, die dieses Problem beheben sollte. Sie können die Verwendung in ImplementationClassTest überprüfen und sie kommentieren. – Bravehorsie