简体   繁体   中英

Deserialize POJOs from multiple YAML documents in a single file in Jackson

I have a YAML file that looks something like this:

---
name: Sam
tags:
    -   Dev
    -   Java
----
name: Bob
tags:
    -   PM

I'd like to use Jackson to deserialize all documents from the file, but I don't see a way to use a normal ObjectMapper to do it. If I use the YAMLFactory to create a parser for my file I can step through all tokens, so the parser is obviously capable of dealing with multiple documents - but how do I tie them together? Looks like the parser created by my YAMLFactory only parses a single document out of the file.

I've also tried creating a YAMLParser directly and using ObjectMapper#readValue(JsonParser, Class) , but the ObjectMapper exhausts the entire YAMLParser to deserialize a single instance.

This is years later but it's worth pointing out that this is supported. The Jackson semantics are slightly different, probably due to it's JSON origins. This can be achieved by using the MappingIterator from ObjectMapper .

YAMLFactory yaml;
ObjectMapper mapper;

YAMLParser yamlParser = yaml.createParser("file-with-multiple-docs.yaml")
List<ObjectNode> docs = mapper
      .readValues<ObjectNode>(yamlParser, new TypeReference<ObjectNode> {})
      .readAll();

Replace ObjectNode with your own POJOs if desired.

You can use directly SnakeYaml (Jackson YAML parser is using it internally):

try (InputStream input = new FileInputStream(file)) {
    Yaml yaml = new Yaml(new SafeConstructor());
    yaml.loadAll(input).forEach( System.out::println );
} catch (Throwable e) {
    System.out.println("ERROR: " + e.getMessage());
}

Will Produce:

{name=Sam, tags=[Dev, Java]}
{name=Bob, tags=[PM]}

This does not seem to be supported at this point. Here is the link to the YAMLParser source code .

If the input YAML contains several documents then Jackson fails. Here is an example:

public class JacksonYAML {
    public static final String YAML = "---\n" +
            "name: Sam\n" +
            "tags:\n" +
            "    -   Dev\n" +
            "    -   Java\n" +
            "----\n" +
            "name: Bob\n" +
            "tags:\n" +
            "    -   PM";

    public static void main(String[] args) throws IOException {
        ObjectMapper mapper = new ObjectMapper(new YAMLFactory());
        System.out.println(mapper.readValue(YAML, Object.class));
    }
}

The exception error points to the second item in the input source:

Exception in thread "main" while scanning a simple key
 in 'reader', line 6, column 1:
    ----
    ^
could not found expected ':'
 in 'reader', line 7, column 1:
    name: Bob
    ^

    at com.fasterxml.jackson.dataformat.yaml.snakeyaml.scanner.ScannerImpl.stalePossibleSimpleKeys(ScannerImpl.java:465)
    at com.fasterxml.jackson.dataformat.yaml.snakeyaml.scanner.ScannerImpl.needMoreTokens(ScannerImpl.java:280)
    at com.fasterxml.jackson.dataformat.yaml.snakeyaml.scanner.ScannerImpl.checkToken(ScannerImpl.java:225)
    at com.fasterxml.jackson.dataformat.yaml.snakeyaml.parser.ParserImpl$ParseBlockSequenceEntry.produce(ParserImpl.java:502)
    at com.fasterxml.jackson.dataformat.yaml.snakeyaml.parser.ParserImpl.peekEvent(ParserImpl.java:158)
    at com.fasterxml.jackson.dataformat.yaml.snakeyaml.parser.ParserImpl.getEvent(ParserImpl.java:168)
    at com.fasterxml.jackson.dataformat.yaml.YAMLParser.nextToken(YAMLParser.java:331)
    at com.fasterxml.jackson.databind.deser.std.UntypedObjectDeserializer$Vanilla.mapArray(UntypedObjectDeserializer.java:529)
    at com.fasterxml.jackson.databind.deser.std.UntypedObjectDeserializer$Vanilla.deserialize(UntypedObjectDeserializer.java:449)
    at com.fasterxml.jackson.databind.deser.std.UntypedObjectDeserializer$Vanilla.mapObject(UntypedObjectDeserializer.java:572)
    at com.fasterxml.jackson.databind.deser.std.UntypedObjectDeserializer$Vanilla.deserialize(UntypedObjectDeserializer.java:435)
    at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:3051)
    at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2146)
    at stackoverflow.JacksonYAML.main(JacksonYAML.java:26)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:134)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM