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 413ecc0727 Marshall module improvements
413ecc0727 is described below

commit 413ecc07278ef3c8520288b89e6191f94508dafd
Author: James Bognar <[email protected]>
AuthorDate: Mon Dec 8 17:11:01 2025 -0500

    Marshall module improvements
---
 .../juneau/bean/openapi3/OpenApiElement.java       |  1 +
 .../juneau/commons/utils/ThrowableUtils.java       | 56 ++++++++++++++++++++++
 .../main/java/org/apache/juneau/BeanContext.java   | 14 +++---
 .../src/main/java/org/apache/juneau/BeanMeta.java  | 36 +++++++-------
 4 files changed, 84 insertions(+), 23 deletions(-)

diff --git 
a/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/OpenApiElement.java
 
b/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/OpenApiElement.java
index 8811bf28b2..75e37864d9 100644
--- 
a/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/OpenApiElement.java
+++ 
b/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/OpenApiElement.java
@@ -31,6 +31,7 @@ import org.apache.juneau.json.*;
 /**
  * Root class for all Swagger beans.
  */
+@Bean
 public abstract class OpenApiElement {
 
        private boolean strict;
diff --git 
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/utils/ThrowableUtils.java
 
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/utils/ThrowableUtils.java
index f40f9ee7b0..fa75de05a8 100644
--- 
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/utils/ThrowableUtils.java
+++ 
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/utils/ThrowableUtils.java
@@ -181,6 +181,62 @@ public class ThrowableUtils {
                return sw.toString();
        }
 
+       /**
+        * Prints a stack trace with a maximum depth limit.
+        *
+        * <p>
+        * This method is useful for {@link StackOverflowError} situations 
where printing the full stack trace
+        * can cause additional errors due to stack exhaustion. The stack trace 
will be limited to the specified
+        * maximum number of elements.
+        *
+        * <h5 class='section'>Example:</h5>
+        * <p class='bjava'>
+        *      <jk>try</jk> {
+        *              <jc>// Some code that might cause 
StackOverflowError</jc>
+        *      } <jk>catch</jk> (StackOverflowError <jv>e</jv>) {
+        *              <jc>// Print only first 100 stack trace elements</jc>
+        *              ThrowableUtils.<jsm>printStackTrace</jsm>(<jv>e</jv>, 
System.err, 100);
+        *      }
+        * </p>
+        *
+        * @param t The throwable to print the stack trace for.
+        * @param pw The print writer to write to.
+        * @param maxDepth The maximum number of stack trace elements to print. 
If <jk>null</jk> or negative, prints all elements.
+        */
+       public static void printStackTrace(Throwable t, PrintWriter pw, Integer 
maxDepth) {
+               try {
+                       pw.println(t);
+                       var stackTrace = t.getStackTrace();
+                       var depth = maxDepth != null && maxDepth > 0 ? 
Math.min(maxDepth, stackTrace.length) : stackTrace.length;
+                       for (var i = 0; i < depth; i++) {
+                               pw.println("\tat " + stackTrace[i]);
+                       }
+                       if (maxDepth != null && maxDepth > 0 && 
stackTrace.length > maxDepth) {
+                               pw.println("\t... (" + (stackTrace.length - 
maxDepth) + " more)");
+                       }
+                       var cause = t.getCause();
+                       if (cause != null && cause != t) {
+                               pw.print("Caused by: ");
+                               printStackTrace(cause, pw, maxDepth);
+                       }
+               } catch (Exception e) {
+                       pw.println("Error printing stack trace: " + 
e.getMessage());
+               }
+       }
+
+       /**
+        * Prints a stack trace with a maximum depth limit to standard error.
+        *
+        * <p>
+        * Same as {@link #printStackTrace(Throwable, PrintWriter, Integer)} 
but writes to {@link System#err}.
+        *
+        * @param t The throwable to print the stack trace for.
+        * @param maxDepth The maximum number of stack trace elements to print. 
If <jk>null</jk> or negative, prints all elements.
+        */
+       public static void printStackTrace(Throwable t, Integer maxDepth) {
+               printStackTrace(t, new PrintWriter(System.err, true), maxDepth);
+       }
+
        /**
         * Same as {@link Throwable#getCause()} but searches the throwable 
chain for an exception of the specified type.
         *
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanContext.java 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanContext.java
index 667135d600..e5ec82be0b 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanContext.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanContext.java
@@ -4136,22 +4136,22 @@ public class BeanContext extends Context {
         * Determines whether the specified class is ignored as a bean class 
based on the various exclusion parameters
         * specified on this context class.
         *
-        * @param c The class type being tested.
+        * @param ci The class info being tested.
         * @return <jk>true</jk> if the specified class matches any of the 
exclusion parameters.
         */
-       protected final boolean isNotABean(Class<?> c) {
-               if (c.isArray() || c.isPrimitive() || c.isEnum() || 
c.isAnnotation())
+       protected final boolean isNotABean(ClassInfo ci) {
+               if (ci.isArray() || ci.isPrimitive() || ci.isEnum() || 
ci.isAnnotation())
                        return true;
-               Package p = c.getPackage();
+               var p = ci.getPackage();
                if (nn(p)) {
+                       var pn = p.getName();
                        for (var p2 : notBeanPackageNames)
-                               if (p.getName().equals(p2))
+                               if (pn.equals(p2))
                                        return true;
                        for (var p2 : notBeanPackagePrefixes)
-                               if (p.getName().startsWith(p2))
+                               if (pn.startsWith(p2))
                                        return true;
                }
-               var ci = info(c);
                for (var exclude : notBeanClassesArray)
                        if (ci.isChildOf(exclude))
                                return true;
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanMeta.java 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanMeta.java
index 1cb7ad4401..ac85da45f0 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanMeta.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanMeta.java
@@ -135,6 +135,22 @@ public class BeanMeta<T> {
         */
        public static <T> BeanMetaValue<T> create(ClassMeta<T> cm, BeanFilter 
bf, String[] pNames, ConstructorInfo implClassConstructor) {
                try {
+                       var bc = cm.getBeanContext();
+                       var ap = bc.getAnnotationProvider();
+
+                       // Sanity checks first.
+                       if (bc.isNotABean(cm))
+                               return notABean("Class matches exclude-class 
list");
+
+                       if (bf == null && bc.isBeansRequireSerializable() && ! 
cm.isChildOf(Serializable.class))
+                               return notABean("Class is not serializable");
+
+                       if (ap.has(BeanIgnore.class, cm))
+                               return notABean("Class is annotated with 
@BeanIgnore");
+
+                       if ((! 
bc.getBeanClassVisibility().isVisible(cm.getModifiers()) || 
cm.isAnonymousClass()) && ! ap.has(Bean.class, cm))
+                               return notABean("Class is not public");
+
                        var bm = new BeanMeta<>(cm, bf, pNames, 
implClassConstructor);
                        var nabr = bm.notABeanReason;
                        return new BeanMetaValue<>(nabr == null ? bm : null, 
nabr);
@@ -143,6 +159,10 @@ public class BeanMeta<T> {
                }
        }
 
+       private static <T> BeanMetaValue<T> notABean(String reason) {
+               return new BeanMetaValue<>(null, reason);
+       }
+
        /*
         * Temporary getter/setter method struct.
         */
@@ -253,7 +273,6 @@ public class BeanMeta<T> {
 
                        try {
                                var conVis = ctx.getBeanConstructorVisibility();
-                               var cVis = ctx.getBeanClassVisibility();
                                var mVis = ctx.getBeanMethodVisibility();
                                var fVis = ctx.getBeanFieldVisibility();
 
@@ -284,21 +303,6 @@ public class BeanMeta<T> {
                                Map<String,BeanPropertyMeta.Builder> 
normalProps = map();  // NOAI
 
                                var hasBean = ap.has(Bean.class, ci);
-                               var hasBeanIgnore = ap.has(BeanIgnore.class, 
ci);
-
-                               /// See if this class matches one the patterns 
in the exclude-class list.
-                               if (ctx.isNotABean(c))
-                                       return "Class matches exclude-class 
list";
-
-                               if (! hasBean && ! 
(cVis.isVisible(c.getModifiers()) || c.isAnonymousClass()))
-                                       return "Class is not public";
-
-                               if (hasBeanIgnore)
-                                       return "Class is annotated with 
@BeanIgnore";
-
-                               // Make sure it's serializable.
-                               if (beanFilter == null && 
ctx.isBeansRequireSerializable() && ! ci.isChildOf(Serializable.class))
-                                       return "Class is not serializable";
 
                                // Look for @Beanc constructor on public 
constructors.
                                ci.getPublicConstructors().stream().filter(x -> 
ap.has(Beanc.class, x)).forEach(x -> {

Reply via email to