Convert yaml to properties using Java
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.
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 toString
directly assigned value
2. Optimization measures
-
Store key-value pairs based on
LinkedHashMap
-
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());
}
});
}
}