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

commit f3f91065bf854aa1b51ca89543166b6ae20bbac8
Author: James Bognar <[email protected]>
AuthorDate: Mon Dec 8 12:26:02 2025 -0500

    Marshall module improvements
---
 TODO.md                                            |  3 +-
 .../src/main/java/org/apache/juneau/ClassMeta.java | 48 ++++++++++++----------
 2 files changed, 29 insertions(+), 22 deletions(-)

diff --git a/TODO.md b/TODO.md
index 547b30d4d7..a928b0298f 100644
--- a/TODO.md
+++ b/TODO.md
@@ -1,6 +1,6 @@
 # TODO List
 
-**Last generated TODO number: TODO-93**
+**Last generated TODO number: TODO-94**
 
 This file tracks pending tasks for the Apache Juneau project. For completed 
items, see [TODO-completed.md](TODO-completed.md).
 
@@ -28,6 +28,7 @@ This file tracks pending tasks for the Apache Juneau project. 
For completed item
 - [ ] TODO-21 Thrown NotFound causes - javax.servlet.ServletException: Invalid 
method response: 200
 - [x] TODO-89 Add ClassInfoTyped
 - [ ] TODO-91 Security: LogsResource returns HTTP 500 instead of 404 for 
malformed query parameters (CWE-74). When accessing log file URLs with encoded 
special characters in query parameters (e.g., `?method=VIEW%5C%5C%5C%22`), the 
system returns HTTP 500 "Invalid method response: 200" instead of HTTP 404. The 
error suggests it's incorrectly trying to find a Java method matching a 
malformed path. Should return 404 for invalid/malformed requests.
+- [ ] TODO-94 Add a "cloaked" mode to IRS to always return 404s in place of 
40x/50x responses.
 
 ## HTTP Response/Exception Improvements
 
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ClassMeta.java 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ClassMeta.java
index f8f04078f7..3c3cb9b435 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ClassMeta.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ClassMeta.java
@@ -146,7 +146,7 @@ public class ClassMeta<T> extends ClassInfoTyped<T> {
        private final List<ObjectSwap<?,?>> childSwaps;                         
   // Any ObjectSwaps where the normal type is a subclass of this class.
        private final Cache<Class<?>,ObjectSwap<?,?>> childUnswapMap;           
   // Maps swap subclasses to ObjectSwaps.
        private final Supplier<String> dictionaryName;                          
   // The dictionary name of this class if it has one.
-       private final ClassMeta<?> elementType;                                 
   // If ARRAY or COLLECTION, the element class type.
+       private final Supplier<ClassMeta<?>> elementType;                       
   // If ARRAY or COLLECTION, the element class type.
        private final OptionalSupplier<String> example;                         
   // Example JSON.
        private final OptionalSupplier<FieldInfo> exampleField;                 
   // The @Example-annotated field (if it has one).
        private final OptionalSupplier<MethodInfo> exampleMethod;               
   // The example() or @Example-annotated method (if it has one).
@@ -258,20 +258,8 @@ public class ClassMeta<T> extends ClassInfoTyped<T> {
                        example = memoize(()->findExample());
                        implClass = memoize(()->findImplClass());
 
-                       var _elementType = (ClassMeta<?>)null;
-                       if (cat.is(ARRAY)) {
-                               _elementType = 
beanContext.getClassMeta(inner().getComponentType(), false);
-                       } else if (cat.is(COLLECTION) || is(Optional.class)) {
-                               // If this is a COLLECTION, see if it's 
parameterized (e.g. AddressBook extends LinkedList<Person>)
-                               var parameters = 
beanContext.findParameters(inner(), inner());
-                               if (nn(parameters) && parameters.length == 1) {
-                                       _elementType = parameters[0];
-                               } else {
-                                       _elementType = 
beanContext.getClassMeta(Object.class);
-                               }
-                       }
-                       this.elementType = _elementType;
                        this.keyValueTypes = memoize(()->findKeyValueTypes());
+                       this.elementType = memoize(()->findElementType());
 
                        this.beanMeta = memoize(()->findBeanMeta());
                        this.enumValues = memoize(()->findEnumValues());
@@ -334,7 +322,7 @@ public class ClassMeta<T> extends ClassInfoTyped<T> {
                this.childUnswapMap = null;
                this.cat = new Categories().set(ARGS);
                this.beanContext = null;
-               this.elementType = null;
+               this.elementType = memoize(()->findElementType());
                this.keyValueTypes = memoize(()->findKeyValueTypes());
                this.proxyInvocationHandler = null;
                this.beanMeta = memoize(()->findBeanMeta());
@@ -370,7 +358,7 @@ public class ClassMeta<T> extends ClassInfoTyped<T> {
                this.cat = mainType.cat;
                this.fromStringMethod = mainType.fromStringMethod;
                this.beanContext = mainType.beanContext;
-               this.elementType = elementType;
+               this.elementType = elementType != null ? 
memoize(()->elementType) : mainType.elementType;
                this.keyValueTypes = (keyType != null || valueType != null) ? 
memoize(()->Tuple2.of(keyType, valueType)) : mainType.keyValueTypes;
                this.proxyInvocationHandler = mainType.proxyInvocationHandler;
                this.beanMeta = mainType.beanMeta;
@@ -419,7 +407,7 @@ public class ClassMeta<T> extends ClassInfoTyped<T> {
        public boolean canCreateNewInstance() {
                if (isMemberClass() && isNotStatic())
                        return false;
-               if (noArgConstructor.isPresent() || 
proxyInvocationHandler.isPresent() || (isArray() && 
elementType.canCreateNewInstance()))
+               if (noArgConstructor.isPresent() || 
proxyInvocationHandler.isPresent() || (isArray() && 
elementType.get().canCreateNewInstance()))
                        return true;
                return false;
        }
@@ -564,7 +552,7 @@ public class ClassMeta<T> extends ClassInfoTyped<T> {
         *
         * @return The element class type, or <jk>null</jk> if this class is 
not an array or Collection.
         */
-       public ClassMeta<?> getElementType() { return elementType; }
+       public ClassMeta<?> getElementType() { return elementType.get(); }
 
        /**
         * Returns the example of this class.
@@ -1388,6 +1376,22 @@ public class ClassMeta<T> extends ClassInfoTyped<T> {
                return Tuple2.of(null,null);
        }
 
+       private ClassMeta<?> findElementType() {
+               if (beanContext == null)
+                       return null;
+               if (cat.is(ARRAY)) {
+                       return 
beanContext.getClassMeta(inner().getComponentType(), false);
+               } else if (cat.is(COLLECTION) || is(Optional.class)) {
+                       // If this is a COLLECTION, see if it's parameterized 
(e.g. AddressBook extends LinkedList<Person>)
+                       var parameters = beanContext.findParameters(inner(), 
inner());
+                       if (nn(parameters) && parameters.length == 1) {
+                               return parameters[0];
+                       }
+                       return beanContext.getClassMeta(Object.class);
+               }
+               return null;
+       }
+
        @SuppressWarnings("unchecked")
        private BuilderSwap<T,?> findBuilderSwap() {
                var bc = beanContext;
@@ -1743,7 +1747,7 @@ public class ClassMeta<T> extends ClassInfoTyped<T> {
                        n = n.substring(i == -1 ? 0 : i + 1).replace('$', '.');
                }
                if (cat.is(ARRAY))
-                       return elementType.toString(sb, 
simple).append('[').append(']');
+                       return elementType.get().toString(sb, 
simple).append('[').append(']');
                if (cat.is(BEANMAP))
                        return 
sb.append(cn(BeanMap.class)).append('<').append(n).append('>');
                if (cat.is(MAP)) {
@@ -1754,8 +1758,10 @@ public class ClassMeta<T> extends ClassInfoTyped<T> {
                                return sb.append(n);
                        return sb.append(n).append('<').append(kt == null ? "?" 
: kt.toString(simple)).append(',').append(vt == null ? "?" : 
vt.toString(simple)).append('>');
                }
-               if (cat.is(COLLECTION) || is(Optional.class))
-                       return sb.append(n).append(elementType.isObject() ? "" 
: "<" + elementType.toString(simple) + ">");
+               if (cat.is(COLLECTION) || is(Optional.class)) {
+                       var et = elementType.get();
+                       return sb.append(n).append(et != null && et.isObject() 
? "" : "<" + (et == null ? "?" : et.toString(simple)) + ">");
+               }
                return sb.append(n);
        }
 

Reply via email to