ArrayBucket.java
package io.github.pojotools.flat2pojo.core.engine;
import com.fasterxml.jackson.databind.node.ObjectNode;
import java.util.*;
public final class ArrayBucket {
private final Map<CompositeKey, ObjectNode> byKey = new LinkedHashMap<>();
private List<ObjectNode> cachedSortedElements;
private List<Comparator<ObjectNode>> lastComparators;
/**
* Upserts an element into the bucket.
*
* <p>Production behavior: Always called with an empty candidate node. When a key exists, it
* returns the existing node unchanged. When the key is new, inserts and returns the candidate.
*
* <p>This implements first-write-wins semantics: the first insert establishes the node, later
* upserts with the same key return the existing node without modification.
*
* @param key composite key identifying the element
* @param candidate node to insert (production: always empty; will be populated by callers)
* @return the node in the bucket (either newly inserted or pre-existing)
*/
public ObjectNode upsert(CompositeKey key, ObjectNode candidate) {
Objects.requireNonNull(key, "key must not be null");
Objects.requireNonNull(candidate, "candidate must not be null");
return existsInBucket(key) ? byKey.get(key) : insertNew(key, candidate);
}
private boolean existsInBucket(CompositeKey key) {
return byKey.containsKey(key);
}
private ObjectNode insertNew(CompositeKey key, ObjectNode candidate) {
byKey.put(key, candidate);
invalidateCache();
return candidate;
}
private void invalidateCache() {
cachedSortedElements = null;
lastComparators = null;
}
public List<ObjectNode> ordered(List<Comparator<ObjectNode>> comparators) {
if (isCached(comparators)) {
return cachedSortedElements;
}
List<ObjectNode> elements = sortElements(comparators);
cacheResults(comparators, elements);
return elements;
}
private boolean isCached(List<Comparator<ObjectNode>> comparators) {
return cachedSortedElements != null && Objects.equals(lastComparators, comparators);
}
private List<ObjectNode> sortElements(List<Comparator<ObjectNode>> comparators) {
List<ObjectNode> elements = new ArrayList<>(byKey.values());
if (!comparators.isEmpty()) {
elements.sort(buildCombinedComparator(comparators));
}
return elements;
}
private Comparator<ObjectNode> buildCombinedComparator(List<Comparator<ObjectNode>> comparators) {
return comparators.stream().reduce(Comparator::thenComparing).orElseThrow();
}
private void cacheResults(List<Comparator<ObjectNode>> comparators, List<ObjectNode> elements) {
cachedSortedElements = elements;
lastComparators = new ArrayList<>(comparators);
}
}