This is an automated email from the ASF dual-hosted git repository.
jamesbognar pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/juneau.git
The following commit(s) were added to refs/heads/master by this push:
new 50edad73a9 READY-253 Cases 1-3 — pin acyclic invariants (BUG-17
false-positives): PathTraversal.JsonNode comment + Messages parent-chain
termination test + HttpPartSchema deep-nesting finiteness test. No wire change.
50edad73a9 is described below
commit 50edad73a9f010ba60caa4fa61b1f80a85295b95
Author: James Bognar <[email protected]>
AuthorDate: Fri Jul 17 09:52:25 2026 -0400
READY-253 Cases 1-3 — pin acyclic invariants (BUG-17 false-positives):
PathTraversal.JsonNode comment + Messages parent-chain termination test +
HttpPartSchema deep-nesting finiteness test. No wire change.
Co-authored-by: Cursor <[email protected]>
---
.../juneau/marshall/objecttools/PathTraversal.java | 1 +
.../java/org/apache/juneau/cp/Messages_Test.java | 22 +++++++++++++
.../httppart/HttpPartSchema_Validation_Test.java | 37 ++++++++++++++++++++++
3 files changed, 60 insertions(+)
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/objecttools/PathTraversal.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/objecttools/PathTraversal.java
index f34bb958ca..58fe8af031 100644
---
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/objecttools/PathTraversal.java
+++
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/objecttools/PathTraversal.java
@@ -139,6 +139,7 @@ import org.apache.juneau.marshall.parser.*;
"rawtypes" // Raw types necessary for generic type handling
})
public class PathTraversal {
+ // Internal traversal node — never serialized; 'parent' is an upward
tree pointer used only to walk back up the model during PUT/POST/DELETE
rewrites.
class JsonNode {
Object o;
ClassMeta cm;
diff --git
a/juneau-core/juneau-marshall/src/test/java/org/apache/juneau/cp/Messages_Test.java
b/juneau-core/juneau-marshall/src/test/java/org/apache/juneau/cp/Messages_Test.java
index 1849eb05b3..e3cf85eb64 100644
---
a/juneau-core/juneau-marshall/src/test/java/org/apache/juneau/cp/Messages_Test.java
+++
b/juneau-core/juneau-marshall/src/test/java/org/apache/juneau/cp/Messages_Test.java
@@ -165,4 +165,26 @@ class Messages_Test extends TestBase {
assertEquals("foo bar", x.getString("foo", "bar"));
assertEquals("fooja bar", x.forLocale(JAPAN).getString("foo",
"bar"));
}
+
+ @Test void a15_parentChainTerminationAndFlatness() {
+ // Invariant anchor: a Messages parent chain is a finite,
null-terminated singly-linked list, and
+ // toString() emits a FLAT key/value view (parent keys are
folded into the child keyMap at
+ // construction) rather than recursively stringifying the
parent2 back-reference. Serialization/
+ // toString() therefore terminates regardless of chain depth.
+ var leaf = Messages.of(Test2.class);
// deepest link: file, yyy
+ var mid =
Messages.create(MessageBundleTest1.class).parent(leaf).build(); // +
foo/bar/xx...
+ var top = Messages.chain(Messages.of(Test2.class), mid);
// 3-link chain
+
+ // (b) toString() returns finitely (no depth blow-up / no
infinite recursion into parent2).
+ var s = assertDoesNotThrow(top::toString);
+
+ // (a) The flattened view resolves keys contributed by every
level of the chain.
+ assertTrue(s.contains("yyy="), "Expected key contributed by the
deepest link (Test2)");
+ assertTrue(s.contains("bar="), "Expected key contributed by the
middle link (MessageBundleTest1)");
+ assertTrue(s.contains("foo="), "Expected key contributed by the
middle link (MessageBundleTest1)");
+ assertTrue(s.contains("file="), "Expected shared 'file' key");
+
+ // Flattening is not nested — the private parent2
back-reference is never exposed as a bean value.
+ assertFalse(s.contains("parent2"), "toString() must not expose
the parent2 back-reference");
+ }
}
\ No newline at end of file
diff --git
a/juneau-core/juneau-marshall/src/test/java/org/apache/juneau/marshall/httppart/HttpPartSchema_Validation_Test.java
b/juneau-core/juneau-marshall/src/test/java/org/apache/juneau/marshall/httppart/HttpPartSchema_Validation_Test.java
index 0c27908aed..d035174179 100644
---
a/juneau-core/juneau-marshall/src/test/java/org/apache/juneau/marshall/httppart/HttpPartSchema_Validation_Test.java
+++
b/juneau-core/juneau-marshall/src/test/java/org/apache/juneau/marshall/httppart/HttpPartSchema_Validation_Test.java
@@ -1385,4 +1385,41 @@ class HttpPartSchema_Validation_Test extends TestBase {
s.validateOutput(l("abc", "defghi"));
assertThrowsWithMessage(SchemaValidationException.class,
"Minimum length of value not met.", ()->s.validateOutput(l("a", "b")));
}
+
+
//-----------------------------------------------------------------------------------------------------------------
+ // Nested-schema finiteness invariant
+
//-----------------------------------------------------------------------------------------------------------------
+
+ @Test void t01_deepNesting_buildAndToStringFinite() {
+ // Invariant anchor: the nested items/additionalProperties
schema graph is an immutable DAG assembled
+ // bottom-up (each child is fully built before the parent's
final field is assigned), so build() and
+ // toString() over a deeply-nested schema are finite. The only
way to manufacture a cycle is a
+ // self-referential builder, which would
infinite-loop/StackOverflow at construction time and never
+ // reach here.
+ var depth = 100;
+ var b = HttpPartSchema.create().tString();
+ for (var i = 0; i < depth; i++) {
+ b = (i % 2 == 0)
+ ? HttpPartSchema.create().tArray().items(b)
+ :
HttpPartSchema.create().tObject().additionalProperties(b);
+ }
+ var built = b.build();
+
+ // toString()/serialize over the full nested graph returns
finitely (no depth blow-up).
+ var str = assertDoesNotThrow(built::toString);
+ assertNotNull(str);
+ assertFalse(str.isEmpty());
+
+ // The graph is fully materialized to the requested depth
(acyclic DAG, not truncated by a cycle guard).
+ var levels = 0;
+ var cur = built;
+ while (cur != null && levels <= depth + 5) {
+ levels++;
+ var next = cur.getItems();
+ if (next == null)
+ next = cur.getProperty("anyKey"); //
additionalProperties fallback
+ cur = next;
+ }
+ assertTrue(levels >= depth, "Expected the nested schema to be
reachable to full depth");
+ }
}