Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Parsing a YAML document with a map at the root using snakeYaml

I want to read a YAML document to a map of custom objects (instead of maps, which snakeYaml does by default). So this:

19:
  typeID: 2
  limit: 300
20:
  typeID: 8
  limit: 100

Would be loaded to a map which looks like this:

Map<Integer, Item>

where Item is:

class Item {
    private Integer typeId;
    private Integer limit;
}

I could not find a way to do this with snakeYaml, and I couldn't find a better library for the task either.

The documentation only has examples with maps/collections nested inside other objects, so that you can do the following:

    TypeDescription typeDescription = new TypeDescription(ClassContainingAMap.class);
    typeDescription.putMapPropertyType("propertyNameOfNestedMap", Integer.class, Item.class);
    Constructor constructor = new Constructor(typeDescription);
    Yaml yaml = new Yaml(constructor);
    /* creating an input stream (is) */
    ClassContainingAMap obj = (ClassContainingAMap) yaml.load(is);

But how do I go about defining the Map format when it is at the root of the document?

like image 944
Justas Avatar asked Feb 16 '15 21:02

Justas


People also ask

How do you represent a map in YAML?

In YAML, maps are represented using the colon ( : ) character. We can also use quotation marks ( " or ' ) to enclose the keys and values if we need to.

What does SnakeYAML do?

SnakeYAML allows you to read a YAML file into a simple Map object or parse the file and convert it into a custom Java object. Depending on your requirements you can decide in which format you want to read your YAML files.

What is parsing in YAML?

In Ruby, this might be a Hash, an Array or any other Ruby object. But before YAML is loaded into those types, it must be parsed. Parsing is the stage where the structure of the document becomes apparent, but not the native typing. YAML. rb gives you access to a YAML document before it is transformed.

Is SnakeYAML thread safe?

Since the implementation is not thread safe, different threads must have their own Yaml instance.


1 Answers

Here is what I did for a very similar situation. I just tabbed my whole yml file over one tab and added a map: tag to the top. So for your case it would be.

map:
  19:
    typeID: 2
    limit: 300
  20:
    typeID: 8
    limit: 100

And then create a static class in your class that reads this file like follows.

static class Items {
    public Map<Integer, Item> map;
}

And then to read your map just use.

Yaml yaml = new Yaml(new Constructor(Items));
Items items = (Items) yaml.load(<file>);
Map<Integer, Item> itemMap = items.map;

UPDATE:

If you don't want to or cannot edit your yml file you could just do the above transform in code while reading the file with something like this.

try (BufferedReader br = new BufferedReader(new FileReader(new File("example.yml")))) {
    StringBuilder builder = new StringBuilder("map:\n");
    String line;
    while ((line = br.readLine()) != null) {
        builder.append("    ").append(line).append("\n");
    }

    Yaml yaml = new Yaml(new Constructor(Items));
    Items items = (Items) yaml.load(builder.toString());
    Map<Integer, Item> itemMap = items.map;
}
like image 85
crowmagnumb Avatar answered Oct 05 '22 23:10

crowmagnumb