YamlConfigParser.java
package io.github.pojotools.flat2pojo.core.config;
import io.github.pojotools.flat2pojo.core.config.MappingConfig.ConflictPolicy;
import io.github.pojotools.flat2pojo.core.config.MappingConfig.Nulls;
import io.github.pojotools.flat2pojo.core.config.MappingConfig.OrderBy;
import io.github.pojotools.flat2pojo.core.config.MappingConfig.OrderDirection;
import io.github.pojotools.flat2pojo.core.config.MappingConfig.PrimitiveListRule;
import io.github.pojotools.flat2pojo.core.config.MappingConfig.PrimitiveSplitRule;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.yaml.snakeyaml.Yaml;
/** Parses YAML configuration into MappingConfig. Single Responsibility: YAML parsing only. */
@SuppressWarnings("unchecked")
final class YamlConfigParser {
private YamlConfigParser() {}
static MappingConfig parse(final String yaml) {
final Map<String, Object> root = new Yaml().load(yaml);
if (root == null) {
return MappingConfig.builder().build();
}
final ImmutableMappingConfig.Builder builder = MappingConfig.builder();
parseBasicConfiguration(root, builder);
parsePrimitiveRules(root, builder);
parsePrimitiveListRules(root, builder);
parseListRules(root, builder);
parseNullPolicy(root, builder);
return builder.build();
}
private static void parseBasicConfiguration(
final Map<String, Object> root, final ImmutableMappingConfig.Builder builder) {
builder.separator((String) root.getOrDefault("separator", "/"));
builder.allowSparseRows(Boolean.TRUE.equals(root.get("allowSparseRows")));
final List<String> rootKeys = (List<String>) root.get("rootKeys");
if (rootKeys != null) {
builder.rootKeys(rootKeys);
}
}
private static void parsePrimitiveRules(
final Map<String, Object> root, final ImmutableMappingConfig.Builder builder) {
List<Map<String, Object>> primitives = (List<Map<String, Object>>) root.get("primitives");
if (primitives == null) {
return;
}
for (Map<String, Object> primitive : primitives) {
parseSinglePrimitiveRule(primitive, builder);
}
}
private static void parseSinglePrimitiveRule(
final Map<String, Object> primitive, final ImmutableMappingConfig.Builder builder) {
Map<String, Object> split = (Map<String, Object>) primitive.get("split");
if (split == null) {
return;
}
String path = (String) primitive.get("path");
String delimiter = (String) split.getOrDefault("delimiter", ",");
boolean trim = Boolean.TRUE.equals(split.get("trim"));
builder.addPrimitives(new PrimitiveSplitRule(path, delimiter, trim));
}
private static void parsePrimitiveListRules(
final Map<String, Object> root, final ImmutableMappingConfig.Builder builder) {
List<Map<String, Object>> primitiveLists =
(List<Map<String, Object>>) root.get("primitiveLists");
if (primitiveLists == null) {
return;
}
for (Map<String, Object> primitiveListRule : primitiveLists) {
parseSinglePrimitiveListRule(primitiveListRule, builder);
}
}
private static void parseSinglePrimitiveListRule(
final Map<String, Object> primitiveListRule, final ImmutableMappingConfig.Builder builder) {
String path = (String) primitiveListRule.get("path");
String orderDirectionString =
(String) primitiveListRule.getOrDefault("orderDirection", "insertion");
OrderDirection orderDirection =
OrderDirection.valueOf(orderDirectionString.toLowerCase(java.util.Locale.ROOT));
boolean dedup = !Boolean.FALSE.equals(primitiveListRule.get("dedup"));
builder.addPrimitiveLists(new PrimitiveListRule(path, orderDirection, dedup));
}
private static void parseListRules(
final Map<String, Object> root, final ImmutableMappingConfig.Builder builder) {
List<Map<String, Object>> lists = (List<Map<String, Object>>) root.get("lists");
if (lists == null) {
return;
}
for (Map<String, Object> listRule : lists) {
parseSingleListRule(listRule, builder);
}
}
private static void parseSingleListRule(
final Map<String, Object> listRule, final ImmutableMappingConfig.Builder builder) {
String path = (String) listRule.get("path");
List<String> keyPaths = (List<String>) listRule.getOrDefault("keyPaths", List.of());
List<OrderBy> orderBy = parseOrderByRules(listRule);
boolean dedupe = !Boolean.FALSE.equals(listRule.get("dedupe"));
ConflictPolicy conflictPolicy = parseConflictPolicy(listRule);
builder.addLists(new MappingConfig.ListRule(path, keyPaths, orderBy, dedupe, conflictPolicy));
}
private static List<OrderBy> parseOrderByRules(Map<String, Object> listRule) {
List<Map<String, Object>> orderByList = (List<Map<String, Object>>) listRule.get("orderBy");
if (orderByList == null) {
return new ArrayList<>();
}
List<OrderBy> orderBy = new ArrayList<>();
for (Map<String, Object> orderSpec : orderByList) {
orderBy.add(parseSingleOrderBy(orderSpec));
}
return orderBy;
}
private static OrderBy parseSingleOrderBy(Map<String, Object> orderSpec) {
String path = (String) orderSpec.get("path");
OrderDirection orderDirection =
parseDirection((String) orderSpec.getOrDefault("direction", "asc"));
Nulls nulls = parseNulls((String) orderSpec.getOrDefault("nulls", "last"));
return new OrderBy(path, orderDirection, nulls);
}
private static OrderDirection parseDirection(String directionString) {
return OrderDirection.valueOf(directionString.toLowerCase(java.util.Locale.ROOT));
}
private static Nulls parseNulls(String nullsString) {
return Nulls.valueOf(nullsString.toLowerCase(java.util.Locale.ROOT));
}
private static ConflictPolicy parseConflictPolicy(final Map<String, Object> listRule) {
final String policyString = (String) listRule.getOrDefault("onConflict", "error");
return ConflictPolicy.valueOf(policyString.trim());
}
private static void parseNullPolicy(
final Map<String, Object> root, final ImmutableMappingConfig.Builder builder) {
Object nullPolicyObject = root.get("nullPolicy");
if (!(nullPolicyObject instanceof Map<?, ?> nullPolicyMap)) {
return;
}
boolean blanksAsNulls = parseBlanksAsNulls(nullPolicyMap.get("blanksAsNulls"));
builder.nullPolicy(new MappingConfig.NullPolicy(blanksAsNulls));
}
private static boolean parseBlanksAsNulls(Object blanksAsNullsValue) {
if (blanksAsNullsValue instanceof Boolean booleanValue) {
return booleanValue;
}
return blanksAsNullsValue != null && Boolean.parseBoolean(String.valueOf(blanksAsNullsValue));
}
}