RootKeyGrouper.java
package io.github.pojotools.flat2pojo.core.impl;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
/**
* Groups flat rows by root keys (single or composite). Single Responsibility: Root key-based
* grouping logic only.
*
* <p>Implementation note: Uses LinkedHashMap to preserve insertion order of groups, ensuring
* deterministic output when processing rows in sequence.
*/
final class RootKeyGrouper {
private RootKeyGrouper() {}
/**
* Groups rows by root keys, preserving the order in which groups are first encountered.
*
* <p>Rows with missing or null root key values are skipped entirely.
*
* @param rows input rows to group
* @param rootKeys keys to group by (single or composite)
* @return map of key values to row lists, ordered by first appearance
*/
static Map<Object, List<Map<String, ?>>> groupByRootKeys(
final List<? extends Map<String, ?>> rows, final List<String> rootKeys) {
return rootKeys.size() == 1
? groupBySingleKey(rows, rootKeys.getFirst())
: groupByCompositeKey(rows, rootKeys);
}
private static Map<Object, List<Map<String, ?>>> groupBySingleKey(
final List<? extends Map<String, ?>> rows, final String key) {
final Map<Object, List<Map<String, ?>>> groups = new LinkedHashMap<>();
for (final Map<String, ?> row : rows) {
final Object keyValue = row.get(key);
if (keyValue != null) {
groups.computeIfAbsent(keyValue, k -> new ArrayList<>()).add(row);
}
}
return groups;
}
private static Map<Object, List<Map<String, ?>>> groupByCompositeKey(
final List<? extends Map<String, ?>> rows, final List<String> rootKeys) {
final Map<Object, List<Map<String, ?>>> groups = new LinkedHashMap<>();
for (final Map<String, ?> row : rows) {
final List<Object> compositeKey = buildCompositeKey(row, rootKeys);
if (compositeKey != null) {
groups.computeIfAbsent(compositeKey, k -> new ArrayList<>()).add(row);
}
}
return groups;
}
@SuppressWarnings("PMD.ReturnEmptyCollectionRatherThanNull")
private static List<Object> buildCompositeKey(
final Map<String, ?> row, final List<String> rootKeys) {
final List<Object> compositeKey = new ArrayList<>(rootKeys.size());
for (final String rootKey : rootKeys) {
final Object value = row.get(rootKey);
if (value == null) {
return null;
}
compositeKey.add(value);
}
return compositeKey;
}
}