2017-09-05 15 views
3

我适应这个杰克逊代码:如何使用json-b反序列化接口?

@JsonDeserialize(as = EntityImpl.class) 
public interface Entity { ... } 

原始代码工作得很好,甚至嵌套的实体对象。

如何在新的json-b规范中做到这一点?我试过使用@JsonbTypeDeserializer,但

  1. 这真的是要走的路吗?它似乎缺乏指定类的简单性。
  2. 它似乎没有使用嵌套实体合作,这是我最大的问题:

    javax.json.bind.JsonbException:无法推断类型的解编为:实体

  3. 该注释在实体上未被拾取。我必须手动添加JsonbConfig :: withDeserializers。

这里是我的解串器代码:

public class EntityDeserializer implements JsonbDeserializer<Entity> { 

    @Override 
    public Entity deserialize(JsonParser parser, DeserializationContextdeserializationContext, Type runtimeType) { 
     Class<? extends Entity> entityClass = EntityImpl.class.asSubclass(Entity.class); 
     return deserializationContext.deserialize(entityClass, parser); 
    } 
} 

任何提示或帮助非常感谢:-)

+1

我已经在Yasson上创建了一个[pullrequest](https://github.com/eclipse/yasson/pull/64),它应该解决这个问题。您可以在ImplementationClassTest中查看使用情况并对其进行评论。 – Bravehorsie

回答

5

JSON-B不声明序列化多态类型的标准方法。但是您可以使用自定义串行器和解串器手动实现它。我会在一个简单的例子中解释它。

想象一下,你有Shape接口和两个类SquareCircle实现它。

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需要创建一个SquareCircle的实例,并且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] 

因此,它完美的作品。希望能帮助到你。 :)

+1

感谢您的信息。尽管如此,它仍然不适用于我们的情况。我们只有每个接口的一个实现。所以它不是真正的多态。 OTH,我们需要反序列化json中的嵌套接口。 JSON-B的参考实现似乎有问题。事实上。如果我们用一些具体类型替换类定义中的所有嵌套对象,它就会起作用。请参阅https://github.com/dAti/siren4j/blob/master/src/test/java/com/google/code/siren4j/converter/ReflectingConverterTest.java中的testToJsonThereAndBackEntity()和相应的解串器。 – David

+0

我面临同样的问题,我只是想配置Jsonb实例来返回我想要解析的接口的具体实现。我试着用一个包含'return ctx.deserialize(CustomerImpl.class,parser)'的JsonbDeserializer;'但是它会导致stackoverflow。 @David是否已经解决了这个问题? –

相关问题