Server returns such part of 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"
}
}
]
}
]
}}
I wrote next classes hierarchy:
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) {
}
}
I've added next jackson annotations in hope to deserialize JSON above:
@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=""),
})
I marked appropriate constructors as @JsonCreator
.
This doesn't work for Expression
class.
If I modify JSON that every expression
object has the name "expression":
"expression" : {
"operand": "a",
"operator": "==",
"value": "true"
}
And
@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"),
})
It fails when trying to parse "not" condition saying that "can't instantiate abstract class need more information about type". So looks like it loses annotations declaration in deeper parsing.
I wonder if it's possible to write deserialization with jackson for original JSON
Why second approach doesn't work for Not
deserialization
To deserialize the string to a class object, you need to write a custom method to construct the object. You can add a static method to ImageLabelCollection inside of which you construct Label objects from the loaded JSON dictionary and then assign them as a list to the class variable bbox.
Deserialization is transforming the data from a file or stream back into an object to be used in your application. This can be binary data or structured data like JSON and XML. Deserialization is the opposite of serialization, which transforms objects into byte streams or structured text.
Serialization & Deserialization Python and the JSON module is working extremely well with dictionaries. For serializing and deserializing of JSON objects Python “__dict__” can be used. There is the __dict__ on any Python object, which is a dictionary used to store an object's (writable) attributes.
I had to accomplish something very similar, here is an excerpt.
@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();
}
This may seem kind of counter intuitive for using an interface but I was able to get this all working by telling the interface what concrete class to use. I also have another chunk of code in a separate project that overrides the JsonSubTypes
to instantiate it's own type of classes below, if this helps.
@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 this class I can parse the same REST message but I am overriding the original projects concrete types and the subtypes for this project make them persistent. Since the type names are the same I can override what interface to use for this object type. Please keep in mind that I am using the @class property but this is completely arbitrary could be @whatever annotation but it would need to match on both sides. This is not using the JsonTypeInfo.Id.Class
annotation.
@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);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With