2013-01-17 14 views
15

rendimenti Server, ad una parte di JSON:Deserialize JSON per classi

{"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" 
        } 
       } 
      ] 
     } 
    ] 
}} 

ho scritto classi prossimo gerarchia:

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) { 
    } 
} 

Ho aggiunto prossimi Jackson annotazioni in speranza deserializzare json sopra:

@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=""), 
}) 

Ho contrassegnato i costruttori appropriati come @JsonCreator.

Questo non funziona per la classe Expression.


Se modifico JSON che ogni espressione oggetto ha nome "espressione":

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

e

@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"), 
}) 

Non riesce quando si cerca di analizzare "non" condizione dicendo che "non è possibile istanziare una classe astratta per avere più informazioni sul tipo". Quindi sembra che perde la dichiarazione delle annotazioni in analisi più approfondite.


  1. Mi chiedo se è possibile scrivere deserializzazione con Jackson per originale JSON
  2. Perché secondo approccio non funziona per Not deserializzazione
+1

sarebbe utile se hai postato la gerarchia classe reale - il codice di cui sopra non sembra che sarebbe compilare –

+1

Codice modificato per essere codice Java. La fonte completa è qui: https://github.com/emartynov/spil-games-assignment/tree/master/service-core/src/main/java/com/spilgames/core/condition –

+0

Linee corrette di thess: __Non implementa Condition__ a __Not implementa Condition__ __public class E() estende __public class E extends__ __public class Or() ext__ a __public class O extends__ – Visruth

risposta

1

Si dovrebbe usare una classe , non un'interfaccia. Altrimenti, Jackson non può creare un'istanza.

Credo che sia necessario creare anche costruttori predefiniti (anche senza argomenti) per far funzionare i POJO per Jackson.

Inoltre, un buon approccio generale per la creazione di una mappatura Jackson è quello di creare un'istanza Java delle classi e quindi creare il JSON da quello, Java -> JSON. Questo rende molto più facile capire come la mappatura sia diversa - passando da JSON -> Java è più difficile eseguire il debug.

+0

Tom, grazie per la risposta. Potresti proporre una gerarchia di classi dall'esempio json sopra la quale verrà correttamente serializzata da Jackson? –

+0

Vedere il commento alla domanda per favore –

+0

Scusa - Sono molto occupato al momento. Suggerirei di fare costruttori no-arg alle tue lezioni come primo passo. Inoltre, lavora dalla parte superiore della gerarchia verso il basso. La semplice classe "Condtion di classe pubblica {Map condition;}" deve deserializzare per impostazione predefinita, quindi ispezionare il risultato e aggiungere lentamente mappature più specifiche per ciascun elemento. –

18

Ho dovuto realizzare qualcosa di molto simile, ecco un estratto.

@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(); 
} 

Questo può sembrare tipo di contatore intuitivo per l'utilizzo di un'interfaccia, ma sono stato in grado di ottenere tutto questo lavoro raccontando l'interfaccia che classe concreta da utilizzare. Ho anche un'altra porzione di codice in un progetto separato che sovrascrive lo JsonSubTypes per creare un'istanza del proprio tipo di classi qui sotto, se questo aiuta.

@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); 
} 

In questa classe posso analizzare lo stesso messaggio REST ma sto ignorando i progetti originali tipi concreti ed i sottotipi per questo progetto li rendono persistente. Poiché i nomi dei tipi sono gli stessi, è possibile sovrascrivere l'interfaccia da utilizzare per questo tipo di oggetto. Si prega di tenere presente che sto usando la proprietà @class ma questa è completamente arbitraria potrebbe essere annotazione @whatever, ma avrebbe bisogno di corrispondere su entrambi i lati. Questo non sta usando l'annotazione 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); 
} 
+0

Chris, grazie per la risposta. Potresti fornire il tuo esempio json o guardare il mio? Sta funzionando quasi il mio codice ma con alcune modifiche a JSON. –

Problemi correlati