java 将 JSON 反序列化为类
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/14378776/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Deserialize JSON to classes
提问by Eugen Martynov
Server returns such part of 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"
}
}
]
}
]
}}
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 Hymanson annotations in hope to deserialize JSON above:
我添加了下一个 Hymanson 注释,希望能反序列化上面的 JSON:
@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
.
我将适当的构造函数标记为@JsonCreator
.
This doesn't work for Expression
class.
这对Expression
课堂不起作用。
If I modify JSON that every expression
object has the name "expression":
如果我修改每个expression
对象都具有名称“表达式”的JSON :
"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.
当试图解析“not”条件时失败,说“无法实例化抽象类需要更多关于类型的信息”。所以看起来它在更深入的解析中丢失了注释声明。
I wonder if it's possible to write deserialization with Hymanson for original JSON
Why second approach doesn't work for
Not
deserialization
我想知道是否可以用Hymanson为原始JSON编写反序列化
为什么第二种方法不适用于
Not
反序列化
回答by Chris Hinshaw
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.
这对于使用接口来说似乎有点反直觉,但我能够通过告诉接口使用什么具体类来使这一切正常工作。我在一个单独的项目中还有另一块代码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);
}
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.
在这个类中,我可以解析相同的 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);
}
回答by Tom Carchrae
You should use a class, not an interface. Otherwise, Hymanson cannot create an instance.
您应该使用类,而不是接口。否则,Hymanson 无法创建实例。
I believe you also need to create default (aka no-arg) constructors for your POJOs for Hymanson to work.
我相信您还需要为您的 POJO 创建默认(又名无参数)构造函数,以便 Hymanson 工作。
Also, a good general approach for creating a Hymanson mapping is to instantiate a Java instance of your classes and then create the JSON from that, Java -> JSON. This makes it much easier to understand how the mapping is different - going from JSON -> Java is harder to debug.
此外,创建 Hymanson 映射的一个很好的通用方法是实例化类的 Java 实例,然后从中创建 JSON,Java -> JSON。这使得更容易理解映射的不同之处 - 从 JSON -> Java 更难调试。