JSON-B ne déclare pas un moyen standard de sérialisation types polymorphes. Mais vous pouvez le réaliser manuellement en utilisant un sérialiseur et un désérialiseur personnalisés. Je vais l'expliquer sur un échantillon simple. Imaginez que vous ayez l'interface Shape
et deux classes Square
et Circle
l'implémentant.
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;
}
}
Vous devez sérialisation et la désérialisation Liste qui peut contenir des Shape
implémentations.
sérialisation fonctionne hors de la boîte:
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);
Le résultat sera:
[
{
"side": 2.0
},
{
"radius": 5.0
}
]
Il est ok, mais il ne fonctionnera pas si vous essayez de désérialiser. Lors de la désérialisation, JSON-B doit créer une instance de Square
ou Circle
et il n'y a aucune information sur le type d'objet dans le document JSON.
Pour le corriger, nous devons ajouter ces informations manuellement. Ici, les sérialiseurs et les désérialiseurs vont aider. Nous pouvons créer un sérialiseur qui met un type d'objet sérialisé dans un document JSON et un désérialiseur qui le lit et crée une instance appropriée. Il peut se faire comme ceci:
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.");
}
}
}
Maintenant, nous avons besoin de le brancher dans le moteur JSON-B et essayer sérialisation. Vous ne devez pas oublier de passer un type générique au moteur JSON-B pendant la sérialisation/désérialisation. Sinon, cela ne fonctionnera pas correctement.
// 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);
Le résultat de sérialisation sera:
[
{
"jsonb.sample.SerializerSample$Square": {
"side": 2.0
}
},
{
"jsonb.sample.SerializerSample$Circle": {
"radius": 5.0
}
}
]
Vous voyez ce type d'objet est ajouté par ShapeSerializer
. Maintenant, nous allons essayer de désérialiser et les résultats d'impression:
// Deserialize
List<SerializerSample.Shape> deserializedShapes = jsonb.fromJson(json, type);
// Print results
System.out.println("Deserialization:");
for (SerializerSample.Shape shape : deserializedShapes) {
System.out.println(shape);
}
Le résultat est:
Square[side=2.0]
Circle[radius=5.0]
Ainsi, il fonctionne parfaitement. J'espère que cela aide. :)
J'ai créé une [pullrequest] (https://github.com/eclipse/yasson/pull/64) sur Yasson, qui devrait résoudre ce problème. Vous pouvez regarder l'utilisation dans ImplementationClassTest et le commenter. – Bravehorsie