javayamlsnakeyaml

How to read from YAML file in Java?


I have YAML file like this:

Product:
 ProductA:
  Suite:
    SuiteName_A:
      Environment_1: ["A","B","C"]
      Environment_2: ["X","Y","Z"]
    SuiteName_B:
      Environment_1: ["E","F","G"]
      Environment_2: ["K","L","M"]
 ProductB:
  Suite:
    SuiteName_K:
      Environment_1: ["A1","B2","C3"]
      Environment_2: ["X1","Y1","Z1"]

I have created few classes as I read in some read article and here what I came up with.

Environment class:

package Configuration;

import java.util.ArrayList;

public class Environment {

    private ArrayList<String> Environment_1;
    private ArrayList<String> Environment_2;

    public ArrayList<String> getEnvironment_1() {
        return Environment_1;
    }

    public void setEnvironment_1(ArrayList<String> Environment_1) {
        this.Environment_1 = Environment_1;
    }

    public ArrayList<String> getEnvironment_2() {
        return Environment_2;
    }

    public void setEnvironment_2(ArrayList<String> Environment_2) {
        this.Environment_1 = Environment_2;
    }
}

SuiteNames class:

package Configuration;

import java.util.HashMap;

public class SuiteNames {

    private HashMap<String,Environment> Suite;

    public HashMap<String, Environment> getSuite() {
        return Suite;
    }

    public void setSuite(HashMap<String, Environment> suite) {
        Suite = suite;
    }
}

Product class:

package Configuration;

import java.util.HashMap;

public class Product {

    private HashMap<String,SuiteNames> Product;

    public HashMap<String, SuiteNames> getProduct() {
        return Product;
    }

    public void setProduct(HashMap<String, SuiteNames> product) {
        this.Product = product;
    }
}

Main class:

package Configuration;

import org.yaml.snakeyaml.Yaml;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;

public class DbClass {

    public static void main(String[] args) throws FileNotFoundException {
        Yaml yaml = new Yaml();
        InputStream inputStream = new FileInputStream("path");
        System.out.println(inputStream);
        Product product = yaml.loadAs(inputStream,Product.class);
        System.out.println(product.getProduct());
    }
}

This gives following error:

     Exception in thread "main" Cannot create property=Product for JavaBean=Configuration.Product@4c98385c
 in 'reader', line 1, column 1:
    Product:
    ^
Unable to find property 'Product' on class: Configuration.Product
 in 'reader', line 2, column 3:
      Check-in:
      ^

    at org.yaml.snakeyaml.constructor.Constructor$ConstructMapping.constructJavaBean2ndStep(Constructor.java:270)
    at org.yaml.snakeyaml.constructor.Constructor$ConstructMapping.construct(Constructor.java:149)
    at org.yaml.snakeyaml.constructor.Constructor$ConstructYamlObject.construct(Constructor.java:309)
    at org.yaml.snakeyaml.constructor.BaseConstructor.constructObjectNoCheck(BaseConstructor.java:216)
    at org.yaml.snakeyaml.constructor.BaseConstructor.constructObject(BaseConstructor.java:205)
    at org.yaml.snakeyaml.constructor.BaseConstructor.constructDocument(BaseConstructor.java:164)
    at org.yaml.snakeyaml.constructor.BaseConstructor.getSingleData(BaseConstructor.java:148)
    at org.yaml.snakeyaml.Yaml.loadFromReader(Yaml.java:525)
    at org.yaml.snakeyaml.Yaml.loadAs(Yaml.java:519)
    at Configuration.DbClass.main(DbClass.java:17)
Caused by: org.yaml.snakeyaml.error.YAMLException: Unable to find property 'Product' on class: Configuration.Product
    at org.yaml.snakeyaml.introspector.PropertyUtils.getProperty(PropertyUtils.java:159)
    at org.yaml.snakeyaml.introspector.PropertyUtils.getProperty(PropertyUtils.java:148)
    at org.yaml.snakeyaml.constructor.Constructor$ConstructMapping.getProperty(Constructor.java:287)
    at org.yaml.snakeyaml.constructor.Constructor$ConstructMapping.constructJavaBean2ndStep(Constructor.java:208)
    ... 9 more

I want get the list of Environment names and to store this in a list. I am aware using Jackson API. But I don't know how to map this data to class.

I am using servlets and inside the servlet I want to have a Java method to get the list of strings.


Solution

  • YAML has a list of recommended libraries for Java: SnakeYAML, YamlBeans and eo-yaml

    The most widely used of these is probably SnakeYAML. Baeldung has a very easy to understand tutorial here: https://www.baeldung.com/java-snake-yaml

    [Edit to address new code and output in edit by OP]:

    You also have some problems with the formatting and naming conventions you used. In your yaml file [brackets] are needed around any Lists, instance variables need to be camelCase, and any Strings need to be surrounded by quotes (including Object keys):

    products:
      "ProductA":
        suite:
          "SuiteName_A":
            environment_1: ["A","B","C"]
            environment_2: ["X","Y","Z"]
          "SuiteName_B":
            environment_1: ["E","F","G"]
            environment_2: ["K","L","M"]
      "ProductB":
        suite:
          "SuiteName_K":
            environment_1: ["A1","B2","C3"]
            environment_2: ["X1","Y1","Z1"]
    

    You should try to match this in your bean naming convention. Also your 2nd setter needs to set Environment_2 instead of Environment_1. Here's how your entity classes would look.

    Environment

    package Configuration;
    
    import java.util.ArrayList;
    
    public class Environment {
        private ArrayList<String> environment_1;
        private ArrayList<String> environment_2;
    
        public ArrayList<String> getEnvironment_1() {
            return environment_1;
        }
    
        public void setEnvironment_1(ArrayList<String> environment_1) {
            this.environment_1 = environment_1;
        }
    
        public ArrayList<String> getEnvironment_2() {
            return environment_2;
        }
    
        public void setEnvironment_2(ArrayList<String> environment_2) {
            this.environment_2 = environment_2;
        }
    }
    

    SuiteNames

    package Configuration;
    
    import java.util.HashMap;
    
    public class SuiteName {
        private HashMap<String,Environment> suite;
    
        public HashMap<String, Environment> getSuite() {
            return suite;
        }
    
        public void setSuite(HashMap<String, Environment> suite) {
            suite = suite;
        }
    }
    package Configuration;
    
    import java.util.HashMap;
    
    public class Product {
        private HashMap<String, SuiteName> products;
    
        public HashMap<String, SuiteName> getProducts() {
            return products;
        }
    
        public void setProducts(HashMap<String, SuiteName> products) {
            this.products = products;
        }
    }
    

    Edit: In your main method you will probably want to use yaml.load(inputStream) to get the whole file in a HashMap. Based on your question in the comment I've added accessing the data structure.

    DbClass

    package Configuration;
    
    import org.yaml.snakeyaml.Yaml;
    
    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    import java.io.InputStream;
    import java.util.ArrayList;
    import java.util.HashMap;
    
    public class DbClass {
    
        public static void main(String[] args) throws FileNotFoundException {
            Yaml yaml = new Yaml();
            InputStream inputStream = new FileInputStream("path.yml");
            System.out.println(inputStream);
    
            HashMap yamlMap = yaml.load(inputStream);
            for (Object o : yamlMap.entrySet()) {
                System.out.println(o);
            }
            // Access HashMaps and ArrayList by key(s)
            HashMap products = (HashMap) yamlMap.get("products");
            HashMap product = (HashMap) products.get("ProductA");
            HashMap suite = (HashMap) product.get("suite");
            HashMap suiteName = (HashMap) suite.get("SuiteName_B");
            ArrayList environment = (ArrayList) suiteName.get("environment_1");
            System.out.println(environment);
        }
    }