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<Person> <jv>cm</jv> =
<jv>beanContext</jv>.getClassMeta(Person.<jk>class</jk>);
+ * BeanMetaValue<Person> <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<Person> <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() {