SnakeYAML:以不同的方式创建一些对象
SnakeYAML: Creating some objects differently
我无法更改程序中的以下 class 结构:
class Node {
public String name;
}
class Nodes {
public List<Node> nodes;
}
class Master {
public Nodes nodes;
}
我可以使用下面的 YAML 来初始化它:
master:
nodes:
nodes:
- name: test
SnakeYaml 是否有可能用某种自定义对象实例化逻辑省略第一个 "nodes:",以便我的客户可以只使用以下 YAML?
master:
nodes:
- name: test
我尝试使用自定义构造函数实现,但没有成功:
class MyConstructor extends Constructor {
MyConstructor() {
yamlClassConstructors.put(NodeId.mapping, new NodesConstructor());
}
class NodesConstructor extends Constructor.ConstructMapping {
@Override
protected Object constructJavaBean2ndStep(MappingNode node, Object object) {
Class type = node.getType();
if (type.equals(Master.class)) {
Nodes nodes = new Nodes();
//FIXME: I don't want to construct the whole object tree here, I only want to fill the nodes
nodes.nodes = new ArrayList<>();
Master master = new Master();
master.nodes = nodes;
return master;
} else {
return super.constructJavaBean2ndStep(node, object);
}
}
}
}
最后,这就是我喜欢开始工作的方式:
class MyDsl {
public Master master;
}
public class SnakeYaml {
public static void main(String[] args) throws IOException {
// 1: this is working OK
Yaml yaml = new Yaml();
MyDsl myDsl = yaml.loadAs("master:\n nodes:\n nodes:\n - name: mystage", MyDsl.class);
if(!myDsl.master.nodes.nodes.get(0).name.equals("mystage")) {
throw new AssertionError("Failed with nested nodes");
}
// 2: this is how I need it
Yaml yaml2 = new Yaml(new MyConstructor());
MyDsl myDsl2 = yaml2.loadAs("master:\n nodes:\n - name: mystage", MyDsl.class);
if(!myDsl2.master.nodes.nodes.get(0).name.equals("mystage")) {
throw new AssertionError("Failed with leaving out nodes");
}
}
}
有什么想法吗?提前致谢。
我最终解决这个问题的方法是手动转换底层映射,将其转储为字符串并使用我的 DSL 包装器再次加载它 class:
Yaml yaml2 = new Yaml();
Map map = yaml2.loadAs("master:\n nodes:\n - name: mystage", Map.class);
Map master = (Map) map.get("master");
List nodes = (List) master.get("nodes");
Map newNodes = new HashMap();
newNodes.put("nodes", nodes);
master.put("nodes", newNodes);
String modifiedDsl = yaml.dump(map);
MyDsl myDsl2 = yaml2.loadAs(modifiedDsl, MyDsl.class);
可能不是最漂亮的解决方案,但它确实有效。仍然开放的是如何在另一个方向使用它(为 DSL 对象生成 YAML)。
我无法更改程序中的以下 class 结构:
class Node {
public String name;
}
class Nodes {
public List<Node> nodes;
}
class Master {
public Nodes nodes;
}
我可以使用下面的 YAML 来初始化它:
master:
nodes:
nodes:
- name: test
SnakeYaml 是否有可能用某种自定义对象实例化逻辑省略第一个 "nodes:",以便我的客户可以只使用以下 YAML?
master:
nodes:
- name: test
我尝试使用自定义构造函数实现,但没有成功:
class MyConstructor extends Constructor {
MyConstructor() {
yamlClassConstructors.put(NodeId.mapping, new NodesConstructor());
}
class NodesConstructor extends Constructor.ConstructMapping {
@Override
protected Object constructJavaBean2ndStep(MappingNode node, Object object) {
Class type = node.getType();
if (type.equals(Master.class)) {
Nodes nodes = new Nodes();
//FIXME: I don't want to construct the whole object tree here, I only want to fill the nodes
nodes.nodes = new ArrayList<>();
Master master = new Master();
master.nodes = nodes;
return master;
} else {
return super.constructJavaBean2ndStep(node, object);
}
}
}
}
最后,这就是我喜欢开始工作的方式:
class MyDsl {
public Master master;
}
public class SnakeYaml {
public static void main(String[] args) throws IOException {
// 1: this is working OK
Yaml yaml = new Yaml();
MyDsl myDsl = yaml.loadAs("master:\n nodes:\n nodes:\n - name: mystage", MyDsl.class);
if(!myDsl.master.nodes.nodes.get(0).name.equals("mystage")) {
throw new AssertionError("Failed with nested nodes");
}
// 2: this is how I need it
Yaml yaml2 = new Yaml(new MyConstructor());
MyDsl myDsl2 = yaml2.loadAs("master:\n nodes:\n - name: mystage", MyDsl.class);
if(!myDsl2.master.nodes.nodes.get(0).name.equals("mystage")) {
throw new AssertionError("Failed with leaving out nodes");
}
}
}
有什么想法吗?提前致谢。
我最终解决这个问题的方法是手动转换底层映射,将其转储为字符串并使用我的 DSL 包装器再次加载它 class:
Yaml yaml2 = new Yaml();
Map map = yaml2.loadAs("master:\n nodes:\n - name: mystage", Map.class);
Map master = (Map) map.get("master");
List nodes = (List) master.get("nodes");
Map newNodes = new HashMap();
newNodes.put("nodes", nodes);
master.put("nodes", newNodes);
String modifiedDsl = yaml.dump(map);
MyDsl myDsl2 = yaml2.loadAs(modifiedDsl, MyDsl.class);
可能不是最漂亮的解决方案,但它确实有效。仍然开放的是如何在另一个方向使用它(为 DSL 对象生成 YAML)。