2017-09-05 27 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インターフェイスと2つのクラス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; 
    } 
} 

Shapeの実装を含むListを直列化および逆直列化する必要があります。

シリアル化は、箱から出して動作します:

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ドキュメントに配置し、デシリアライザを使用してそれを読み込んで適切なインスタンスを作成します。

これで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

情報ありがとうございます。しかし、私たちの場合はまだ動作しません。各インタフェースの実装は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になります。 @デビッドあなたはすでにこの問題を解決しましたか? –

関連する問題