JSON-B不聲明序列化多態類型的標準方法。但是您可以使用自定義串行器和解串器手動實現它。我會在一個簡單的例子中解釋它。
想象一下,你有Shape
接口和兩個類Square
和Circle
實現它。
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;
}
}
您需要序列化和反序列化List,其中可以包含任何Shape
實現。
連載作品開箱:
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);
結果將是:
[
{
"side": 2.0
},
{
"radius": 5.0
}
]
這是確定的,但如果你試圖反序列化將無法正常工作。在反序列化期間,JSON-B需要創建一個Square
或Circle
的實例,並且JSON文檔中沒有關於對象類型的信息。
爲了解決這個問題,我們需要在那裏手動添加這些信息。這裏序列化器和反序列化器將會有所幫助。我們可以創建一個序列化器,它將一種序列化對象放入JSON文檔和解串器中,該序列化器讀取它並創建一個適當的實例。它可以這樣做:
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.");
}
}
}
現在我們需要將它插入到JSON-B引擎並嘗試序列化。在序列化/反序列化過程中,您不應該忘記將通用類型傳遞給JSON-B引擎。否則它將無法正常工作。
// 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);
系列化的結果將是:
[
{
"jsonb.sample.SerializerSample$Square": {
"side": 2.0
}
},
{
"jsonb.sample.SerializerSample$Circle": {
"radius": 5.0
}
}
]
你看到該對象類型由ShapeSerializer
加入。現在,讓我們嘗試反序列化和打印結果:
// Deserialize
List<SerializerSample.Shape> deserializedShapes = jsonb.fromJson(json, type);
// Print results
System.out.println("Deserialization:");
for (SerializerSample.Shape shape : deserializedShapes) {
System.out.println(shape);
}
結果是:
Square[side=2.0]
Circle[radius=5.0]
因此,它完美的作品。希望能幫助到你。 :)
我已經在Yasson上創建了一個[pullrequest](https://github.com/eclipse/yasson/pull/64),它應該解決這個問題。您可以在ImplementationClassTest中查看使用情況並對其進行評論。 – Bravehorsie