web-dev-qa-db-ja.com

JSONをクラスに逆シリアル化します

サーバーはJSONのそのような部分を返します:

{"condition": {
    "or": [
        {
            "and": [
                {
                    "operand": "a",
                    "operator": "==",
                    "value": "true"
                },
                {
                    "not": {
                        "operand": "b",
                        "operator": "==",
                        "value": "true"
                    }
                }
            ]
        },
        {
            "and": [
                {
                    "operand": "b",
                    "operator": "==",
                    "value": "true"
                },
                {
                    "not": {
                        "operand": "a",
                        "operator": "==",
                        "value": "true"
                    }
                }
            ]
        }
    ]
}}

次のクラス階層を作成しました。

public interface Condition {}


public class Expression implements Condition { 
   public Expression(String operator, String operand, String value) {
   } 
}


public class Not implements Condition { 
   public Not(Condition condition) {
   }
}

public abstract class GroupOperation implements Condition {
   public GroupOperation (List<Condition> conditions) {
   }
}

public class And extends GroupOperation { 
   public And(List<Condition> conditions) {
   }
}

public class Or extends GroupOperation { 
   public Or(List<Condition> conditions) {
   }
}

上記のJSONを逆シリアル化することを期待して、次のjacksonアノテーションを追加しました。

@JsonTypeInfo(use=Id.NAME, include=As.WRAPPER_OBJECT)
@JsonSubTypes({
    @JsonSubTypes.Type(value=Not.class, name="not"),
    @JsonSubTypes.Type(value=And.class, name="and"),
    @JsonSubTypes.Type(value=Or.class, name="or"),
    @JsonSubTypes.Type(value=Expression.class, name=""),
})

適切なコンストラクターを@JsonCreatorとしてマークしました。

これはExpressionクラスでは機能しません。


すべてのexpressionオブジェクトの名前が「expression」であるJSONを変更すると、次のようになります。

"expression" : {
    "operand": "a",
    "operator": "==",
    "value": "true"
}

そして

@JsonTypeInfo(use=Id.NAME, include=As.WRAPPER_OBJECT)
@JsonSubTypes({
    @JsonSubTypes.Type(value=Not.class, name="not"),
    @JsonSubTypes.Type(value=And.class, name="and"),
    @JsonSubTypes.Type(value=Or.class, name="or"),
    @JsonSubTypes.Type(value=Expression.class, name="expression"),
})

「抽象クラスをインスタンス化できない」という条件を解析しようとすると失敗し、「型に関する詳細情報が必要です」と表示されます。したがって、より深い解析でアノテーション宣言が失われるように見えます。


  1. オリジナルのJSONのjacksonでデシリアライズを書くことは可能かしら

  2. 2番目のアプローチがNot逆シリアル化で機能しない理由

15
Eugen Martynov

私は非常に似たようなことを成し遂げなければなりませんでした、ここに抜粋があります。

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "@class")
@JsonSubTypes({
    @JsonSubTypes.Type(value=IMetricCollection.class, name="MetricCollection"),
    @JsonSubTypes.Type(value=IMetricDouble.class, name="MetricDouble"),
    @JsonSubTypes.Type(value=IMetricInteger.class, name="MetricInteger"),
    @JsonSubTypes.Type(value=IMetricPlot.class, name="MetricPlot"),
    @JsonSubTypes.Type(value=IMetricString.class, name="MetricString"),
    @JsonSubTypes.Type(value=IMetricMatrix.class, name="MetricMatrix")
})

public interface IMetric extends HasViolations<IViolation>, Serializable {

    /**
     * Getter for the name of the object.
     * 
     * @return
     */
    public abstract String getName();

    /**
     * Set the name of the object.
     * 
     * @param name
     */
    public abstract void setName(String name);

    /**
     * Returns true if metric has violations.
     * @return
     */
    public abstract boolean hasMetricViolations();
}

これは、インターフェイスを使用するのに直感に反するように思えるかもしれませんが、使用する具象クラスをインターフェイスに指示することで、これをすべて機能させることができました。また、別のプロジェクトに別のコードチャンクがあり、JsonSubTypesをオーバーライドして、以下の独自のタイプのクラスをインスタンス化します。

@JsonDeserialize(as=MetricMatrix.class)
public interface IMetricMatrix<C extends IColumn> extends IMetric {

    public static interface IColumn extends IMetricCollection<IMetric> {
    }

    public static interface IIntegerColumn extends IColumn {
    }

    public static interface IDoubleColumn extends IColumn {
    }

    public static interface IStringColumn extends IColumn {
    }


    public abstract List<C> getValue();

    public abstract void setValue(List<C> value);

    public abstract void addColumn(C column);
}

このクラスでは、同じRESTメッセージを解析できますが、元のプロジェクトの具象型をオーバーライドし、このプロジェクトのサブタイプはそれらを永続化します。型名は同じなので、どのインターフェイスをオーバーライドできますか?このオブジェクトタイプに使用します。@ classプロパティを使用していますが、これは完全に任意であり、@ whateverアノテーションである可能性がありますが、両側で一致する必要があることに注意してください。これはJsonTypeInfo.Id.Classアノテーションを使用していません。 。

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "@class")
@JsonSubTypes({
    @JsonSubTypes.Type(value=IMetricCollectionEntity.class, name="MetricCollection"),
    @JsonSubTypes.Type(value=IMetricDoubleEntity.class, name="MetricDouble"),
    @JsonSubTypes.Type(value=IMetricIntegerEntity.class, name="MetricInteger"),
    @JsonSubTypes.Type(value=IMetricPlotEntityEntity.class, name="MetricPlot"),
    @JsonSubTypes.Type(value=IMetricStringEntity.class, name="MetricString"),
    @JsonSubTypes.Type(value=IMetricMatrixEntity.class, name="MetricMatrix")
})
public interface IMetricEntity extends IDatastoreObject, IMetric {

    public String getContext();

    public List<IViolation> getViolations();
}



@JsonDeserialize(as=MetricMatrixEntity.class)
public interface IMetricMatrixEntity extends IMetricEntity {

    public static interface IColumnEntity extends IColumn {
        public String getName();
    }

    public static interface IIntegerColumnEntity extends IColumnEntity {
    }

    public static interface IDoubleColumnEntity extends IColumnEntity {
    }

    public static interface IStringColumnEntity extends IColumnEntity {
    }

    public abstract List<IColumnEntity> getValue();

    public abstract void setValue(List<IColumnEntity> value);

    public abstract void addColumn(IColumnEntity column);
}
18
Chris Hinshaw

インターフェイスではなく、クラスを使用する必要があります。そうしないと、Jacksonはインスタンスを作成できません。

Jacksonが機能するには、POJOのデフォルト(別名no-arg)コンストラクターも作成する必要があると思います。

また、Jacksonマッピングを作成するための一般的なアプローチとしては、クラスのJavaインスタンスをインスタンス化し、そこからJSONを作成するJava-> JSON 。これにより、マッピングがどのように異なるかを理解しやすくなります。JSONから移行する-> Javaはデバッグが困難です。

1
Tom Carchrae