Use Java to convert yaml to properties to ensure order and tested BUG-free version

I. Introduction

After browsing around the online versions, most of them have the following problems:

  • The order is out of order after conversion
  • Missing child node

It has been optimized based on this. If you just want to convert directly, you can directly use the online version I published If you want to use it in the project, You can continue reading, the source code is at the end of the article.
Insert image description here

1.1 Reasons for disordered order

Most of the code is converted using thejava.util.Properties class. This class is based on ConcurrentHashMap to store key-value pairs, and the order will inevitably be disordered

This is an intercepted portion of the source code of the Properties class:

/**
  * Properties does not store values in its inherited Hashtable, but instead
  * in an internal ConcurrentHashMap.  Synchronization is omitted from
  * simple read operations.  Writes and bulk operations remain synchronized,
  * as in Hashtable.
  */
private transient volatile ConcurrentHashMap<Object, Object> map;

/**
     * Creates an empty property list with the specified defaults.
     *
     * @implNote The initial capacity of a {@code Properties} object created
     * with this constructor is unspecified.
     *
     * @param   defaults   the defaults.
     */
public Properties(Properties defaults) {
    
    
    this(defaults, 8);
}

private Properties(Properties defaults, int initialCapacity) {
    
    
    // use package-private constructor to
    // initialize unused fields with dummy values
    super((Void) null);
    map = new ConcurrentHashMap<>(initialCapacity);
    this.defaults = defaults;

    // Ensure writes can't be reordered
    UNSAFE.storeFence();
}

1.2 Reasons for missing child nodes

The main reason is that the code is not rigorous enough. When parsing, it is not judged whether the child node is an array or object, and it is rudely converted toStringdirectly assigned value

2. Optimization measures

  • Store key-value pairs based onLinkedHashMap

  • Determine the type of child nodes during recursive traversal, and use different processing methods for different types.

3. Source code

import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
import org.yaml.snakeyaml.Yaml;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

@Slf4j
public class YamlUtil {
    
    

    /**
     * yaml 转 Properties
     *
     * @param input
     * @return
     */
    public static String castToProperties(String input) {
    
    
        Map<String, Object> propertiesMap = new LinkedHashMap<>();
        Map<String, Object> yamlMap = new Yaml().load(input);
        flattenMap("", yamlMap, propertiesMap);
        StringBuffer strBuff = new StringBuffer();
        propertiesMap.forEach((key, value) -> strBuff.append(key)
                .append("=")
                .append(value)
                .append(StrUtil.LF));
        return strBuff.toString();
    }

    /**
     * 递归 Map 集合,转为 Properties集合
     *
     * @param prefix
     * @param yamlMap
     * @param treeMap
     */
    private static void flattenMap(String prefix, Map<String, Object> yamlMap, Map<String, Object> treeMap) {
    
    
        yamlMap.forEach((key, value) -> {
    
    
            String fullKey = prefix + key;
            if (value instanceof LinkedHashMap) {
    
    
                flattenMap(fullKey + ".", (LinkedHashMap) value, treeMap);
            } else if (value instanceof ArrayList) {
    
    
                List values = (ArrayList) value;
                for (int i = 0; i < values.size(); i++) {
    
    
                    String itemKey = String.format("%s[%d]", fullKey, i);
                    Object itemValue = values.get(i);
                    if (itemValue instanceof String) {
    
    
                        treeMap.put(itemKey, itemValue);
                    } else {
    
    
                        flattenMap(itemKey + ".", (LinkedHashMap) itemValue, treeMap);
                    }
                }
            } else {
    
    
                treeMap.put(fullKey, value.toString());
            }
        });
    }

}

Guess you like

Origin blog.csdn.net/qq_27574367/article/details/134684155