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 1427c450e5 Marshall module improvements
1427c450e5 is described below
commit 1427c450e5498cfce49893f878bda35880621e0d
Author: James Bognar <[email protected]>
AuthorDate: Fri Dec 12 19:55:33 2025 -0500
Marshall module improvements
---
.../src/main/java/org/apache/juneau/Context.java | 327 ++++++++++-----------
.../java/org/apache/juneau/ContextSession.java | 2 +-
2 files changed, 163 insertions(+), 166 deletions(-)
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/Context.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/Context.java
index 1f11fa9150..fe8cea5341 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/Context.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/Context.java
@@ -74,93 +74,6 @@ import org.apache.juneau.xml.annotation.*;
*/
public abstract class Context {
- /*
- * Cache of static <c>create</c> methods that return builder instances
for context classes.
- *
- * <p>
- * This cache stores {@link MethodInfo} objects for public static
methods named <c>create</c> that return
- * builder objects. The methods are discovered by:
- * <ol>
- * <li>Finding public constructors that take a single parameter
(the builder type)
- * <li>Looking for a matching static <c>create</c> method that
returns the builder type
- * <li>Caching the result for future lookups
- * </ol>
- *
- * <p>
- * Used by {@link #createBuilder(Class)} to efficiently locate and
invoke builder creation methods.
- *
- * @see #createBuilder(Class)
- */
- private static final Cache<Class<?>,MethodInfo> BUILDER_CREATE_METHODS
= Cache.<Class<?>,MethodInfo>create()
- .supplier(type -> {
- var c = info(type);
- // @formatter:off
- return c.getPublicConstructors().stream()
- .filter(ci -> ci.hasNumParameters(1) && !
ci.getParameter(0).getParameterType().is(type))
- .map(ci -> c.getPublicMethod(
- x -> x.isStatic()
- && x.isNotDeprecated()
- && x.hasName("create")
- &&
x.hasReturnType(ci.getParameter(0).getParameterType())
- ).orElse(null))
- .filter(Objects::nonNull)
- .findFirst()
- .orElseThrow(() -> rex("Could not find builder
create method on class {0}", cn(type)));
- // @formatter:on
- })
- .build();
-
- /*
- * Cache of public constructors on context classes that accept builder
instances.
- *
- * <p>
- * This cache stores {@link ConstructorInfo} objects for public
constructors on context classes that take
- * a single parameter of the builder type. The constructor is
discovered by:
- * <ol>
- * <li>Finding public constructors on the context type that take
exactly one parameter
- * <li>Matching constructors where the parameter type is a parent
of (or equal to) the builder type
- * <li>Caching the result for future lookups
- * </ol>
- *
- * <p>
- * Used by {@link Builder#getContextConstructor()} to efficiently
locate and invoke context constructors
- * when building context instances from builders.
- *
- * @see Builder#getContextConstructor()
- * @see Builder#innerBuild()
- */
- private static final Cache2<Class<? extends Context>,Class<? extends
Builder>,ConstructorInfo> CONTEXT_CONSTRUCTORS = Cache2.<Class<? extends
Context>,Class<? extends Builder>,ConstructorInfo>create()
- .supplier((cacheType, builderType) -> {
- var ct = info(cacheType);
- var bt = info(builderType);
- return ct
- .getPublicConstructor(x ->
x.hasNumParameters(1) &&
x.getParameter(0).getParameterType().isParentOf(builderType))
- .orElseThrow(() -> rex("Public constructor not
found: {0}({1})", ct.getName(), bt.getName()));
- })
- .build();
-
-
- /*
- * Default annotation provider instance for finding annotations on
classes, methods, fields, and constructors.
- *
- * <p>
- * This is a static reference to {@link AnnotationProvider#INSTANCE},
used by the {@link Builder#traverse(AnnotationWorkList, Object)}
- * method to discover annotations that can be applied to context
builders.
- *
- * <p>
- * The annotation provider supports:
- * <ul>
- * <li>Finding annotations on classes, methods, fields, and
constructors
- * <li>Traversing class hierarchies (parent-to-child or
child-to-parent order)
- * <li>Supporting runtime annotations (annotations added
programmatically)
- * <li>Caching results for performance
- * </ul>
- *
- * @see AnnotationProvider
- * @see Builder#traverse(AnnotationWorkList, Object)
- */
- private static final AnnotationProvider AP =
AnnotationProvider.INSTANCE;
-
/**
* Builder class.
*/
@@ -170,9 +83,10 @@ public abstract class Context {
private Class<? extends Context> type;
private Context impl;
private List<Annotation> annotations;
- private Cache<HashKey,? extends Context> cache;
+ private Cache<HashKey,? extends Context> cache;
private final List<Object> builders = list();
+
private final AnnotationWorkList applied =
AnnotationWorkList.create();
/**
@@ -182,7 +96,7 @@ public abstract class Context {
@SuppressWarnings("unchecked")
protected Builder() {
debug = env("Context.debug", false);
- annotations = null;
+ annotations = list();
registerBuilders(this);
// By default, the type being created should be the
class declaring the builder.
@@ -199,7 +113,7 @@ public abstract class Context {
protected Builder(Builder copyFrom) {
debug = copyFrom.debug;
type = copyFrom.type;
- annotations = toList(copyFrom.annotations, true);
+ annotations = copyOf(copyFrom.annotations);
registerBuilders(this);
}
@@ -211,7 +125,7 @@ public abstract class Context {
protected Builder(Context copyFrom) {
debug = copyFrom.debug;
type = copyFrom.getClass();
- annotations = toList(copyFrom.annotations, true);
+ annotations = copyOf(copyFrom.annotations);
registerBuilders(this);
}
@@ -387,7 +301,7 @@ public abstract class Context {
* @return This object.
*/
public Builder annotations(Annotation...values) {
- annotations = addAll(annotations, values);
+ annotations.addAll(l(values));
return this;
}
@@ -399,7 +313,7 @@ public abstract class Context {
* @return This object.
*/
public Builder annotations(List<Annotation> values) {
- annotations = addAll(annotations, values);
+ annotations.addAll(values);
return this;
}
@@ -437,32 +351,6 @@ public abstract class Context {
return this;
}
- /**
- * Returns this builder cast to the specified subtype if it is
an instance of that type.
- *
- * <p>
- * This is a type-safe way to check if this builder is an
instance of a specific builder subtype
- * and cast it accordingly. Returns an empty {@link Optional}
if this builder is not an instance
- * of the specified subtype.
- *
- * <h5 class='section'>Example:</h5>
- * <p class='bjava'>
- * Builder <jv>b</jv> = JsonSerializer.<jsm>create</jsm>();
- * Optional<JsonSerializer.Builder>
<jv>jsonBuilder</jv> =
<jv>b</jv>.asSubtype(JsonSerializer.Builder.<jk>class</jk>);
- * <jk>if</jk> (<jv>jsonBuilder</jv>.isPresent()) {
- * <jc>// Use JsonSerializer.Builder-specific
methods</jc>
- * <jv>jsonBuilder</jv>.get().pretty();
- * }
- * </p>
- *
- * @param <T> The builder subtype.
- * @param subtype The builder subtype class to cast to.
- * @return An {@link Optional} containing this builder cast to
the subtype, or empty if not an instance.
- */
- public <T extends Builder> Optional<T> asSubtype(Class<T>
subtype) {
- return opt(subtype.isInstance(this) ?
subtype.cast(this) : null);
- }
-
/**
* Same as {@link #applyAnnotations(Object...)} but explicitly
specifies a class varargs to avoid compilation warnings.
*
@@ -561,6 +449,32 @@ public abstract class Context {
return apply(work);
}
+ /**
+ * Returns this builder cast to the specified subtype if it is
an instance of that type.
+ *
+ * <p>
+ * This is a type-safe way to check if this builder is an
instance of a specific builder subtype
+ * and cast it accordingly. Returns an empty {@link Optional}
if this builder is not an instance
+ * of the specified subtype.
+ *
+ * <h5 class='section'>Example:</h5>
+ * <p class='bjava'>
+ * Builder <jv>b</jv> = JsonSerializer.<jsm>create</jsm>();
+ * Optional<JsonSerializer.Builder>
<jv>jsonBuilder</jv> =
<jv>b</jv>.asSubtype(JsonSerializer.Builder.<jk>class</jk>);
+ * <jk>if</jk> (<jv>jsonBuilder</jv>.isPresent()) {
+ * <jc>// Use JsonSerializer.Builder-specific
methods</jc>
+ * <jv>jsonBuilder</jv>.get().pretty();
+ * }
+ * </p>
+ *
+ * @param <T> The builder subtype.
+ * @param subtype The builder subtype class to cast to.
+ * @return An {@link Optional} containing this builder cast to
the subtype, or empty if not an instance.
+ */
+ public <T extends Builder> Optional<T> asSubtype(Class<T>
subtype) {
+ return opt(subtype.isInstance(this) ?
subtype.cast(this) : null);
+ }
+
/**
* Build the object.
*
@@ -737,37 +651,6 @@ public abstract class Context {
return this;
}
- private ConstructorInfo getContextConstructor() {
- return CONTEXT_CONSTRUCTORS.get(type, getClass());
- }
-
- private Context innerBuild() {
- if (type == null)
- throw rex("Type not specified for context
builder {0}", cn(getClass()));
- if (nn(impl) && type.isInstance(impl))
- return type.cast(impl);
- if (nn(cache))
- return cache.get(hashKey(), () ->
getContextConstructor().newInstance(this));
- return getContextConstructor().newInstance(this);
- }
-
- private static AnnotationWorkList traverse(AnnotationWorkList
work, Object x) {
- var ap = AP;
- CollectionUtils.traverse(x, y -> {
- if (x instanceof Class<?> x2)
-
work.add(rstream(ap.find(info(x2))).filter(CONTEXT_APPLY_FILTER));
- else if (x instanceof ClassInfo x2)
-
work.add(rstream(ap.find(x2)).filter(CONTEXT_APPLY_FILTER));
- else if (x instanceof Method x2)
-
work.add(rstream(ap.find(info(x2))).filter(CONTEXT_APPLY_FILTER));
- else if (x instanceof MethodInfo x2)
-
work.add(rstream(ap.find(x2)).filter(CONTEXT_APPLY_FILTER));
- else
- illegalArg("Invalid type passed to
applyAnnotations: {0}", cn(x));
- });
- return work;
- }
-
/**
* Registers the specified secondary builders with this context
builder.
*
@@ -786,8 +669,109 @@ public abstract class Context {
this.builders.add(b);
}
}
+
+ private ConstructorInfo getContextConstructor() {
+ return CONTEXT_CONSTRUCTORS.get(type, getClass());
+ }
+
+ private Context innerBuild() {
+ if (type == null)
+ throw rex("Type not specified for context
builder {0}", cn(getClass()));
+ if (nn(impl) && type.isInstance(impl))
+ return type.cast(impl);
+ if (nn(cache))
+ return cache.get(hashKey(), () ->
getContextConstructor().newInstance(this));
+ return getContextConstructor().newInstance(this);
+ }
}
+ /*
+ * Cache of static <c>create</c> methods that return builder instances
for context classes.
+ *
+ * <p>
+ * This cache stores {@link MethodInfo} objects for public static
methods named <c>create</c> that return
+ * builder objects. The methods are discovered by:
+ * <ol>
+ * <li>Finding public constructors that take a single parameter
(the builder type)
+ * <li>Looking for a matching static <c>create</c> method that
returns the builder type
+ * <li>Caching the result for future lookups
+ * </ol>
+ *
+ * <p>
+ * Used by {@link #createBuilder(Class)} to efficiently locate and
invoke builder creation methods.
+ *
+ * @see #createBuilder(Class)
+ */
+ private static final Cache<Class<?>,MethodInfo> BUILDER_CREATE_METHODS
= Cache.<Class<?>,MethodInfo>create()
+ .supplier(type -> {
+ var c = info(type);
+ // @formatter:off
+ return c.getPublicConstructors().stream()
+ .filter(ci -> ci.hasNumParameters(1) && !
ci.getParameter(0).getParameterType().is(type))
+ .map(ci -> c.getPublicMethod(
+ x -> x.isStatic()
+ && x.isNotDeprecated()
+ && x.hasName("create")
+ &&
x.hasReturnType(ci.getParameter(0).getParameterType())
+ ).orElse(null))
+ .filter(Objects::nonNull)
+ .findFirst()
+ .orElseThrow(() -> rex("Could not find builder
create method on class {0}", cn(type)));
+ // @formatter:on
+ })
+ .build();
+
+
+ /*
+ * Cache of public constructors on context classes that accept builder
instances.
+ *
+ * <p>
+ * This cache stores {@link ConstructorInfo} objects for public
constructors on context classes that take
+ * a single parameter of the builder type. The constructor is
discovered by:
+ * <ol>
+ * <li>Finding public constructors on the context type that take
exactly one parameter
+ * <li>Matching constructors where the parameter type is a parent
of (or equal to) the builder type
+ * <li>Caching the result for future lookups
+ * </ol>
+ *
+ * <p>
+ * Used by {@link Builder#getContextConstructor()} to efficiently
locate and invoke context constructors
+ * when building context instances from builders.
+ *
+ * @see Builder#getContextConstructor()
+ * @see Builder#innerBuild()
+ */
+ private static final Cache2<Class<? extends Context>,Class<? extends
Builder>,ConstructorInfo> CONTEXT_CONSTRUCTORS = Cache2.<Class<? extends
Context>,Class<? extends Builder>,ConstructorInfo>create()
+ .supplier((cacheType, builderType) -> {
+ var ct = info(cacheType);
+ var bt = info(builderType);
+ return ct
+ .getPublicConstructor(x ->
x.hasNumParameters(1) &&
x.getParameter(0).getParameterType().isParentOf(builderType))
+ .orElseThrow(() -> rex("Public constructor not
found: {0}({1})", ct.getName(), bt.getName()));
+ })
+ .build();
+
+ /*
+ * Default annotation provider instance for finding annotations on
classes, methods, fields, and constructors.
+ *
+ * <p>
+ * This is a static reference to {@link AnnotationProvider#INSTANCE},
used by the {@link Builder#traverse(AnnotationWorkList, Object)}
+ * method to discover annotations that can be applied to context
builders.
+ *
+ * <p>
+ * The annotation provider supports:
+ * <ul>
+ * <li>Finding annotations on classes, methods, fields, and
constructors
+ * <li>Traversing class hierarchies (parent-to-child or
child-to-parent order)
+ * <li>Supporting runtime annotations (annotations added
programmatically)
+ * <li>Caching results for performance
+ * </ul>
+ *
+ * @see AnnotationProvider
+ * @see Builder#traverse(AnnotationWorkList, Object)
+ */
+ private static final AnnotationProvider AP =
AnnotationProvider.INSTANCE;
+
/**
* Predicate for annotations that themselves are annotated with {@link
ContextApply}.
*/
@@ -805,18 +789,31 @@ public abstract class Context {
*/
public static Builder createBuilder(Class<? extends Context> type) {
try {
- MethodInfo mi = BUILDER_CREATE_METHODS.get(type);
- var b = (Builder)mi.invoke(null);
- b.type(type);
- return b;
+ return
((Builder)BUILDER_CREATE_METHODS.get(type).invoke(null)).type(type);
} catch (ExecutableException e) {
throw toRex(e);
}
}
- final List<Annotation> annotations;
- final boolean debug;
+ private static AnnotationWorkList traverse(AnnotationWorkList work,
Object x) {
+ var ap = AP;
+ CollectionUtils.traverse(x, y -> {
+ if (x instanceof Class<?> x2)
+
work.add(rstream(ap.find(info(x2))).filter(CONTEXT_APPLY_FILTER));
+ else if (x instanceof ClassInfo x2)
+
work.add(rstream(ap.find(x2)).filter(CONTEXT_APPLY_FILTER));
+ else if (x instanceof Method x2)
+
work.add(rstream(ap.find(info(x2))).filter(CONTEXT_APPLY_FILTER));
+ else if (x instanceof MethodInfo x2)
+
work.add(rstream(ap.find(x2)).filter(CONTEXT_APPLY_FILTER));
+ else
+ illegalArg("Invalid type passed to
applyAnnotations: {0}", cn(x));
+ });
+ return work;
+ }
+ private final List<Annotation> annotations;
+ private final boolean debug;
private final AnnotationProvider annotationProvider;
/**
@@ -827,7 +824,7 @@ public abstract class Context {
protected Context(Builder builder) {
init(builder);
debug = builder.debug;
- annotations =
opt(builder.annotations).orElseGet(Collections::emptyList);
+ annotations = copyOf(builder.annotations);
annotationProvider =
AnnotationProvider.create().addRuntimeAnnotations(annotations).build();
}
@@ -837,18 +834,11 @@ public abstract class Context {
* @param copyFrom The context to copy from.
*/
protected Context(Context copyFrom) {
- annotations = copyFrom.annotations;
+ annotations = copyOf(copyFrom.annotations);
debug = copyFrom.debug;
annotationProvider = copyFrom.annotationProvider;
}
- /**
- * Returns the annotation provider for this context.
- *
- * @return The annotation provider for this context.
- */
- public AnnotationProvider getAnnotationProvider() { return
annotationProvider; }
-
/**
* Creates a builder from this context object.
*
@@ -874,6 +864,13 @@ public abstract class Context {
throw unsupportedOp();
}
+ /**
+ * Returns the annotation provider for this context.
+ *
+ * @return The annotation provider for this context.
+ */
+ public AnnotationProvider getAnnotationProvider() { return
annotationProvider; }
+
/**
* Returns a session to use for this context.
*
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ContextSession.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ContextSession.java
index 73ebe88fc2..a61488641a 100644
---
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ContextSession.java
+++
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ContextSession.java
@@ -55,7 +55,7 @@ public abstract class ContextSession {
*/
protected Builder(Context ctx) {
this.ctx = ctx;
- debug = ctx.debug;
+ debug = ctx.isDebug();
}
/**