On Tue, Feb 12, 2019, 23:02 Tatu Saloranta <[email protected] wrote: > On Tue, Feb 12, 2019 at 1:18 PM John Passaro <[email protected]> > wrote: > > > > Hello folks! I am trying to deserialize a yaml file with anchors and > references. There are some existing StackOverflow questions along these > lines but the answers aren't quite getting me to the finish line. > > > > Here is my model: > > > > @JsonIdentityInfo(generator = ObjectIdGenerators.None.class) > > class YamlScratch { > > @JsonProperty("misc") > > List<List<String>> misc; > > > > @JsonProperty("contents") > > Map<String, Config> contents; > > > > static class Config { > > @JsonProperty("header") > > String header; > > > > @JsonProperty("labels") > > @JsonIdentityInfo(generator = ObjectIdGenerators.None.class) > > List<String> labels; > > } > > } > > > > > > > > Here is my YAML: > > > > misc: > > - &letters > > - Aie > > - Bee > > - See > > - &numbers > > - One > > - Two > > - Three > > > > contents: > > letters: > > header: "This is a list of phonetic letters" > > labels: *letters > > numbers: > > header: "This is a list of number spellings" > > labels: *numbers > > moreletters: > > header: "this is another copy of the letters" > > labels: *letters > > > > > > The idea is that I have lists that may be referenced more than once in > the "contents" tree, and I'd like to be able to reference them concisely. > > > > I've tried to enable this in my Java code by adding @JsonIdentityInfo to > the "labels" field that will reference these lists. As for the YAML, I > added "&..." anchors to the data that will be referenced, and where it > should appear I added "*..." references. PyYAML seems to confirm this is > the correct YAML usage: > > > > $ python3 > > >>> import yaml > > >>> f = > open("/Users/johnpassaro/Library/Preferences/IdeaIC2018.3/scratches/scratch.yml") > > >>> y = yaml.load(f) > > >>> y > > {'misc': [['Aie', 'Bee', 'See'], ['One', 'Two', 'Three']], 'contents': > {'letters': {'header': 'This is a list of phonetic letters', 'labels': > ['Aie', 'Bee', 'See']}, 'numbers': {'header': 'This is a list of number > spellings', 'labels': ['One', 'Two', 'Three']}}} > > > > > > With Jackson (2.9), I get an error: > > > > Exception in thread "main" > com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot > deserialize instance of java.util.ArrayList out of VALUE_STRING token > > at [Source: (File); line: 14, column: 13] (through reference chain: > YamlScratch["contents"]->java.util.LinkedHashMap["letters"]->YamlScratch$Config["labels"]) > > > > I tried changing > > List<String> labels; > > to > > Object labels; > > just to see how Jackson was treating it: instead of resolving the anchor > reference ("*letters"), it just returns the reference name as as a string > ("letters"). > > > > One of the StackOverflow questions has an answer that mentions the > feature YAMLParser.Feature.USE_NATIVE_OBJECT_ID. That would seem to be > exactly what I need, but that enum value is not present in 2.9. > > > > Is this behavior supported at all? If so, what do I need to do to make > it work? > > > > Many thanks in advance for your help. I'd be happy to post the results > on the relevant SO threads to make sure this information get shared > reasonably widely. > > Ok. I think I can point to the problem itself at least. > > For Jackson to handle anchors and references, property value types (or > property declarations) need `@JsonIdentityInfo`; otherwise Jackson > does not know to look for, or keep track of, anchors (ids for values > to reference) or references. > > But one limitation is that only POJO types support Object Id handling, > and here references would be to Lists of Strings (or maybe Lists of > Lists). In theory it would be possible to handle Object Ids for > Collection, Map and array types, but they are not supported at this > point. > > It might, however, be possible for you to create POJO type that gets > serialized as yaml/json Array, just like List (and deserialized from > as well). This could work by using combination of `@JsonValue` (to get > `List` to serialize) and `@JsonCreator` annotated constructor that > takes actual `List` value you want; or, using Converters. Either way > once you get that working, and type itself annotated with > `@JsonIdentityInfo` it should work. > > I know this is sub-optimal and leaves out some valid YAML cases. But > it just might work for your usage. > > I hope this helps, > > -+ Tatu +- >
I will certainly try this out, it does seem like it would address my need. Thank you for the close attention to the example and for your suggestion. If it works I'll post my findings (i.e. working example) here and maybe add to those SO questions. It seems to me there might be a friendlier experience if there was a YamlParser.Feature to treat the entire document as having the JsonIdentityInfo annotation, including Lists and Maps and their contents - that is, resolving anchor references everywhere without the need for indicating where the user expects them to be. I don't know enough to assert that this is closer to the intention of the anchor/reference feature or of an average document that uses it, but it is closer to how PyYAML treats them, which I've found very useful. I hope you'll consider supporting such usage. Regardless, thank you for your help and for your work on this powerful library. -- You received this message because you are subscribed to the Google Groups "jackson-user" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. To post to this group, send email to [email protected]. For more options, visit https://groups.google.com/d/optout.
