在 SnakeYAML 中折叠单子 bean
Collapse single-child bean in SnakeYAML
我有一个类型,它是 Map<String, Integer>
的简单包装器,我正在使用 SnakeYAML 将其转储到 YAML。
举个例子:
class Flags {
private final Map<String, Boolean> _flags = new HashMap<>();
Boolean get(String flag) {
return _flags.containsKey(flag) ? _flags.get(flag) : false;
}
boolean put(String flag, Boolean value) {
return _flags.put(flag, value);
}
}
目前,我正在使用 DumperOptions
与 allowReadOnlyProperties = true
和 BeanAccess
的 FIELD
来正确转储此 class。当放入包含 class 时,我得到一个 dumpAsMap
YAML,如下所示:
flags:
_flags: {}
我想让 SnakeYAML 转储这个:
flags: {}
如何实现单元素层的扁平化?由于内部变量是私有的,并且包装类型应该有效地充当包装类型,因此包装类型应该像包装类型一样被序列化是有意义的。
基本上,我希望包装类型被序列化就好像它是包装类型一样。没有也永远不会其他需要在包装变量外的 class 序列化的变量。我愿意更改包装类型的类型声明,但包装类型必须保留用于我的用例。
可运行复制案例的完整来源:
import org.yaml.snakeyaml.*;
import org.yaml.snakeyaml.introspector.*;
import java.util.*;
public class Example {
private final Flags flags = new Flags();
public Flags getFlags() { return flags; }
public static void main(String[] args) {
DumperOptions options = new DumperOptions();
options.setAllowReadOnlyProperties(true);
Yaml yaml = new Yaml(options);
yaml.setBeanAccess(BeanAccess.FIELD);
System.out.println(yaml.dumpAsMap(new Example()));
}
}
class Flags {
private final Map<String, Boolean> _flags = new HashMap<>();
Boolean get(String flag) {
return _flags.containsKey(flag) ? _flags.get(flag) : false;
}
boolean put(String flag, Boolean value) {
return _flags.put(flag, value);
}
}
类似这样的方法可能有效(未测试代码):
class FlagsRepresenter extends Representer {
public FlagsRepresenter() {
this.representers.put(Flags.class, new RepresentFlags());
}
private class RepresentFlags implements Represent {
public Node representData(Object data) {
// going the hacky, painful way of accessing a private field here.
// YMMV.
try {
final Field f = data.getClass().getDeclaredField("_flags");
f.setAccessible(true);
final Map<String, Boolean> inner =
(Map<String, Boolean>) f.get(data);
return representMapping(Tag.MAP, inner, null);
} catch (final Exception ignored) {
// will not occur as long as field _flags exists and has the
// expected type.
return null;
}
}
}
}
这样使用:
Yaml yaml = new Yaml(new FlagsRepresenter(), new DumperOptions());
我有一个类型,它是 Map<String, Integer>
的简单包装器,我正在使用 SnakeYAML 将其转储到 YAML。
举个例子:
class Flags {
private final Map<String, Boolean> _flags = new HashMap<>();
Boolean get(String flag) {
return _flags.containsKey(flag) ? _flags.get(flag) : false;
}
boolean put(String flag, Boolean value) {
return _flags.put(flag, value);
}
}
目前,我正在使用 DumperOptions
与 allowReadOnlyProperties = true
和 BeanAccess
的 FIELD
来正确转储此 class。当放入包含 class 时,我得到一个 dumpAsMap
YAML,如下所示:
flags:
_flags: {}
我想让 SnakeYAML 转储这个:
flags: {}
如何实现单元素层的扁平化?由于内部变量是私有的,并且包装类型应该有效地充当包装类型,因此包装类型应该像包装类型一样被序列化是有意义的。
基本上,我希望包装类型被序列化就好像它是包装类型一样。没有也永远不会其他需要在包装变量外的 class 序列化的变量。我愿意更改包装类型的类型声明,但包装类型必须保留用于我的用例。
可运行复制案例的完整来源:
import org.yaml.snakeyaml.*;
import org.yaml.snakeyaml.introspector.*;
import java.util.*;
public class Example {
private final Flags flags = new Flags();
public Flags getFlags() { return flags; }
public static void main(String[] args) {
DumperOptions options = new DumperOptions();
options.setAllowReadOnlyProperties(true);
Yaml yaml = new Yaml(options);
yaml.setBeanAccess(BeanAccess.FIELD);
System.out.println(yaml.dumpAsMap(new Example()));
}
}
class Flags {
private final Map<String, Boolean> _flags = new HashMap<>();
Boolean get(String flag) {
return _flags.containsKey(flag) ? _flags.get(flag) : false;
}
boolean put(String flag, Boolean value) {
return _flags.put(flag, value);
}
}
类似这样的方法可能有效(未测试代码):
class FlagsRepresenter extends Representer {
public FlagsRepresenter() {
this.representers.put(Flags.class, new RepresentFlags());
}
private class RepresentFlags implements Represent {
public Node representData(Object data) {
// going the hacky, painful way of accessing a private field here.
// YMMV.
try {
final Field f = data.getClass().getDeclaredField("_flags");
f.setAccessible(true);
final Map<String, Boolean> inner =
(Map<String, Boolean>) f.get(data);
return representMapping(Tag.MAP, inner, null);
} catch (final Exception ignored) {
// will not occur as long as field _flags exists and has the
// expected type.
return null;
}
}
}
}
这样使用:
Yaml yaml = new Yaml(new FlagsRepresenter(), new DumperOptions());