假设我有一个用Java实现的参数化树,如下所示:
public class Tree<E> {
private static class Node {
E element;
List<Node> children.
}
Node root;
//... You get the idea.
}
这里的想法是上面的实现仅涉及树的拓扑结构,但是对实例化将存储在树中的元素一无所知。
现在,说我希望我的树元素成为地理位置。它们在树木中组织的原因是因为大陆包含国家,国家包含州或省,等等。为简单起见,地理位置具有名称和类型:
public class GeoElement { String name; String type; }
最后,地理层次结构如此:
public class Geography extends Tree<GeoElement> {}
现在到杰克逊序列化。假设Jackson序列化程序可以看到字段,则此实现的直接序列化将如下所示:
{
"root": {
"element": {
"name":"Latin America",
"type":"Continent"
}
"children": [
{
"element": {
"name":"Brazil",
"type":"Country"
},
"children": [
// ... A list of states in Brazil
]
},
{
"element": {
"name":"Argentina",
"type":"Country"
},
"children": [
// ... A list of states in Argentina
]
}
]
}
这种JSON渲染并不好,因为它包含来自Tree和Node类的不必要的工件,即“root”和“element”。我需要的是:
{
"name":"Latin America",
"type":"Continent"
"children": [
{
"name":"Brazil",
"type":"Country"
"children": [
// ... A list of states in Brazil
]
},
{
"name":"Argentina",
"type":"Country"
"children": [
// ... A list of states in Argentina
]
}
]
}
非常感谢任何帮助。 -Igor。
答案 0 :(得分:7)
您需要的是@JsonUnwrapped
。
用于指示属性应“ unwrapped”序列化的注释;也就是说,如果将其序列化为JSON对象,则其属性将作为其包含对象的属性包含在内
将此注释添加到root
类的Tree
和element
字段的Node
字段中,如下所示:
public class Tree<E> {
private static class Node {
@JsonUnwrapped
E element;
List<Node> children.
}
@JsonUnwrapped
Node root;
//... You get the idea.
}
它将为您提供所需的输出:
{
"name": "Latin America",
"type": "Continent",
"children": [{
"name": "Brazil",
"type": "Country",
"children": []
}, {
"name": "Argentina",
"type": "Country",
"children": []
}]
}
答案 1 :(得分:4)
也许像这样使用@JsonValue
:
public class Tree<E> {
@JsonValue
Node root;
}
如果你只需要“打开”你的树吗?
答案 2 :(得分:0)
您最好的选择是为您的对象构建并注册一个自定义序列化程序。
定义序列化器:
public class NodeSerializer extends StdSerializer<Node> {
然后在您的Node类上:
@JsonSerialize(using = NodeSerializer.class)
public class Node {
}
在NodeSerializer
@Override
public void serialize(
Node node, JsonGenerator jgen, SerializerProvider provider)
throws IOException, JsonProcessingException {
jgen.writeStartObject();
jgen.writeStringField("name", node.element.name);
jgen.writeStringField("type", node.element.type);
//Process children
serializeFields(node, jgen, provider);
jgen.writeEndObject();
}
此通用框架将让您控制元素的序列化方式。您可能还需要在@JsonIgnore
内部的element
对象Node
,因为您的自定义序列化程序会负责将这些信息推送到生成的JSON中。在线上有很多关于自定义序列化程序和覆盖默认JSON导出的信息。
对于Tree的实现,您可以使用序列化器以类似的方式摆脱根。
如果您不想在类上注册序列化程序,也可以使用ObjectMapper
一次一次进行:
ObjectMapper mapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
module.addSerializer(Node.class, new NodeSerializer());
mapper.registerModule(module);
String serialized = mapper.writeValueAsString(tree);
注释方法将在全球范围内应用。这种方法可以控制自定义序列化器的使用方式/位置。
答案 3 :(得分:-2)
要删除element
类型,一种可能是更改结构,以便名称和类型将直接包含在每个节点中:
public class TreeGeo {
private static class Node {
String name;
String type;
List<Node> children.
}
Node root;
}
要删除root
类型,我不知道。我想你可以从jsonObject中提取一个子对象,但我对Jackson不太了解。但是,你可以给它一个更好的名字,比如world
,或者操纵结果字符串,用一些字符串操作手动删除它。