On Tue, Feb 12, 2019 at 8:43 PM John Passaro <[email protected]> wrote: > > 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.
Yes, it is true that for YAML documents the idea of using "default identity" (similar to "default typing" for polymorphic type handling) would be useful. Unfortunately I am not sure how practical it would be for general case, one problem being the limited support for non-POJO types. In practice one could achieve something like this by custom `AnnotationIntrospector` that basically "finds" equivalent of `@JsonIdentityInfo` on every introspected type. But as to more general handling... I wonder if `JsonNode` could be forced (with a feature or YAMLMapper setting) to support anchors/refs and in THAT case you could first resolve all of these and THEN map to actual POJOs. I will file an issue for that -- I can't promise I can make that happen, but I think that is a reasonable idea and could help tackle this completely without requiring annotations. -+ Tatu +- -- 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.
