【问题标题】:Collapse single-child bean in SnakeYAML在 SnakeYAML 中折叠单子 bean
【发布时间】:2017-04-04 12:20:50
【问题描述】:

我有一个类型,它是 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);
    }
}

目前,我使用DumperOptionsallowReadOnlyProperties = trueBeanAccessFIELD 来正确转储此类。当放入包含类时,我会得到一个 dumpAsMap YAML,如下所示:

flags:
    _flags: {}

我想让 SnakeYAML 转储它:

flags: {}

如何实现单元素图层的扁平化?由于内部变量是私有的,并且包装类型应该有效地充当包装类型,因此包装类型应该像被包装类型一样序列化是有意义的。

基本上,我希望包装类型被序列化就像被包装类型一样。没有也永远不会有其他需要序列化的变量包装变量之外的此类。我愿意更改包装类型的类型声明,但包装类型必须保留用于我的用例。

可运行复制案例的完整来源:

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);
    }
}

【问题讨论】:

    标签: java yaml snakeyaml


    【解决方案1】:

    这样的事情可能会起作用(没有测试代码):

    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());
    

    【讨论】:

    • 我希望在不为每个包装类型编写自定义 Represent 的情况下这是可能的,但目前看来这是最好的方法。对反序列化的评论将使这成为一个完美的答案。
    • 对于反序列化,很容易适应documentation 中的示例代码,就像我为表示所做的那样。
    • 这就是我找不到的。谢谢!
    猜你喜欢
    • 1970-01-01
    • 2013-10-15
    • 1970-01-01
    • 2019-01-06
    • 2013-04-08
    • 2011-01-15
    • 2011-04-25
    • 1970-01-01
    相关资源
    最近更新 更多