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 a49cda2674 Marshall module improvements
a49cda2674 is described below
commit a49cda267406133e07975fa1d6a0764a0dd3eb91
Author: James Bognar <[email protected]>
AuthorDate: Sun Dec 7 16:54:14 2025 -0500
Marshall module improvements
---
.../apache/juneau/commons/utils/ClassUtils.java | 66 +++++++++++++++++++++
.../src/main/java/org/apache/juneau/BeanMeta.java | 68 +---------------------
2 files changed, 67 insertions(+), 67 deletions(-)
diff --git
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/utils/ClassUtils.java
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/utils/ClassUtils.java
index b1f09277b4..b429c3038e 100644
---
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/utils/ClassUtils.java
+++
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/utils/ClassUtils.java
@@ -524,6 +524,72 @@ public class ClassUtils {
return null;
}
+ /**
+ * Recursively determines the classes represented by parameterized
types in the class hierarchy of the specified
+ * type, and puts the results in the specified map.
+ *
+ * <p>
+ * For example, given the following classes...
+ * <p class='bjava'>
+ * <jk>public static class</jk> BeanA<T> {
+ * <jk>public</jk> T <jf>x</jf>;
+ * }
+ * <jk>public static class</jk> BeanB <jk>extends</jk>
BeanA<Integer> {...}
+ * </p>
+ * <p>
+ * ...calling this method on {@code BeanB.class} will load the
following data into {@code m} indicating
+ * that the {@code T} parameter on the BeanA class is implemented
with an {@code Integer}:
+ * <p class='bcode'>
+ * {BeanA.class:[Integer.class]}
+ * </p>
+ *
+ * <h5 class='section'>Known Limitations:</h5>
+ * <p>
+ * This code doesn't currently properly handle the following situation
with nested generic bounds:
+ * <p class='bjava'>
+ * <jk>public static class</jk> BeanB<T <jk>extends</jk>
Number> <jk>extends</jk> BeanA<>;
+ * <jk>public static class</jk> BeanC <jk>extends</jk>
BeanB<Integer>;
+ * </p>
+ *
+ * <p>
+ * When called on {@code BeanC}, the type variable will be resolved as
{@code Number}, not {@code Integer}.
+ * This limitation exists because the intermediate type parameter bound
information is lost during type resolution
+ *
+ * @param t The type we're recursing.
+ * @param m Where the results are loaded.
+ */
+ public static Map<Class<?>,Class<?>[]> findTypeVarImpls(Type t) {
+ Map<Class<?>,Class<?>[]> m = new LinkedHashMap<>();
+ return findTypeVarImpls(t, m);
+ }
+
+ private static Map<Class<?>,Class<?>[]> findTypeVarImpls(Type t,
Map<Class<?>,Class<?>[]> m) {
+ if (t instanceof Class<?> c) {
+ findTypeVarImpls(c.getGenericSuperclass(), m);
+ for (var ci : c.getGenericInterfaces())
+ findTypeVarImpls(ci, m);
+ } else if (t instanceof ParameterizedType t2) {
+ var rt = t2.getRawType();
+ if (rt instanceof Class) {
+ Type[] gImpls = t2.getActualTypeArguments();
+ Class<?>[] gTypes = new Class[gImpls.length];
+ for (var i = 0; i < gImpls.length; i++) {
+ Type gt = gImpls[i];
+ if (gt instanceof Class<?> c)
+ gTypes[i] = c;
+ else if (gt instanceof TypeVariable<?>
tv) {
+ for (var upperBound :
tv.getBounds())
+ if (upperBound
instanceof Class upperBound2)
+ gTypes[i] =
upperBound2;
+ }
+ }
+ m.put((Class<?>)rt, gTypes);
+ findTypeVarImpls(t2.getRawType(), m);
+ }
+ }
+ return m;
+ }
+
private static boolean canAddTo(Class<?> c) {
var b = MODIFIABLE_COLLECTION_TYPES.get(c);
if (b == null) {
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 a750243f65..94a7adade4 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
@@ -150,7 +150,6 @@ public class BeanMeta<T> {
Map<Method,String> setterProps = map();
BeanPropertyMeta dynaProperty;
- Map<Class<?>,Class<?>[]> typeVarImpls;
ConstructorInfo constructor, implClassConstructor;
String[] constructorArgs = {};
PropertyNamer propertyNamer;
@@ -398,10 +397,7 @@ public class BeanMeta<T> {
});
}
- typeVarImpls = map();
- findTypeVarImpls(c, typeVarImpls);
- if (typeVarImpls.isEmpty())
- typeVarImpls = null;
+ var typeVarImpls =
ClassUtils.findTypeVarImpls(c);
// Eliminate invalid properties, and set the
contents of getterProps and setterProps.
for (Iterator<BeanPropertyMeta.Builder> i =
normalProps.values().iterator(); i.hasNext();) {
@@ -699,65 +695,6 @@ public class BeanMeta<T> {
return value.get();
}
- /**
- * Recursively determines the classes represented by parameterized
types in the class hierarchy of the specified
- * type, and puts the results in the specified map.
- *
- * <p>
- * For example, given the following classes...
- * <p class='bjava'>
- * <jk>public static class</jk> BeanA<T> {
- * <jk>public</jk> T <jf>x</jf>;
- * }
- * <jk>public static class</jk> BeanB <jk>extends</jk>
BeanA<Integer> {...}
- * </p>
- * <p>
- * ...calling this method on {@code BeanB.class} will load the
following data into {@code m} indicating
- * that the {@code T} parameter on the BeanA class is implemented
with an {@code Integer}:
- * <p class='bcode'>
- * {BeanA.class:[Integer.class]}
- * </p>
- *
- * <h5 class='section'>Known Limitations:</h5>
- * <p>
- * This code doesn't currently properly handle the following situation
with nested generic bounds:
- * <p class='bjava'>
- * <jk>public static class</jk> BeanB<T <jk>extends</jk>
Number> <jk>extends</jk> BeanA<>;
- * <jk>public static class</jk> BeanC <jk>extends</jk>
BeanB<Integer>;
- * </p>
- *
- * <p>
- * When called on {@code BeanC}, the type variable will be resolved as
{@code Number}, not {@code Integer}.
- * This limitation exists because the intermediate type parameter bound
information is lost during type resolution
- *
- * @param t The type we're recursing.
- * @param m Where the results are loaded.
- */
- static final void findTypeVarImpls(Type t, Map<Class<?>,Class<?>[]> m) {
- if (t instanceof Class<?> c) {
- findTypeVarImpls(c.getGenericSuperclass(), m);
- for (var ci : c.getGenericInterfaces())
- findTypeVarImpls(ci, m);
- } else if (t instanceof ParameterizedType t2) {
- var rt = t2.getRawType();
- if (rt instanceof Class) {
- Type[] gImpls = t2.getActualTypeArguments();
- Class<?>[] gTypes = new Class[gImpls.length];
- for (var i = 0; i < gImpls.length; i++) {
- Type gt = gImpls[i];
- if (gt instanceof Class<?> c)
- gTypes[i] = c;
- else if (gt instanceof TypeVariable<?>
tv) {
- for (var upperBound :
tv.getBounds())
- if (upperBound
instanceof Class upperBound2)
- gTypes[i] =
upperBound2;
- }
- }
- m.put((Class<?>)rt, gTypes);
- findTypeVarImpls(t2.getRawType(), m);
- }
- }
- }
/**
* Finds @Beanp and @Name annotations from parent methods if this
method overrides a parent.
@@ -836,8 +773,6 @@ public class BeanMeta<T> {
protected final BeanContext ctx;
/** Optional bean filter associated with the target class. */
protected final BeanFilter beanFilter;
- /** Type variables implemented by this bean. */
- protected final Map<Class<?>,Class<?>[]> typeVarImpls;
/** The constructor for this bean. */
protected final ConstructorInfo constructor;
@@ -912,7 +847,6 @@ public class BeanMeta<T> {
getterProps = u(b.getterProps);
setterProps = u(b.setterProps);
dynaProperty = b.dynaProperty;
- typeVarImpls = u(b.typeVarImpls);
constructor = b.constructor;
constructorArgs = b.constructorArgs;
beanRegistry = b.beanRegistry;