You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@juneau.apache.org by ja...@apache.org on 2026/09/15 17:21:55 UTC

(juneau) branch master updated: Publish ClassMeta into the marshaller cache only after swaps is assigned so concurrent Html.of never observes a half-constructed instance (Jenkins Java-17 concurrency 500).

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 0002c9410c Publish ClassMeta into the marshaller cache only after swaps is assigned so concurrent Html.of never observes a half-constructed instance (Jenkins Java-17 concurrency 500).
0002c9410c is described below

commit 0002c9410c7390e632d09197afdd3aabaeb92d60
Author: James Bognar <ja...@apache.org>
AuthorDate: Tue Sep 15 13:21:49 2026 -0400

    Publish ClassMeta into the marshaller cache only after swaps is assigned so concurrent Html.of never observes a half-constructed instance (Jenkins Java-17 concurrency 500).
---
 .../src/main/java/org/apache/juneau/marshall/ClassMeta.java    | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/ClassMeta.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/ClassMeta.java
index 73c981b27f..1f82033561 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/ClassMeta.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/ClassMeta.java
@@ -186,10 +186,6 @@ public final class ClassMeta<T> extends BeanInfo<T> {
 		this.marshallingContext = marshallingContext;
 		this.cat = new Categories();
 
-		// We always immediately add this class meta to the bean context cache so that we can resolve recursive references.
-		if (nn(marshallingContext) && nn(marshallingContext.getCmCache()) && isCacheable(innerClass))
-			marshallingContext.getCmCache().put(innerClass, this);
-
 		var ap = marshallingContext.getAnnotationProvider();
 
 		if (isAssignableTo(Delegate.class)) {
@@ -272,6 +268,12 @@ public final class ClassMeta<T> extends BeanInfo<T> {
 		swaps = memoize(this::findSwaps);
 
 		this.args = null;
+
+		// Publish after fields are assigned so concurrent getClassMeta callers never observe
+		// this instance with swaps == null.  Recursive bean-property lookups still resolve:
+		// they run from the lazy suppliers after construction, once this entry is cached.
+		if (nn(marshallingContext) && nn(marshallingContext.getCmCache()) && isCacheable(innerClass))
+			marshallingContext.getCmCache().put(innerClass, this);
 	}
 
 	protected ObjectSwap<?,?> findSwap(Class<?> c) {