Search code examples
javaspring-bootyamlsnakeyaml

Writing a java object to a file using SnakeYaml - List of inner objects are not writen out when using Yaml.dump()


I am having trouble writing out a java object to a yml file using SnakeYaml. I have setup a spring boot project with a simple application.yml that I convert to a set of java objects. In the real application some objects get added and when the application is done I want to write out the new application.yml.

The input application.yml looks like this:

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

The java object that maps this application.yml:

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

And the sample class that writes out the 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());          
    }
}

The output is just: name: toyota (ommitted some yaml settings that also get writen out). However I want the output to be exactly the same as the input:

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

Is there a way to do this?

EDIT:

User flyx correctly pointed out the following documentation.

My adjusted code:

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

Gives the following output:

$$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

Solution

  • Without an explicit setter on the list of Car, the list will not be printed.

    After changing:

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

    To this:

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

    The code works.