DEV Community

Cover image for How to handling internal Yaml in Jar.
Kooin-Shin
Kooin-Shin

Posted on • Edited on

How to handling internal Yaml in Jar.

Intro.


Some far ago, I've been introducing 'How to manage your configuration file with YAML in Java programmatically' in previous post.
if you wanna know it, follow link: How to manage your configuration file with YAML in Java programmatically

It was about handing Yaml file contents to create Java Bean object. That was including information of a configuration or serialized Valued-Object(VO). Simply to say, It was about load or dump information between Yaml file and Java object.

Meanwhile, Someone who has keen thinking asked how to access a Yaml file in internal resources?
So I realized it's need,
Here I would show how to load and dump Yaml file in Jar.

Setting up environments.


  1. As same as previous post, To handle Yaml file, We need SnakeYAML library.
  2. For our works, Any IDE Tools is able to use, But I gonna to use Visual Studio Code(VSCODE) on fever in these days.
  3. And we have to set SnakeYAML MAVEN dependency to POM.xml. In previous post I used Gradle but now, Would use MAVEN for diversity :) Alt Text
  4. If you are prepared with above things, Readied to start coding.

Designing Java Class.


Before we gonna see implemented code, I would show you entire design of our works.

  1. We will define java class named "YamlInternalHandler" to handle Yaml file in Jar.
  2. Will define two method named "loadInternalJar" and "dumpInternalJar". First one is to load Yaml's contents to Java object with jar entry path and a Class object to be loaded the contents. Second one is to dump a object values to Yaml file in Jar with jar entry path and instance of Java object including a values.
  3. We could load and dump a specified object mapping with a Yaml file in jar. Surely, It's good to make sure syntax of Yaml file in Jar.

Let's dive into code.


Contents of Yaml file in Jar is down below.

firstName: Kooin
lastName: Shin
age: 48
profile:
  - character: bright
    hobby: claiming
    address: Seoul
    postalCode: 123
  - character: delight
    hobby: ski
    address: Seoul
    postalCode: 123

Enter fullscreen mode Exit fullscreen mode

Java Bean to be loaded contents is 'Customer' and 'Profile' representing Yaml's values.

package org.chaostocosmos.doc.yml;

import java.util.List;

public class Customer {

    private String firstName;
    private String lastName;
    private int age;
    private List<Profile> profile;

    public Customer() {}

    public String getFirstName() {
        return this.firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return this.lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public int getAge() {
        return this.age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public List<Profile> getProfile() {
        return this.profile;
    }

    public void setProfile(List<Profile> profile) {
        this.profile = profile;
    }

    @Override
    public String toString() {
        return "{" +
            " firstName='" + firstName + "'" +
            ", lastName='" + lastName + "'" +
            ", age='" + age + "'" +
            ", profile='" + profile + "'" +
            "}";
    }
}
Enter fullscreen mode Exit fullscreen mode
package org.chaostocosmos.doc.yml;

public class Profile {

    String character;
    String hobby;
    String address;
    int postalCode;    

    public Profile() {}

    public String getCharacter() {
        return this.character;
    }

    public void setCharacter(String character) {
        this.character = character;
    }

    public String getHobby() {
        return this.hobby;
    }

    public void setHobby(String hobby) {
        this.hobby = hobby;
    }

    public String getAddress() {
        return this.address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public int getPostalCode() {
        return this.postalCode;
    }

    public void setPostalCode(int postalCode) {
        this.postalCode = postalCode;
    }

    @Override
    public String toString() {
        return "{" +
            " character='" + character + "'" +
            ", hobby='" + hobby + "'" +
            ", address='" + address + "'" +
            ", postalCode='" + postalCode + "'" +
            "}";
    }    
}
Enter fullscreen mode Exit fullscreen mode

And Now we gonna show core code of 'YamlInternalHandler' class.

package org.chaostocosmos.doc.yml;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.jar.JarOutputStream;
import java.util.zip.ZipEntry;

import org.yaml.snakeyaml.DumperOptions;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.DumperOptions.FlowStyle;
import org.yaml.snakeyaml.constructor.Constructor;

/**
 * Yaml Internal Handler 
 * 
 * @author Kooin-Shin
 * @since 2021.01.04
 */
public class YamlInternalHandler {

    /**
     * Jar file having yaml file
     */
    File file;

    /**
     * Constructor
     * @param file
     * @throws IOException
     */
    public YamlInternalHandler(File file) throws IOException {
        this.file = file;
    }

    /**
     * Load object from internal yaml file in jar
     * @param jarEntry
     * @param clazz
     * @return
     * @throws IOException
     */
    public Object loadInternalJar(String jarEntry, Class<? extends Object> clazz) throws IOException {
        if (!jarEntry.endsWith(".yml")) {
            throw new IllegalArgumentException("This component only support a yaml file in jar!!!");
        }
        JarFile jarFile = new JarFile(this.file);   //Create JarFile object
        JarEntry entry = jarFile.getJarEntry(jarEntry);  //Get JarEntry specified by first parameter
        InputStream is = jarFile.getInputStream(entry);  //Get InputStream from JarFile  by JarEntry
        Constructor constructor = new Constructor(clazz); //Create Constructor object specified by second parameter
        Yaml yaml = new Yaml(constructor);  //Create Yaml object with Constructor object
        Object obj = yaml.load(is);   //Load contents to object instance
        is.close();  //Close InputStream
        jarFile.close();  //Close JarFile
        return obj;
    }

    /**
     * Dump object to yaml file in jar
     * @param jarEntry
     * @param obj
     * @throws FileNotFoundException
     * @throws IOException
     */
    public void dumpInternalJar(String jarEntry, Object obj) throws FileNotFoundException, IOException {
        JarOutputStream jos = new JarOutputStream(new FileOutputStream(this.file));  //Create JarOutputStream object 
        jos.putNextEntry(new ZipEntry(jarEntry));  //Put jar entry by first parameter
        DumperOptions options = new DumperOptions();  //Set dump options
        options.setDefaultFlowStyle(FlowStyle.BLOCK); 
        options.setPrettyFlow(true);
        Yaml yaml = new Yaml(options);  //Create Yaml object with DumperOptions object
        yaml.dump(obj, new OutputStreamWriter(jos));  //Dump contents of second parameter
        jos.close(); // Close JarOutputStream
    }

    public static void main(String[] args) throws IOException {
        File file = new File("D:\\Projects\\chaos-commons\\yaml.jar");
        YamlInternalHandler ymlHandler = new YamlInternalHandler(file);
        Customer customer = (Customer) ymlHandler.loadInternalJar("tmp/yaml/Customer.yml", Customer.class);
        System.out.println(customer.toString());
        customer.setFirstName("Jim ");
        customer.getProfile().get(0).setAddress("Busan");
        ymlHandler.dumpInternalJar("tmp/yaml/Customer.yml", customer);
    }
}
Enter fullscreen mode Exit fullscreen mode

Conclusion

Above code is assumed very simple cases of accessing of a Yaml in Jar. As a situation, It can be transformed, modified and improved.
Always elastic thinking is yours!!!
Good Luck!!!

Top comments (0)