web-dev-qa-db-ja.com

GSONとInstanceCreatorの問題

次のPOJOがあります。

public interface Shape {
    public double calcArea();
    public double calcPerimeter();
}

public class Rectangle implement Shape {
    // Various properties of a rectangle
}

public class Circle implements Shape {
    // Various properties of a circle
}

public class ShapeHolder {
    private List<Shape> shapes;

    // other stuff
}

GSONにShapeHolderのインスタンスをJSONにシリアル化しても問題ありません。しかし、そのJSONの文字列をShapeHolderインスタンスに逆シリアル化しようとすると、エラーが発生します。

String shapeHolderAsStr = getString();
ShapeHolder holder = gson.fromJson(shapeHodlderAsStr, ShapeHolder.class);

スロー:

Exception in thread "main" Java.lang.RuntimeException: Unable to invoke no-args constructor for interface    
net.myapp.Shape. Register an InstanceCreator with Gson for this type may fix this problem.
    at com.google.gson.internal.ConstructorConstructor$8.construct(ConstructorConstructor.Java:167)
    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.Java:162)
    ... rest of stack trace ommitted for brevity

それで、私は here を見て、自分のShapeInstanceCreatorを実装し始めました:

public class ShapeInstanceCreator implements InstanceCreator<Shape> {
    @Override
    public Shape createInstance(Type type) {
        // TODO: ???
        return null;
    }
}

しかし、今私は行き詰まっています:Java.lang.reflect.Type、しかし私は本当にJava.lang.Objectしたがって、次のようなコードを記述できます。

public class ShapeInstanceCreator implements InstanceCreator<Shape> {
    @Override
    public Shape createInstance(Type type) {
        Object obj = convertTypeToObject(type);

        if(obj instanceof Rectangle) {
            Rectangle r = (Rectangle)obj;
            return r;
        } else {
            Circle c = (Circle)obj;
            return c;
        }

        return null;
    }
}

私に何ができる?

更新

@raffianの提案(彼/彼女が投稿したリンク)に従って、私はInterfaceAdapterexactlyをリンクのように実装しました(私はしませんでした) 何も変更しない)。今、私は次の例外を得ています:

Exception in thread "main" com.google.gson.JsonParseException: no 'type' member found in what was expected to be an interface wrapper
    at net.myapp.InterfaceAdapter.get(InterfaceAdapter.Java:39)
    at net.myapp.InterfaceAdapter.deserialize(InterfaceAdapter.Java:23)

何か案は?

11
IAmYourFaja

this を見ましたか? InstanceCreatorsを実装するすてきな方法のように見えます。

私もGsonを使用していましたが、シリアル化の問題により FlexJSON に切り替えました。 Flexでは、インスタンス作成者は必要ありません。オブジェクトにJavaBean仕様に基づくすべてのフィールドのゲッター/セッターがあることを確認してください。

 ShapeHolder sh = new ShapeHolder();
 sh.addShape(new Rectangle());
 sh.addShape(new Circle());
 JSONSerializer ser = new JSONSerializer();
 String json = ser.deepSerialize(sh);
 JSONDeserializer<ShapeHolder> der = new JSONDeserializer<ShapeHolder>();
 ShapeHolder sh2 = der.deserialize(json);
9
raffian

FlexJSON は、以下のシリアル化時間のように、jsonの一部としてクラス名を追加することに注意してください。

{
    "HTTPStatus": "OK",
    "class": "com.XXX.YYY.HTTPViewResponse",
    "code": null,
    "outputContext": {
        "class": "com.XXX.YYY.ZZZ.OutputSuccessContext",
        "eligible": true
    }
}

したがって、JSONは扱いにくいものになります。しかし、GSONで必要なInstanceCreatorを書く必要はありません。

1