I have one half of an answer, and two full answers if you allow a frame challenge.
Half an answer
Load
has a constructor that allows injecting your own factory into the deserialization process, and the functions where have access to Node objects that do carry the anchor.
So the approach would be something like this:
Map<Object, ?> metadata = new HashMap<>();
Load loader = new Load(
settings,
// Inject a StandardConstructor; BaseConstructor does not know about Map etc.
new StandardConstructor(settings) {
@Override
protected Object constructObjectNoCheck(Node node) {
// Let it construct the Pojo from the Node normally.
final Object result = super.constructObjectNoCheck(node);
// Now that you have both Pojo and internal Node,
// you can exfiltrate whatever Node info that you want
// and do metadata.put(result, someInfoGleanedFromNode)
return result;
}
});
The snag is: The Node created for the anchor does not generate a Pojo.
I.e. you have an anchor, but you don't really know to which object in your deserialized nested Map
/List
that anchor corresponds; you'll likely have to walk the Node tree and find the correct node.
So, maybe somebody else wants to add instructions how to walk the Node tree; I do not happen to know that.
Frame challenge: Do you really want the anchor name?
If this is just about error messages, each Node
has a startMark
attribute that's designed specifically for error messages that relate to the Node
, so you can do this:
Map<Object, String> startMarks = new HashMap<>();
Load loader = new Load(
settings,
@Override
protected Object constructObjectNoCheck(Node node) {
final Object result = super.constructObjectNoCheck(node);
node.getStartMark().ifPresent(mark -> startMarks.put(result, mark));
return result;
}
});
e.g. for this YAML snippet:
servers:
- &hetzner
host: <REDACTED>
username: <REDACTED>
private_ssh_key: /home/<REDACTED>/.ssh/id_rsa
the servers
label has this start mark:
in config.yaml, line 1, column 1:
servers:
^
To get this output, I initialized the settings like this:
var settings = LoadSettings.builder().setUseMarks(true).setLabel(path.toString()).build();
setUseMarks
makes it generate start and end marks so you have these texts.
setLabel
is needed to give the in config.yaml
output; otherwise, you'll see something like in reader
(if you pass in a stream reader), which is pretty unhelpful.
Frame challenge: Maybe give the anchored subobject a name?
Something like this:
unit:
&kg
name: Kilogram
shorthand: kg