diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/FeatureEventBuffer.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/FeatureEventBuffer.java index f28e0bcd7..3bbd877d7 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/FeatureEventBuffer.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/FeatureEventBuffer.java @@ -413,21 +413,33 @@ && positionOf(previous, mapping) == positionOf(child, mapping)) { } private static int positionOf(Node node, SchemaMapping mapping) { + if (node.position != Node.POSITION_UNCOMPUTED) { + return node.position; + } List path = node.path(); + int position; if (path.isEmpty()) { - return Integer.MAX_VALUE; + position = Integer.MAX_VALUE; + } else { + List positions = mapping.getPositionsForTargetPath(path); + int p = positions.isEmpty() ? -1 : positions.get(0); + // keep paths without a known position at the end, in their original (stable) order + position = p < 0 ? Integer.MAX_VALUE : p; } - List positions = mapping.getPositionsForTargetPath(path); - int position = positions.isEmpty() ? -1 : positions.get(0); - // keep paths without a known position at the end, in their original (stable) order - return position < 0 ? Integer.MAX_VALUE : position; + node.position = position; + return position; } private static final class Node { + private static final int POSITION_UNCOMPUTED = Integer.MIN_VALUE; + private final FeatureTokenType type; private final List open; private final List children = new ArrayList<>(); private List close; + // schema position (positionOf), memoized for the duration of one ordering pass: the sort + // comparator and the coalesce pass would otherwise re-resolve the same path on every comparison + private int position = POSITION_UNCOMPUTED; private Node(FeatureTokenType type, List open) { this.type = type;