使用 SnakeYaml 将 java 对象写入文件 - 使用 Yaml.dump() 时不会写出内部对象列表

Posted

技术标签:

【中文标题】使用 SnakeYaml 将 java 对象写入文件 - 使用 Yaml.dump() 时不会写出内部对象列表【英文标题】:Writing a java object to a file using SnakeYaml - List of inner objects are not writen out when using Yaml.dump() 【发布时间】:2017-03-20 03:36:57 【问题描述】:

我在使用 SnakeYaml 将 java 对象写入 yml 文件时遇到问题。我已经用一个简单的 application.yml 设置了一个 spring boot 项目,我将其转换为一组 java 对象。在实际应用程序中添加了一些对象,当应用程序完成后,我想写出新的 application.yml。

输入的 application.yml 如下所示:

sample:
  name: toyota
  cars:
     - model: prius
       colour: silver
     - model: avensis
       colour: red

映射这个application.yml的java对象:

@Configuration
@ConfigurationProperties(prefix="sample")
public class Config 

    private String name;
    private final List<Car> cars = new ArrayList<>();

    public String getName() 
        return name;
    
    public void setName(String name) 
        this.name = name;
    
    public List<Car> getCars() 
        return cars;
    

以及写出 yaml 的示例类:

@Component
public class Example 

    @Autowired
    private Config config;

    @PostConstruct
    private void init()
        Yaml yaml = new Yaml();
        StringWriter writer = new StringWriter();
        yaml.dump(config, writer);      
        System.out.println(writer.toString());          
    

输出只是:name: toyota(省略了一些也被写出的 yaml 设置)。但是我希望输出与输入完全相同:

sample:
  name: toyota
  cars:
     - model: prius
       colour: silver
     - model: avensis
       colour: red

有没有办法做到这一点?

编辑:

用户 flyx 正确指出了以下documentation。

我调整后的代码:

Constructor constructor = new Constructor(Config.class);
TypeDescription configDescription = new TypeDescription(Config.class);
configDescription.putListPropertyType("cars", Car.class);
constructor.addTypeDescription(configDescription);
Yaml yaml = new Yaml(constructor);
StringWriter writer = new StringWriter();
yaml.dump(config, writer);      
System.out.println(writer.toString()); 

给出以下输出:

$$beanFactory: !!org.springframework.beans.factory.support.DefaultListableBeanFactory
  allowBeanDefinitionOverriding: true
  allowEagerClassLoading: true
  autowireCandidateResolver: !!org.springframework.context.annotation.ContextAnnotationAutowireCandidateResolver 
  beanClassLoader: !!sun.misc.Launcher$AppClassLoader 
  beanExpressionResolver: !!org.springframework.context.expression.StandardBeanExpressionResolver 
  cacheBeanMetadata: true
  conversionService: null
  dependencyComparator: !!org.springframework.core.annotation.AnnotationAwareOrderComparator 
  parentBeanFactory: null
  serializationId: application
  tempClassLoader: null
  typeConverter: !!org.springframework.beans.SimpleTypeConverter conversionService: null
name: toyota

【问题讨论】:

【参考方案1】:

SnakeYAML 由于类型擦除,在运行时无法获取 List 的元素类型。文档中有一个example 说明您需要做什么。

这样的事情应该可以工作:

@PostConstruct
private void init()
    Constructor c = new Constructor(Config.class);
    TypeDescription configD = new TypeDescription(Config.class);
    configD.putListPropertyType("cars", Car.class);
    c.addTypeDescription(configD);
    Yaml yaml = new Yaml(c);
    StringWriter writer = new StringWriter();
    yaml.dump(config, writer);      
    System.out.println(writer.toString());          

【讨论】:

您的回答很有用,谢谢。但是仍然只有name: toyota 被打印出来。我会根据您的建议更新问题。【参考方案2】:

如果 Car 的列表没有显式设置器,则不会打印该列表。

更改后:

private final List<Car> cars = new ArrayList<>();

public String getName() 
    return name;

public void setName(String name) 
    this.name = name;

public List<Car> getCars() 
    return cars;

到这里:

private List<Car> cars = new ArrayList<>();

public String getName() 
    return name;

public void setName(String name) 
    this.name = name;

public void setCars(List<Car> cars) 
    this.cars = cars;

public List<Car> getCars() 
    return cars;

代码有效。

【讨论】:

以上是关于使用 SnakeYaml 将 java 对象写入文件 - 使用 Yaml.dump() 时不会写出内部对象列表的主要内容,如果未能解决你的问题,请参考以下文章

包含对象列表的 SnakeYaml 反序列化类

在 OSGi 下使用 SnakeYaml?

使用SnakeYAML Java将用户作为嵌套在块序列中的块映射添加到yml文件

使用 SnakeYaml 处理缺失的字段

Snakeyaml - 如何对流样式进行自定义控制

如何解决snakeyaml NoSuchMethodError:getStyle()