2017-06-15 3 views
0

ich die folgende Klassenstruktur in einem Programm haben, die ich nicht ändern kann:SnakeYAML: Erstellen Sie einige Objekte anders

class Node { 
    public String name; 
} 

class Nodes { 
    public List<Node> nodes; 
} 

class Master { 
    public Nodes nodes; 
} 

ich folgende YAML kann es initialisieren:

master: 
    nodes: 
    nodes: 
     - name: test 

Gibt es eine Möglichkeit mit SnakeYaml, die ersten "Nodes:" mit einer Art von Instanzierungslogik für benutzerdefinierte Objekte auszulassen, damit meine Kunden einfach die folgenden YAML verwenden können?

master: 
    nodes: 
    - name: test 

ich mit einer benutzerdefinierten Konstruktor Implementierung versucht, aber nicht bekam diese Arbeit:

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

Am Ende ist das, was Ich mag zum Laufen bringen:

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

Irgendwelche Ideen? Danke im Voraus.

+0

Warum bearbeiten Sie die YAML-Datei nicht vor und löschen Sie die dazwischen liegenden "Knoten". Das würde ein Python-Programm von ~ 5 Zeilen benötigen. – Anthon

+0

Danke. Obwohl dies eine Option wäre, suche ich nach einer Möglichkeit, dies mit SnakeYAML selbst zu erreichen. Außerdem möchte ich dieses YAML (ohne die dazwischenliegenden "Knoten") aus einem Objektbaum erzeugen. Ich denke, es muss einen Weg geben, ich kann es bisher nur nicht finden ... –

Antwort

0

Was ich getan habe, um endlich dieses Problem zu lösen ist, um manuell die darunter liegende Karte zu verwandeln, Dump es in einen String und laden Sie es wieder mit meiner DSL-Wrapper-Klasse:

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

Wahrscheinlich nicht die schönste Lösung, aber Es klappt. Was noch offen ist, ist, wie man das in die andere Richtung benutzt (Generierung von YAML für das DSL-Objekt).

Verwandte Themen