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

commit 831c0e75303b3978236cfa9ac3e5d83e72c60c89
Author: James Bognar <[email protected]>
AuthorDate: Sat Dec 6 18:20:48 2025 -0500

    Marshall module improvements
---
 .../juneau/commons/function/OptionalSupplier.java  | 243 +++++++++++++++++++++
 .../commons/function/ResettableSupplier.java       |  14 +-
 .../org/apache/juneau/commons/utils/Utils.java     |   2 +-
 .../src/main/java/org/apache/juneau/ClassMeta.java | 137 ++++++------
 4 files changed, 331 insertions(+), 65 deletions(-)

diff --git 
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/function/OptionalSupplier.java
 
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/function/OptionalSupplier.java
new file mode 100644
index 0000000000..d182063e69
--- /dev/null
+++ 
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/function/OptionalSupplier.java
@@ -0,0 +1,243 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.juneau.commons.function;
+
+import static org.apache.juneau.commons.utils.AssertionUtils.*;
+import static org.apache.juneau.commons.utils.Utils.*;
+
+import java.util.*;
+import java.util.function.*;
+
+/**
+ * Combines the features of {@link Supplier} and {@link Optional} into a 
single class.
+ *
+ * <p>
+ * This interface extends {@link Supplier} and provides convenience methods 
for working with potentially null values,
+ * similar to {@link Optional}. The key difference is that this interface is 
lazy - the value is only computed when
+ * {@link #get()} is called, and the Optional-like methods operate on that 
computed value.
+ *
+ * <h5 class='section'>Features:</h5>
+ * <ul class='spaced-list'>
+ *     <li>Extends Supplier - can be used anywhere a Supplier is expected
+ *     <li>Optional-like API - provides isPresent(), isEmpty(), map(), 
orElse(), etc.
+ *     <li>Lazy evaluation - value is only computed when get() is called
+ *     <li>Null-safe - handles null values gracefully
+ * </ul>
+ *
+ * <h5 class='section'>Usage:</h5>
+ * <p class='bjava'>
+ *     <jc>// Create from a supplier</jc>
+ *     OptionalSupplier&lt;String&gt; <jv>supplier</jv> = 
OptionalSupplier.<jsm>of</jsm>(() -&gt; <js>"value"</js>);
+ *
+ *     <jc>// Check if value is present</jc>
+ *     <jk>if</jk> (<jv>supplier</jv>.isPresent()) {
+ *             String <jv>value</jv> = <jv>supplier</jv>.get();
+ *     }
+ *
+ *     <jc>// Map the value</jc>
+ *     OptionalSupplier&lt;Integer&gt; <jv>length</jv> = 
<jv>supplier</jv>.map(String::length);
+ *
+ *     <jc>// Get value or default</jc>
+ *     String <jv>result</jv> = <jv>supplier</jv>.orElse(<js>"default"</js>);
+ * </p>
+ *
+ * <h5 class='section'>See Also:</h5><ul>
+ *     <li class='jc'>{@link Supplier} - Base functional interface
+ *     <li class='jc'>{@link Optional} - Java's Optional class
+ * </ul>
+ *
+ * @param <T> The type of value supplied by this supplier.
+ */
+@FunctionalInterface
+public interface OptionalSupplier<T> extends Supplier<T> {
+
+       /**
+        * Creates an OptionalSupplier from a Supplier.
+        *
+        * @param <T> The value type.
+        * @param supplier The supplier. Must not be <jk>null</jk>.
+        * @return A new OptionalSupplier instance.
+        */
+       public static <T> OptionalSupplier<T> of(Supplier<T> supplier) {
+               assertArgNotNull("supplier", supplier);
+               return supplier::get;
+       }
+
+       /**
+        * Creates an OptionalSupplier that always returns the specified value.
+        *
+        * @param <T> The value type.
+        * @param value The value to return. Can be <jk>null</jk>.
+        * @return A new OptionalSupplier instance.
+        */
+       public static <T> OptionalSupplier<T> ofNullable(T value) {
+               return () -> value;
+       }
+
+       /**
+        * Creates an empty OptionalSupplier that always returns <jk>null</jk>.
+        *
+        * @param <T> The value type.
+        * @return A new OptionalSupplier instance that always returns 
<jk>null</jk>.
+        */
+       public static <T> OptionalSupplier<T> empty() {
+               return () -> null;
+       }
+
+       /**
+        * Returns <jk>true</jk> if the supplied value is not <jk>null</jk>.
+        *
+        * @return <jk>true</jk> if the supplied value is not <jk>null</jk>.
+        */
+       default boolean isPresent() {
+               return nn(get());
+       }
+
+       /**
+        * Returns <jk>true</jk> if the supplied value is <jk>null</jk>.
+        *
+        * @return <jk>true</jk> if the supplied value is <jk>null</jk>.
+        */
+       default boolean isEmpty() {
+               return ! isPresent();
+       }
+
+       /**
+        * If a value is present, applies the provided mapping function to it 
and returns an OptionalSupplier describing the result.
+        *
+        * @param <U> The type of the result of the mapping function.
+        * @param mapper A mapping function to apply to the value, if present. 
Must not be <jk>null</jk>.
+        * @return An OptionalSupplier describing the result of applying a 
mapping function to the value of this OptionalSupplier, if a value is present, 
otherwise an empty OptionalSupplier.
+        */
+       default <U> OptionalSupplier<U> map(Function<? super T, ? extends U> 
mapper) {
+               assertArgNotNull("mapper", mapper);
+               return () -> {
+                       T value = get();
+                       return nn(value) ? mapper.apply(value) : null;
+               };
+       }
+
+       /**
+        * If a value is present, returns the result of applying the given 
OptionalSupplier-bearing mapping function to the value, otherwise returns an 
empty OptionalSupplier.
+        *
+        * @param <U> The type parameter to the OptionalSupplier returned by 
the mapping function.
+        * @param mapper A mapping function to apply to the value, if present. 
Must not be <jk>null</jk>.
+        * @return The result of applying an OptionalSupplier-bearing mapping 
function to the value of this OptionalSupplier, if a value is present, 
otherwise an empty OptionalSupplier.
+        */
+       default <U> OptionalSupplier<U> flatMap(Function<? super T, ? extends 
OptionalSupplier<? extends U>> mapper) {
+               assertArgNotNull("mapper", mapper);
+               return () -> {
+                       T value = get();
+                       if (nn(value)) {
+                               OptionalSupplier<? extends U> result = 
mapper.apply(value);
+                               return result != null ? result.get() : null;
+                       }
+                       return null;
+               };
+       }
+
+       /**
+        * If a value is present, and the value matches the given predicate, 
returns an OptionalSupplier describing the value, otherwise returns an empty 
OptionalSupplier.
+        *
+        * @param predicate A predicate to apply to the value, if present. Must 
not be <jk>null</jk>.
+        * @return An OptionalSupplier describing the value of this 
OptionalSupplier if a value is present and the value matches the given 
predicate, otherwise an empty OptionalSupplier.
+        */
+       default OptionalSupplier<T> filter(Predicate<? super T> predicate) {
+               assertArgNotNull("predicate", predicate);
+               return () -> {
+                       T value = get();
+                       return (nn(value) && predicate.test(value)) ? value : 
null;
+               };
+       }
+
+       /**
+        * If a value is present, returns the value, otherwise returns 
<jk>other</jk>.
+        *
+        * @param other The value to be returned if there is no value present. 
Can be <jk>null</jk>.
+        * @return The value, if present, otherwise <jk>other</jk>.
+        */
+       default T orElse(T other) {
+               T value = get();
+               return nn(value) ? value : other;
+       }
+
+       /**
+        * If a value is present, returns the value, otherwise returns the 
result produced by the supplying function.
+        *
+        * @param other A {@link Supplier} whose result is returned if no value 
is present. Must not be <jk>null</jk>.
+        * @return The value, if present, otherwise the result of 
<jk>other.get()</jk>.
+        */
+       default T orElseGet(Supplier<? extends T> other) {
+               assertArgNotNull("other", other);
+               T value = get();
+               return nn(value) ? value : other.get();
+       }
+
+       /**
+        * If a value is present, returns the value, otherwise throws an 
exception produced by the exception supplying function.
+        *
+        * @param <X> Type of the exception to be thrown.
+        * @param exceptionSupplier The supplying function that produces an 
exception to be thrown. Must not be <jk>null</jk>.
+        * @return The value, if present.
+        * @throws X If no value is present.
+        */
+       default <X extends Throwable> T orElseThrow(Supplier<? extends X> 
exceptionSupplier) throws X {
+               assertArgNotNull("exceptionSupplier", exceptionSupplier);
+               T value = get();
+               if (nn(value))
+                       return value;
+               throw exceptionSupplier.get();
+       }
+
+       /**
+        * If a value is present, performs the given action with the value, 
otherwise does nothing.
+        *
+        * @param action The action to be performed, if a value is present. 
Must not be <jk>null</jk>.
+        */
+       default void ifPresent(Consumer<? super T> action) {
+               assertArgNotNull("action", action);
+               T value = get();
+               if (nn(value))
+                       action.accept(value);
+       }
+
+       /**
+        * If a value is present, performs the given action with the value, 
otherwise performs the given empty-based action.
+        *
+        * @param action The action to be performed, if a value is present. 
Must not be <jk>null</jk>.
+        * @param emptyAction The empty-based action to be performed, if no 
value is present. Must not be <jk>null</jk>.
+        */
+       default void ifPresentOrElse(Consumer<? super T> action, Runnable 
emptyAction) {
+               assertArgNotNull("action", action);
+               assertArgNotNull("emptyAction", emptyAction);
+               T value = get();
+               if (nn(value))
+                       action.accept(value);
+               else
+                       emptyAction.run();
+       }
+
+       /**
+        * Converts this OptionalSupplier to an {@link Optional}.
+        *
+        * @return An Optional containing the value if present, otherwise an 
empty Optional.
+        */
+       default Optional<T> toOptional() {
+               return opt(get());
+       }
+}
+
diff --git 
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/function/ResettableSupplier.java
 
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/function/ResettableSupplier.java
index 68bece2bda..98b4022039 100644
--- 
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/function/ResettableSupplier.java
+++ 
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/function/ResettableSupplier.java
@@ -27,8 +27,9 @@ import java.util.function.*;
  * A thread-safe supplier that caches the result of the first call and 
supports resetting the cache.
  *
  * <p>
- * This class provides both standard {@link Supplier#get()} functionality and 
a {@link #reset()} method
- * to clear the cache, forcing recomputation on the next call to {@link 
#get()}.
+ * This class extends {@link OptionalSupplier} to provide both standard {@link 
Supplier#get()} functionality
+ * and a {@link #reset()} method to clear the cache, forcing recomputation on 
the next call to {@link #get()}.
+ * It also inherits all Optional-like convenience methods from {@link 
OptionalSupplier}.
  *
  * <h5 class='section'>Usage:</h5>
  * <p class='bjava'>
@@ -41,6 +42,11 @@ import java.util.function.*;
  *     <jc>// Subsequent calls return cached value</jc>
  *     String <jv>result2</jv> = <jv>supplier</jv>.get();
  *
+ *     <jc>// Use Optional-like methods</jc>
+ *     <jk>if</jk> (<jv>supplier</jv>.isPresent()) {
+ *             String <jv>upper</jv> = 
<jv>supplier</jv>.map(String::toUpperCase).orElse(<js>"default"</js>);
+ *     }
+ *
  *     <jc>// Reset forces recomputation on next get()</jc>
  *     <jv>supplier</jv>.reset();
  *     String <jv>result3</jv> = <jv>supplier</jv>.get();  <jc>// 
Recomputes</jc>
@@ -58,16 +64,18 @@ import java.util.function.*;
  *     <li>The cached value can be <jk>null</jk> if the supplier returns 
<jk>null</jk>.
  *     <li>After reset, the next get() will recompute the value.
  *     <li>This is particularly useful for testing when configuration changes 
and cached values need to be recalculated.
+ *     <li>Inherits all Optional-like methods from {@link OptionalSupplier} 
(isPresent(), isEmpty(), map(), orElse(), etc.).
  * </ul>
  *
  * <h5 class='section'>See Also:</h5>
  * <ul>
  *     <li class='jm'>{@link 
org.apache.juneau.commons.utils.Utils#memoizeResettable(Supplier)}
+ *     <li class='jc'>{@link OptionalSupplier} - Base interface providing 
Optional-like methods
  * </ul>
  *
  * @param <T> The type of value supplied.
  */
-public class ResettableSupplier<T> implements Supplier<T> {
+public class ResettableSupplier<T> implements OptionalSupplier<T> {
        private final Supplier<T> supplier;
        private final AtomicReference<Optional<T>> cache = new 
AtomicReference<>();
 
diff --git 
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/utils/Utils.java
 
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/utils/Utils.java
index 5598f1cb8d..3a67bf6090 100644
--- 
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/utils/Utils.java
+++ 
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/utils/Utils.java
@@ -1069,7 +1069,7 @@ public class Utils {
         * @return A thread-safe memoizing wrapper around the supplier.
         * @throws NullPointerException if supplier is <jk>null</jk>.
         */
-       public static <T> Supplier<T> memoize(Supplier<T> supplier) {
+       public static <T> OptionalSupplier<T> memoize(Supplier<T> supplier) {
                assertArgNotNull("supplier", supplier);
 
                var cache = new AtomicReference<Optional<T>>();
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 6c5c903fb2..e1d0cb96e9 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
@@ -35,6 +35,7 @@ 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.reflect.*;
 import org.apache.juneau.commons.utils.*;
 import org.apache.juneau.cp.*;
@@ -152,24 +153,24 @@ public class ClassMeta<T> extends ClassInfoTyped<T> {
        private final ConcurrentHashMap<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<String> example;                                 
                                        // Example JSON.
-       private final Supplier<FieldInfo> exampleField;                         
                                        // The @Example-annotated field (if it 
has one).
-       private final Supplier<MethodInfo> exampleMethod;                       
                                        // The example() or @Example-annotated 
method (if it has one).
+       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).
        private final Supplier<BidiMap<Object,String>> enumValues;
        private final Map<Class<?>,Mutater<?,T>> fromMutaters = new 
ConcurrentHashMap<>();
-       private final Supplier<MethodInfo> fromStringMethod;                    
                                        // Static fromString(String) or 
equivalent method
-       private final Supplier<ClassInfoTyped<? extends T>> implClass2;         
                                        // The implementation class to use if 
this is an interface.
-       private final InvocationHandler invocationHandler;                      
                                        // The invocation handler for this 
class (if it has one).
+       private final OptionalSupplier<MethodInfo> fromStringMethod;            
                                                // Static fromString(String) or 
equivalent method
+       private final OptionalSupplier<ClassInfoTyped<? extends T>> implClass;  
                                               // The implementation class to 
use if this is an interface.
+       private final OptionalSupplier<InvocationHandler> 
proxyInvocationHandler;                                                         
     // The invocation handler for this class (if it has one).
        private final ClassMeta<?> keyType;                                     
                                        // If MAP, the key class type.
        private final SimpleReadWriteLock lock = new SimpleReadWriteLock(false);
        private final Supplier<MarshalledFilter> marshalledFilter;
        private final Supplier<Property<T,Object>> nameProperty;                
                            // The method to set the name on an object (if it 
has one).
-       private final Supplier<ConstructorInfo> noArgConstructor;               
                                        // The no-arg constructor for this 
class (if it has one).
+       private final OptionalSupplier<ConstructorInfo> noArgConstructor;       
                                                // The no-arg constructor for 
this class (if it has one).
        private final String notABeanReason;                                    
                                        // If this isn't a bean, the reason why.
        private final Supplier<Property<T,Object>> parentProperty;              
                            // The method to set the parent on an object (if it 
has one).
        private final Map<String,Optional<?>> properties = new 
ConcurrentHashMap<>();
        private final Mutater<String,T> stringMutater;
-       private final Supplier<ConstructorInfo> stringConstructor;              
                                       // The X(String) constructor (if it has 
one).
+       private final OptionalSupplier<ConstructorInfo> stringConstructor;      
                                               // The X(String) constructor (if 
it has one).
        private final 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 String typePropertyName;                                  
                                        // The property name of the _type 
property for this class and subclasses.
@@ -264,7 +265,7 @@ public class ClassMeta<T> extends ClassInfoTyped<T> {
                        marshalledFilter = memoize(()->findMarshalledFilter());
                        builderSwap = memoize(()->findBuilderSwap());
                        example = memoize(()->findExample());
-                       implClass2 = memoize(()->findImplClass());
+                       implClass = memoize(()->findImplClass());
 
                        var _elementType = (ClassMeta<?>)null;
                        var _keyType = (ClassMeta<?>)null;
@@ -292,14 +293,14 @@ public class ClassMeta<T> extends ClassInfoTyped<T> {
                                }
                        }
 
-                       BeanMeta<T> _beanMeta = null;
+                       var _beanMeta = (BeanMeta<T>)null;
                        var _beanRegistry = new Value<BeanRegistry>();
 
                        if (! cat.isUnknown()) {
                                notABeanReason = "Known non-bean type";
                        } else {
                                try {
-                                       _beanMeta = new 
BeanMeta<>(ClassMeta.this, beanContext, beanFilter.get(), null, 
implClass2.get() == null ? null : noArgConstructor.get());
+                                       _beanMeta = new 
BeanMeta<>(ClassMeta.this, beanContext, beanFilter.get(), null, implClass.get() 
== null ? null : noArgConstructor.get());
                                        notABeanReason = 
_beanMeta.notABeanReason;
                                        
_beanRegistry.set(_beanMeta.beanRegistry);
                                } catch (RuntimeException e) {
@@ -307,11 +308,6 @@ public class ClassMeta<T> extends ClassInfoTyped<T> {
                                }
                        }
 
-                       ap.find(Bean.class, 
this).stream().map(AnnotationInfo::inner).forEach(x2 -> {
-                               if (x2.dictionary().length != 0)
-                                       _beanRegistry.set(new 
BeanRegistry(beanContext, null, x2.dictionary()));
-                       });
-
                        this.beanMeta = notABeanReason == null ? _beanMeta : 
null;
                        if (nn(this.beanMeta))
                                cat.set(BEAN);
@@ -343,7 +339,7 @@ public class ClassMeta<T> extends ClassInfoTyped<T> {
                        this.swaps = _swaps.isEmpty() ? null : 
_swaps.toArray(new ObjectSwap[_swaps.size()]);
                        this.typePropertyName = opt(beanMeta).map(x2 -> 
x2.typePropertyName).orElse(null);
 
-                       this.invocationHandler = (nn(beanMeta) && 
beanContext.isUseInterfaceProxies() && isInterface()) ? new 
BeanProxyInvocationHandler<>(beanMeta) : null;
+                       this.proxyInvocationHandler = ()->(nn(beanMeta) && 
beanContext.isUseInterfaceProxies() && isInterface()) ? new 
BeanProxyInvocationHandler<>(beanMeta) : null;
                        this.beanRegistry = _beanRegistry.get();
 
                        this.childSwaps = childSwaps;
@@ -370,7 +366,7 @@ public class ClassMeta<T> extends ClassInfoTyped<T> {
                this.elementType = null;
                this.keyType = null;
                this.valueType = null;
-               this.invocationHandler = null;
+               this.proxyInvocationHandler = null;
                this.beanMeta = null;
                this.typePropertyName = null;
                this.notABeanReason = null;
@@ -388,7 +384,7 @@ public class ClassMeta<T> extends ClassInfoTyped<T> {
                this.marshalledFilter = memoize(()->findMarshalledFilter());
                this.builderSwap = memoize(()->findBuilderSwap());
                this.example = memoize(()->findExample());
-               this.implClass2 = memoize(()->findImplClass());
+               this.implClass = memoize(()->findImplClass());
                this.enumValues = memoize(()->findEnumValues());
                this.dictionaryName = memoize(()->findBeanDictionaryName());
        }
@@ -410,7 +406,7 @@ public class ClassMeta<T> extends ClassInfoTyped<T> {
                this.elementType = elementType;
                this.keyType = keyType;
                this.valueType = valueType;
-               this.invocationHandler = mainType.invocationHandler;
+               this.proxyInvocationHandler = mainType.proxyInvocationHandler;
                this.beanMeta = mainType.beanMeta;
                this.typePropertyName = mainType.typePropertyName;
                this.notABeanReason = mainType.notABeanReason;
@@ -428,10 +424,11 @@ public class ClassMeta<T> extends ClassInfoTyped<T> {
                this.marshalledFilter = mainType.marshalledFilter;
                this.builderSwap = mainType.builderSwap;
                this.example = mainType.example;
-               this.implClass2 = mainType.implClass2;
+               this.implClass = mainType.implClass;
                this.enumValues = mainType.enumValues;
                this.dictionaryName = mainType.dictionaryName;
        }
+
        /**
         * Returns <jk>true</jk> if this class can be instantiated as a bean.
         * Returns <jk>false</jk> if this is a non-static member class and the 
outer object does not match the class type of
@@ -458,7 +455,7 @@ public class ClassMeta<T> extends ClassInfoTyped<T> {
        public boolean canCreateNewInstance() {
                if (isMemberClass() && isNotStatic())
                        return false;
-               if (nn(noArgConstructor.get()) || 
nn(getProxyInvocationHandler()) || (super.isArray() && 
elementType.canCreateNewInstance()))
+               if (noArgConstructor.isPresent() || 
proxyInvocationHandler.isPresent() || (isArray() && 
elementType.canCreateNewInstance()))
                        return true;
                return false;
        }
@@ -475,7 +472,7 @@ public class ClassMeta<T> extends ClassInfoTyped<T> {
         */
        public boolean canCreateNewInstance(Object outer) {
                if (isMemberClass() && isNotStatic())
-                       return nn(outer) && nn(noArgConstructor.get()) && 
noArgConstructor.get().hasParameterTypes(outer.getClass());
+                       return nn(outer) && noArgConstructor.map(x -> 
x.hasParameterTypes(outer.getClass())).orElse(false);
                return canCreateNewInstance();
        }
 
@@ -488,11 +485,11 @@ public class ClassMeta<T> extends ClassInfoTyped<T> {
         * @return <jk>true</jk> if this class has a no-arg constructor or 
invocation handler.
         */
        public boolean canCreateNewInstanceFromString(Object outer) {
-               if (nn(fromStringMethod.get()))
+               if (fromStringMethod.isPresent())
                        return true;
-               if (nn(stringConstructor.get())) {
+               if (stringConstructor.isPresent()) {
                        if (isMemberClass() && isNotStatic())
-                               return nn(outer) && 
stringConstructor.get().hasParameterTypes(outer.getClass(), String.class);
+                               return nn(outer) && stringConstructor.map(x -> 
x.hasParameterTypes(outer.getClass(), String.class)).orElse(false);
                        return true;
                }
                return false;
@@ -590,13 +587,6 @@ public class ClassMeta<T> extends ClassInfoTyped<T> {
                return builderSwap.get();
        }
 
-       /**
-        * Returns the no-arg constructor for this class.
-        *
-        * @return The no-arg constructor for this class, or <jk>null</jk> if 
it does not exist.
-        */
-       public ConstructorInfo getConstructor() { return 
noArgConstructor.get(); }
-
        /**
         * Returns the bean dictionary name associated with this class.
         *
@@ -629,11 +619,11 @@ public class ClassMeta<T> extends ClassInfoTyped<T> {
        @SuppressWarnings({ "unchecked" })
        public T getExample(BeanSession session, JsonParserSession jpSession) {
                try {
-                       if (nn(example.get()))
+                       if (example.isPresent())
                                return jpSession.parse(example.get(), this);
-                       if (nn(exampleMethod.get()))
+                       if (exampleMethod.isPresent())
                                return 
(T)exampleMethod.get().invokeLenient(null, session);
-                       if (nn(exampleField.get()))
+                       if (exampleField.isPresent())
                                return (T)exampleField.get().get(null);
 
                        if (isCollection()) {
@@ -700,9 +690,7 @@ public class ClassMeta<T> extends ClassInfoTyped<T> {
         * @return The no-arg constructor for this class, or <jk>null</jk> if 
it does not exist.
         */
        public ConstructorInfo getImplClassConstructor(Visibility conVis) {
-               if (nn(implClass2.get()))
-                       return 
implClass2.get().getNoArgConstructor(conVis).orElse(null);
-               return null;
+               return implClass.map(x -> 
x.getNoArgConstructor(conVis).orElse(null)).orElse(null);
        }
 
        /**
@@ -778,12 +766,42 @@ public class ClassMeta<T> extends ClassInfoTyped<T> {
        public Property<T,Object> getParentProperty() { return 
parentProperty.get(); }
 
        /**
-        * Returns a calculated property on this context.
+        * Returns a lazily-computed, cached property value for this {@link 
ClassMeta} instance.
         *
-        * @param <T2> The type to convert the property to.
-        * @param name The name of the property.
-        * @param function The function used to create this property.
-        * @return The property value.  Never <jk>null</jk>.
+        * <p>
+        * This method provides a memoization mechanism for expensive 
computations. The property value is computed
+        * on the first call using the provided function, then cached for 
subsequent calls with the same property name.
+        *
+        * <p>
+        * The function is only invoked once per property name per {@link 
ClassMeta} instance. Subsequent calls
+        * with the same name will return the cached value without re-invoking 
the function.
+        *
+        * <h5 class='section'>Thread Safety:</h5>
+        * <p>
+        * This method is thread-safe. If multiple threads call this method 
simultaneously with the same property name,
+        * the function may be invoked multiple times, but only one result will 
be cached and returned.
+        *
+        * <h5 class='section'>Usage:</h5>
+        * <p class='bjava'>
+        *      <jc>// Compute and cache an expensive property</jc>
+        *      Optional&lt;String&gt; <jv>computedValue</jv> = 
classMeta.<jsm>getProperty</jsm>(<js>"expensiveProperty"</js>, cm -&gt; {
+        *              <jc>// Expensive computation that only runs once</jc>
+        *              <jk>return</jk> performExpensiveComputation(cm);
+        *      });
+        *
+        *      <jc>// Subsequent calls return cached value</jc>
+        *      Optional&lt;String&gt; <jv>cached</jv> = 
classMeta.<jsm>getProperty</jsm>(<js>"expensiveProperty"</js>, cm -&gt; {
+        *              <jc>// This function is NOT called again</jc>
+        *              <jk>return</jk> performExpensiveComputation(cm);
+        *      });
+        * </p>
+        *
+        * @param <T2> The type of the property value.
+        * @param name The unique name identifying this property. Used as the 
cache key.
+        * @param function The function that computes the property value. 
Receives this {@link ClassMeta} instance as input.
+        *      Only invoked if the property hasn't been computed yet. Can 
return <jk>null</jk>.
+        * @return An {@link Optional} containing the property value if the 
function returned a non-null value,
+        *      otherwise an empty {@link Optional}. Never <jk>null</jk>.
         */
        @SuppressWarnings("unchecked")
        public <T2> Optional<T2> getProperty(String name, 
Function<ClassMeta<?>,T2> function) {
@@ -800,7 +818,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() { return 
invocationHandler; }
+       public InvocationHandler getProxyInvocationHandler() { return 
proxyInvocationHandler.get(); }
 
        /**
         * Returns the transform for this class for creating instances from a 
Reader.
@@ -1284,9 +1302,8 @@ public class ClassMeta<T> extends ClassInfoTyped<T> {
        public T newInstance() throws ExecutableException {
                if (super.isArray())
                        return (T)Array.newInstance(inner().getComponentType(), 
0);
-               var c = getConstructor();
-               if (nn(c))
-                       return c.<T>newInstance();
+               if (noArgConstructor.isPresent())
+                       return noArgConstructor.get().newInstance();
                var h = getProxyInvocationHandler();
                if (nn(h))
                        return 
(T)Proxy.newProxyInstance(this.getClass().getClassLoader(), a(inner(), 
java.io.Serializable.class), h);
@@ -1303,7 +1320,7 @@ public class ClassMeta<T> extends ClassInfoTyped<T> {
         * @throws ExecutableException Exception occurred on invoked 
constructor/method/field.
         */
        public T newInstance(Object outer) throws ExecutableException {
-               if (isMemberClass() && isNotStatic())
+               if (isMemberClass() && isNotStatic() && 
noArgConstructor.isPresent())
                        return noArgConstructor.get().<T>newInstance(outer);
                return newInstance();
        }
@@ -1335,15 +1352,13 @@ public class ClassMeta<T> extends ClassInfoTyped<T> {
                        return t;
                }
 
-               var m = fromStringMethod.get();
-               if (nn(m)) {
-                       return (T)m.invoke(null, arg);
-               }
-               var c = stringConstructor.get();
-               if (nn(c)) {
+               if (fromStringMethod.isPresent())
+                       return (T)fromStringMethod.get().invoke(null, arg);
+
+               if (stringConstructor.isPresent()) {
                        if (isMemberClass() && isNotStatic())
-                               return c.<T>newInstance(outer, arg);
-                       return c.<T>newInstance(arg);
+                               return 
stringConstructor.get().<T>newInstance(outer, arg);
+                       return stringConstructor.get().<T>newInstance(arg);
                }
                throw new ExecutableException("No string constructor or 
valueOf(String) method found for class '" + inner().getName() + "'");
        }
@@ -1649,8 +1664,8 @@ public class ClassMeta<T> extends ClassInfoTyped<T> {
                if (is(Object.class))
                        return null;
 
-               if (implClass2.get() != null)
-                       return implClass2.get().getPublicConstructor(x -> 
x.hasNumParameters(0)).orElse(null);
+               if (implClass.isPresent())
+                       return implClass.get().getPublicConstructor(x -> 
x.hasNumParameters(0)).orElse(null);
 
                if (isAbstract())
                        return null;
@@ -1741,8 +1756,8 @@ public class ClassMeta<T> extends ClassInfoTyped<T> {
                if (is(Object.class) || isAbstract())
                        return null;
 
-               if (implClass2.get() != null)
-                       return implClass2.get().getPublicConstructor(x -> 
x.hasParameterTypes(String.class)).orElse(null);
+               if (implClass.isPresent())
+                       return implClass.get().getPublicConstructor(x -> 
x.hasParameterTypes(String.class)).orElse(null);
 
                if (isAbstract())
                        return null;

Reply via email to