2013-01-17 19 views
15

powraca Server takich częścią json:Cofnięcie json do klas

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

pisałem następny hierarchię klas:

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

Dodałem kolejne jackson adnotacji w nadziei deserializować json powyżej:

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

Oznakowałem odpowiednich konstruktorów jako @JsonCreator.

To nie działa dla klasy Expression.


Gdybym modyfikować json że każdy wyrażenie obiekt ma nazwę "ekspresja":

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

i

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

To nie próbując analizować "nie" warunek mówiąc, że "nie można utworzyć instancji klasy abstrakcyjnej, potrzebuję więcej informacji o typie". Wygląda na to, że traci deklarację adnotacji w głębszej analizie.


  1. Zastanawiam się, czy to możliwe, aby napisać deserializacji z jackson do oryginalnego json
  2. Dlaczego Drugie podejście nie działa Not deserializacji
+1

byłoby pomocne, jeśli pisał rzeczywistą hierarchię klas - powyższy kod nie wygląda to skompilować –

+1

kod zmodyfikowane do kodu Java. Pełne źródło znajduje się tutaj: https://github.com/emartynov/spil-games-assignment/tree/master/service-core/src/main/java/com/spilgames/core/condition –

+0

Popraw wiersze: __Not implementacja warunku__ do __Not implementacji warunku__ __public klasa i() extends__ do __public klasy i extends__ __public class lub() extends__ do __public klasy lub extends__ – Visruth

Odpowiedz

1

należy użyć klasy , a nie interfejs. W przeciwnym razie Jackson nie może utworzyć instancji.

Wierzę, że trzeba również utworzyć konstruktory domyślne (aka no-arg) dla POJO, aby Jackson działał.

Ponadto dobrym ogólnym podejściem do tworzenia mapowania Jacksona jest utworzenie instancji Javy twoich klas, a następnie utworzenie JSON z tego, Java -> JSON. Dzięki temu łatwiej zrozumieć, w jaki sposób mapowanie jest inne - przejście z JSON -> Java jest trudniejsza do debugowania.

+0

Tom, dziękuję za odpowiedź. Czy mógłbyś zaproponować hierarchię klas z powyższego przykładu json, który zostanie poprawnie zdekserializowany przez Jacksona? –

+0

Proszę o komentarz na pytanie proszę –

+0

Niestety - jestem w tej chwili bardzo zajęty. Sugerowałbym, aby na twoich zajęciach robić konstruktory bez argumentów jako pierwszy krok. Pracuj też od początku hierarchii w dół. Prosta klasa "Klasa publiczna Condtion {Map condition;}" powinna domyślnie odserializować, a następnie sprawdzić wynik i powoli dodać bardziej szczegółowe odwzorowania dla każdego elementu. –

18

Musiałem wykonać coś bardzo podobnego, oto fragment.

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

To może wydawać się trochę licznik intuicyjne użyciu interfejsu, ale udało mi się dostać to wszystko działa, mówiąc interfejs co klasa betonu do wykorzystania. Mam także inny fragment kodu w oddzielnym projekcie, który przesłania kod JsonSubTypes, aby utworzyć jego własny typ klas poniżej, jeśli to pomaga.

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

W tej klasie mogę analizować ten sam komunikat REST ale ja nadrzędnymi oryginalne projekty konkretnych typów i podtypów dla tego projektu sprawiają, że są one trwałe. Ponieważ nazwy typów są takie same, mogę przesłonić interfejs do tego typu obiektów. Należy pamiętać, że korzystam z właściwości @class, ale jest to całkowicie dowolne, może być przy każdej adnotacji, ale musi być zgodne po obu stronach. Nie używa się adnotacji 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, dziękuję za odpowiedź. Mógłbyś podać swój przykład jsona lub spojrzeć na mój? To prawie działa mój kod, ale z pewnymi modyfikacjami json. –

Powiązane problemy