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

commit 150725cb4efabb22e091e0d0c9cd4b87b9300b75
Author: James Bognar <[email protected]>
AuthorDate: Mon Dec 8 14:16:22 2025 -0500

    Marshall module improvements
---
 .../src/main/java/org/apache/juneau/BeanMeta.java  | 72 ++++++++++++++++++++--
 .../src/main/java/org/apache/juneau/ClassMeta.java | 64 ++++++++-----------
 2 files changed, 94 insertions(+), 42 deletions(-)

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 b6514f0228..1cb7ad4401 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
@@ -33,7 +33,6 @@ import java.util.function.*;
 
 import org.apache.juneau.annotation.*;
 import org.apache.juneau.commons.collections.*;
-import org.apache.juneau.commons.function.*;
 import org.apache.juneau.commons.function.OptionalSupplier;
 import org.apache.juneau.commons.reflect.*;
 import org.apache.juneau.commons.reflect.Visibility;
@@ -69,13 +68,78 @@ import org.apache.juneau.commons.utils.*;
  */
 public class BeanMeta<T> {
 
-       public static <T> Tuple2<BeanMeta<T>,String> create(ClassMeta<T> cm, 
BeanFilter bf, String[] pNames, ConstructorInfo implClassConstructor) {
+       /**
+        * Represents the result of creating a BeanMeta, including the bean 
metadata and any reason why it's not a bean.
+        *
+        * @param <T> The bean type.
+        * @param beanMeta The bean metadata, or <jk>null</jk> if the class is 
not a bean.
+        * @param notABeanReason The reason why the class is not a bean, or 
<jk>null</jk> if it is a bean.
+        */
+       record BeanMetaValue<T>(BeanMeta<T> beanMeta, String notABeanReason) {
+               Optional<BeanMeta<T>> optBeanMeta() { return opt(beanMeta()); }
+               Optional<String> optNotABeanReason() { return 
opt(notABeanReason()); }
+       }
+
+       /**
+        * Creates a {@link BeanMeta} instance for the specified class metadata.
+        *
+        * <p>
+        * This is a factory method that attempts to create bean metadata for a 
class. If the class is determined to be a bean,
+        * the returned {@link BeanMetaValue} will contain the {@link BeanMeta} 
instance and a <jk>null</jk> reason.
+        * If the class is not a bean, the returned value will contain 
<jk>null</jk> for the bean metadata and a non-null
+        * string explaining why it's not a bean.
+        *
+        * <h5 class='section'>Parameters:</h5>
+        * <ul class='spaced-list'>
+        *      <li><b>cm</b> - The class metadata for the class to create bean 
metadata for.
+        *      <li><b>bf</b> - Optional bean filter to apply. Can be 
<jk>null</jk>.
+        *      <li><b>pNames</b> - Explicit list of property names and order. 
If <jk>null</jk>, properties are determined automatically.
+        *      <li><b>implClassConstructor</b> - Optional constructor to use 
if one cannot be found. Can be <jk>null</jk>.
+        * </ul>
+        *
+        * <h5 class='section'>Return Value:</h5>
+        * <p>
+        * Returns a {@link BeanMetaValue} containing:
+        * <ul>
+        *      <li><b>beanMeta</b> - The bean metadata if the class is a bean, 
or <jk>null</jk> if it's not.
+        *      <li><b>notABeanReason</b> - A string explaining why the class 
is not a bean, or <jk>null</jk> if it is a bean.
+        * </ul>
+        *
+        * <h5 class='section'>Exception Handling:</h5>
+        * <p>
+        * If a {@link RuntimeException} is thrown during bean metadata 
creation, it is caught and the exception message
+        * is returned as the <c>notABeanReason</c> with <jk>null</jk> for the 
bean metadata.
+        *
+        * <h5 class='section'>Example:</h5>
+        * <p class='bjava'>
+        *      <jc>// Create bean metadata for a class</jc>
+        *      ClassMeta&lt;Person&gt; <jv>cm</jv> = 
<jv>beanContext</jv>.getClassMeta(Person.<jk>class</jk>);
+        *      BeanMetaValue&lt;Person&gt; <jv>result</jv> = 
BeanMeta.<jsm>create</jsm>(<jv>cm</jv>, <jk>null</jk>, <jk>null</jk>, 
<jk>null</jk>);
+        *
+        *      <jc>// Check if it's a bean</jc>
+        *      <jk>if</jk> (<jv>result</jv>.beanMeta() != <jk>null</jk>) {
+        *              BeanMeta&lt;Person&gt; <jv>bm</jv> = 
<jv>result</jv>.beanMeta();
+        *              <jc>// Use the bean metadata...</jc>
+        *      } <jk>else</jk> {
+        *              String <jv>reason</jv> = 
<jv>result</jv>.notABeanReason();
+        *              <jc>// Handle the case where it's not a bean...</jc>
+        *      }
+        * </p>
+        *
+        * @param <T> The class type.
+        * @param cm The class metadata for the class to create bean metadata 
for.
+        * @param bf Optional bean filter to apply. Can be <jk>null</jk>.
+        * @param pNames Explicit list of property names and order. If 
<jk>null</jk>, properties are determined automatically.
+        * @param implClassConstructor Optional constructor to use if one 
cannot be found. Can be <jk>null</jk>.
+        * @return A {@link BeanMetaValue} containing the bean metadata (if 
successful) or a reason why it's not a bean.
+        */
+       public static <T> BeanMetaValue<T> create(ClassMeta<T> cm, BeanFilter 
bf, String[] pNames, ConstructorInfo implClassConstructor) {
                try {
                        var bm = new BeanMeta<>(cm, bf, pNames, 
implClassConstructor);
                        var nabr = bm.notABeanReason;
-                       return Tuple2.of(nabr == null ? bm : null, nabr);
+                       return new BeanMetaValue<>(nabr == null ? bm : null, 
nabr);
                } catch (RuntimeException e) {
-                       return Tuple2.of(null, e.getMessage());
+                       return new BeanMetaValue<>(null, e.getMessage());
                }
        }
 
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 c98d043005..0645b11760 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
@@ -165,18 +165,13 @@ public class ClassMeta<T> extends ClassInfoTyped<T> {
        private final OptionalSupplier<ConstructorInfo> stringConstructor;      
   // The X(String) constructor (if it has one).
        private final Supplier<List<ObjectSwap<T,?>>> swaps;                    
   // The object POJO swaps associated with this bean (if it has any).
        private final Map<Class<?>,Mutater<T,?>> toMutaters = new 
ConcurrentHashMap<>();
-       private final OptionalSupplier<BeanMetaValue<T>> beanMeta;
+       private final OptionalSupplier<BeanMeta.BeanMetaValue<T>> beanMeta;
 
        record KeyValueTypes(ClassMeta<?> keyType, ClassMeta<?> valueType) {
                Optional<ClassMeta<?>> optKeyType() { return opt(keyType()); }
                Optional<ClassMeta<?>> optValueType() { return 
opt(valueType()); }
        }
 
-       record BeanMetaValue<T>(BeanMeta<T> beanMeta, String notABeanReason) {
-               Optional<BeanMeta<T>> optBeanMeta() { return opt(beanMeta()); }
-               Optional<String> optNotABeanReason() { return 
opt(notABeanReason()); }
-       }
-
        /**
         * Construct a new {@code ClassMeta} based on the specified {@link 
Class}.
         *
@@ -243,31 +238,27 @@ public class ClassMeta<T> extends ClassInfoTyped<T> {
                                cat.set(INPUTSTREAM);
                        }
 
-                       fromStringMethod = memoize(()->findFromStringMethod());
-                       exampleMethod = memoize(()->findExampleMethod());
-                       parentProperty = memoize(()->findParentProperty());
-                       nameProperty = memoize(()->findNameProperty());
-                       exampleField = memoize(()->findExampleField());
-                       noArgConstructor = memoize(()->findNoArgConstructor());
-                       stringConstructor = 
memoize(()->findStringConstructor());
                        beanFilter = memoize(()->findBeanFilter());
-                       marshalledFilter = memoize(()->findMarshalledFilter());
+                       beanMeta = memoize(()->findBeanMeta());
                        builderSwap = memoize(()->findBuilderSwap());
+                       childSwapMap = 
Cache.<Class<?>,ObjectSwap<?,?>>create().supplier(x -> findSwap(x)).build();
+                       childSwaps = memoize(()->findChildSwaps());
+                       childUnswapMap = 
Cache.<Class<?>,ObjectSwap<?,?>>create().supplier(x -> findUnswap(x)).build();
+                       dictionaryName = memoize(()->findBeanDictionaryName());
+                       elementType = memoize(()->findElementType());
+                       enumValues = memoize(()->findEnumValues());
                        example = memoize(()->findExample());
+                       exampleField = memoize(()->findExampleField());
+                       exampleMethod = memoize(()->findExampleMethod());
+                       fromStringMethod = memoize(()->findFromStringMethod());
                        implClass = memoize(()->findImplClass());
-
-                       this.keyValueTypes = memoize(()->findKeyValueTypes());
-                       this.elementType = memoize(()->findElementType());
-
-                       this.beanMeta = memoize(()->findBeanMeta());
-                       this.enumValues = memoize(()->findEnumValues());
-                       this.dictionaryName = 
memoize(()->findBeanDictionaryName());
-
-                       this.swaps = memoize(()->findSwaps());
-
-                       this.childSwaps = memoize(()->findChildSwaps());
-                       this.childUnswapMap = 
Cache.<Class<?>,ObjectSwap<?,?>>create().supplier(x -> findUnswap(x)).build();
-                       this.childSwapMap = 
Cache.<Class<?>,ObjectSwap<?,?>>create().supplier(x -> findSwap(x)).build();
+                       keyValueTypes = memoize(()->findKeyValueTypes());
+                       marshalledFilter = memoize(()->findMarshalledFilter());
+                       nameProperty = memoize(()->findNameProperty());
+                       noArgConstructor = memoize(()->findNoArgConstructor());
+                       parentProperty = memoize(()->findParentProperty());
+                       stringConstructor = 
memoize(()->findStringConstructor());
+                       swaps = memoize(()->findSwaps());
 
                        this.args = null;
                        this.stringMutater = Mutaters.get(String.class, 
inner());
@@ -492,8 +483,7 @@ public class ClassMeta<T> extends ClassInfoTyped<T> {
         * @return The bean registry for this class, or <jk>null</jk> if no 
bean registry is associated with it.
         */
        public BeanRegistry getBeanRegistry() {
-               var bm = getBeanMeta();
-               return bm == null ? null : bm.getBeanRegistry();
+               return beanMeta.get().optBeanMeta().map(x -> 
x.getBeanRegistry()).orElse(null);
        }
 
        /**
@@ -723,8 +713,7 @@ public class ClassMeta<T> extends ClassInfoTyped<T> {
         * @return The interface proxy invocation handler, or <jk>null</jk> if 
it does not exist.
         */
        public InvocationHandler getProxyInvocationHandler() {
-               var bm = getBeanMeta();
-               return bm == null ? null : bm.getBeanProxyInvocationHandler();
+               return beanMeta.get().optBeanMeta().map(x -> 
x.getBeanProxyInvocationHandler()).orElse(null);
        }
 
        /**
@@ -1313,9 +1302,9 @@ public class ClassMeta<T> extends ClassInfoTyped<T> {
                if (beanContext == null)
                        return null;
 
-               var bm = getBeanMeta();
-               if (nn(bm) && bm.getDictionaryName() != null)
-                       return bm.getDictionaryName();
+               var d = beanMeta.get().optBeanMeta().map(x -> 
x.getDictionaryName()).orElse(null);
+               if (nn(d))
+                       return d;
 
                return beanContext.getAnnotationProvider().find(Bean.class, 
this)
                        .stream()
@@ -1334,11 +1323,10 @@ public class ClassMeta<T> extends ClassInfoTyped<T> {
                return 
BeanFilter.create(inner()).applyAnnotations(reverse(l.stream().map(AnnotationInfo::inner).toList())).build();
        }
 
-       private BeanMetaValue<T> findBeanMeta() {
+       private BeanMeta.BeanMetaValue<T> findBeanMeta() {
                if (! cat.isUnknown())
-                       return new BeanMetaValue<>(null, "Known non-bean type");
-               var result = BeanMeta.create(this, beanFilter.get(), null, 
implClass.map(x -> x.getPublicConstructor(x2 -> 
x2.hasNumParameters(0)).orElse(null)).orElse(null));
-               return new BeanMetaValue<>(result.getA(), result.getB());
+                       return new BeanMeta.BeanMetaValue<>(null, "Known 
non-bean type");
+               return BeanMeta.create(this, beanFilter.get(), null, 
implClass.map(x -> x.getPublicConstructor(x2 -> 
x2.hasNumParameters(0)).orElse(null)).orElse(null));
        }
 
        private KeyValueTypes findKeyValueTypes() {

Reply via email to