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 d40470594d Marshall module improvements
d40470594d is described below
commit d40470594de2e7ce017984c2501b403ef4e333fd
Author: James Bognar <[email protected]>
AuthorDate: Thu Dec 11 18:26:15 2025 -0500
Marshall module improvements
---
.../juneau/commons/reflect/ExecutableInfo.java | 22 +++++++++++++
.../src/main/java/org/apache/juneau/BeanMeta.java | 28 +++++++++--------
.../java/org/apache/juneau/BeanPropertyMeta.java | 36 +++++++++++-----------
.../apache/juneau/html/HtmlBeanPropertyMeta.java | 2 +-
.../commons/reflect/ExecutableInfo_Test.java | 32 +++++++++++++++++++
5 files changed, 89 insertions(+), 31 deletions(-)
diff --git
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/reflect/ExecutableInfo.java
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/reflect/ExecutableInfo.java
index 653a21462d..8d6f5f0051 100644
---
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/reflect/ExecutableInfo.java
+++
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/reflect/ExecutableInfo.java
@@ -87,6 +87,7 @@ public abstract class ExecutableInfo extends AccessibleInfo {
private final boolean isConstructor;
private final Supplier<List<ParameterInfo>> parameters; // All
parameters of this executable.
+ private final Supplier<List<ClassInfo>> parameterTypes; // All
parameter types of this executable.
private final Supplier<List<ClassInfo>> exceptions; // All exceptions
declared by this executable.
private final Supplier<List<AnnotationInfo<Annotation>>>
declaredAnnotations; // All annotations declared directly on this executable.
private final Supplier<String> shortName; // Short name
(method/constructor name with parameters).
@@ -109,6 +110,7 @@ public abstract class ExecutableInfo extends AccessibleInfo
{
this.inner = inner;
this.isConstructor = inner instanceof Constructor;
this.parameters = memoize(this::findParameters);
+ this.parameterTypes = memoize(() ->
getParameters().stream().map(ParameterInfo::getParameterType).toList());
this.exceptions = memoize(() ->
stream(inner.getExceptionTypes()).map(ClassInfo::of).map(ClassInfo.class::cast).toList());
this.declaredAnnotations = memoize(() ->
stream(inner.getDeclaredAnnotations()).flatMap(a ->
AnnotationUtils.streamRepeated(a)).map(a -> ai((Annotatable)this, a)).toList());
this.shortName = memoize(() -> f("{0}({1})", getSimpleName(),
getParameters().stream().map(p ->
p.getParameterType().getNameSimple()).collect(joining(","))));
@@ -321,6 +323,26 @@ public abstract class ExecutableInfo extends
AccessibleInfo {
*/
public final List<ParameterInfo> getParameters() { return
parameters.get(); }
+ /**
+ * Returns the parameter types for this executable.
+ *
+ * <p>
+ * This is a convenience method that extracts the parameter types from
{@link #getParameters()}.
+ *
+ * <h5 class='section'>Example:</h5>
+ * <p class='bjava'>
+ * <jc>// Get parameter types: void myMethod(String s, int i)</jc>
+ * MethodInfo <jv>mi</jv> =
ClassInfo.<jsm>of</jsm>(MyClass.<jk>class</jk>).getMethod(<js>"myMethod"</js>,
String.<jk>class</jk>, <jk>int</jk>.<jk>class</jk>);
+ * List<ClassInfo> <jv>paramTypes</jv> =
<jv>mi</jv>.getParameterTypes();
+ * <jc>// paramTypes contains ClassInfo for String and int</jc>
+ * </p>
+ *
+ * @return A list of parameter types, never <jk>null</jk>.
+ */
+ public final List<ClassInfo> getParameterTypes() {
+ return parameterTypes.get();
+ }
+
/**
* Returns the short name of this executable.
*
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 84298891aa..37612e492d 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
@@ -120,11 +120,11 @@ public class BeanMeta<T> {
return true;
// Get the bean property type from the getter/field.
- var pt = (Class<?>)null;
+ var pt = (Class<?>)null; // TODO - Convert to ClassInfo
if (nn(b.getter))
- pt = b.getter.getReturnType();
+ pt = b.getter.getReturnType().inner();
else if (nn(b.field))
- pt = b.field.inner().getType(); // TODO -
Convert to FieldInfo
+ pt = b.field.inner().getType();
// Matches if only a setter is defined.
if (pt == null)
@@ -403,7 +403,7 @@ public class BeanMeta<T> {
var _notABeanReason = (String)null;
var _properties = Value.<Map<String,BeanPropertyMeta>>empty();
var _hiddenProperties =
CollectionUtils.<String,BeanPropertyMeta>map();
- var _getterProps = CollectionUtils.<Method,String>map();
+ var _getterProps = CollectionUtils.<Method,String>map(); //
Convert to MethodInfo keys
var _setterProps = CollectionUtils.<Method,String>map();
var _dynaProperty = Value.<BeanPropertyMeta>empty();
var _sortProperties = false;
@@ -435,7 +435,11 @@ public class BeanMeta<T> {
bi =
Introspector.getBeanInfo(c2.inner(), null);
if (nn(bi)) {
for (var pd :
bi.getPropertyDescriptors()) {
-
normalProps.computeIfAbsent(pd.getName(), n -> BeanPropertyMeta.builder(this,
n)).setGetter(pd.getReadMethod()).setSetter(pd.getWriteMethod());
+ var builder =
normalProps.computeIfAbsent(pd.getName(), n -> BeanPropertyMeta.builder(this,
n));
+ if (pd.getReadMethod() != null)
+
builder.setGetter(info(pd.getReadMethod()));
+ if (pd.getWriteMethod() != null)
+
builder.setSetter(pd.getWriteMethod());
}
}
@@ -458,20 +462,20 @@ public class BeanMeta<T> {
// Iterate through all the getters.
bms.forEach(x -> {
var pn = x.propertyName;
- var m = x.method;
+ var m = x.method; // TODO - Convert to
MethodInfo
var mi = info(m);
var bpm =
normalProps.computeIfAbsent(pn, k -> new BeanPropertyMeta.Builder(this, k));
if (x.methodType == GETTER) {
// Two getters. Pick the best.
if (nn(bpm.getter)) {
- if (!
ap.has(Beanp.class, mi) && ap.has(Beanp.class, info(bpm.getter))) {
- m = bpm.getter;
// @Beanp annotated method takes precedence.
- } else if
(m.getName().startsWith("is") && bpm.getter.getName().startsWith("get")) {
- m = bpm.getter;
// getX() overrides isX().
+ if (!
ap.has(Beanp.class, mi) && ap.has(Beanp.class, bpm.getter)) {
+ m =
bpm.getter.inner(); // @Beanp annotated method takes precedence.
+ } else if
(m.getName().startsWith("is") && bpm.getter.getSimpleName().startsWith("get")) {
+ m =
bpm.getter.inner(); // getX() overrides isX().
}
}
- bpm.setGetter(m);
+ bpm.setGetter(info(m));
}
});
@@ -500,7 +504,7 @@ public class BeanMeta<T> {
if (p.validate(beanContext,
beanRegistry.get(), typeVarImpls, readOnlyProps, writeOnlyProps)) {
if (nn(p.getter))
-
_getterProps.put(p.getter, p.name);
+
_getterProps.put(p.getter.inner(), p.name);
if (nn(p.setter))
_setterProps.put(p.setter, p.name);
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanPropertyMeta.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanPropertyMeta.java
index 2baaa04d62..fdc9c12ab3 100644
---
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanPropertyMeta.java
+++
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanPropertyMeta.java
@@ -67,7 +67,8 @@ public class BeanPropertyMeta implements
Comparable<BeanPropertyMeta> {
String name; // Package-private for BeanMeta access
FieldInfo field; // Package-private for BeanMeta access
FieldInfo innerField; // Package-private for BeanMeta access
- Method getter, setter, extraKeys; // Package-private for
BeanMeta access. TODO - Replace with MethodInfo fields
+ MethodInfo getter; // Package-private for BeanMeta access
+ Method setter, extraKeys; // Package-private for BeanMeta
access. TODO - Replace with MethodInfo fields
private boolean isConstructorArg, isUri, isDyna,
isDynaGetterMap;
private ClassMeta<?> rawTypeMeta, typeMeta;
private List<String> properties;
@@ -215,22 +216,20 @@ public class BeanPropertyMeta implements
Comparable<BeanPropertyMeta> {
*/
public BeanPropertyMeta.Builder setField(FieldInfo value) {
assertArgNotNull("value", value);
- value.accessible();
- this.field = value;
- this.innerField = value;
+ this.field = value.accessible();
+ this.innerField = this.field;
return this;
}
/**
* Sets the getter method for this bean property.
*
- * @param value The getter method for this bean property.
+ * @param value The getter method info for this bean property.
* @return This object.
*/
- public BeanPropertyMeta.Builder setGetter(Method value) {
+ public BeanPropertyMeta.Builder setGetter(MethodInfo value) {
assertArgNotNull("value", value);
- setAccessible(value);
- this.getter = value;
+ this.getter = value.accessible();
return this;
}
@@ -297,7 +296,7 @@ public class BeanPropertyMeta implements
Comparable<BeanPropertyMeta> {
canWrite |= (nn(field) || nn(setter));
var ifi = innerField;
- var gi = getter == null ? null : info(getter);
+ var gi = getter;
var si = setter == null ? null : info(setter);
if (nn(innerField)) {
@@ -327,7 +326,7 @@ public class BeanPropertyMeta implements
Comparable<BeanPropertyMeta> {
if (nn(getter)) {
var lp = ap.find(Beanp.class,
gi).stream().map(AnnotationInfo::inner).toList();
if (rawTypeMeta == null)
- rawTypeMeta =
bc.resolveClassMeta(last(lp), getter.getGenericReturnType(), typeVarImpls);
+ rawTypeMeta =
bc.resolveClassMeta(last(lp), getter.inner().getGenericReturnType(),
typeVarImpls);
isUri |= (rawTypeMeta.isUri() ||
ap.has(Uri.class, gi));
lp.forEach(x -> {
if (swap == null)
@@ -374,9 +373,9 @@ public class BeanPropertyMeta implements
Comparable<BeanPropertyMeta> {
if (nn(getter)) {
var pt = getter.getParameterTypes();
if (isDyna) {
- if (ci.isChildOf(Map.class) &&
pt.length == 0) {
+ if (ci.isChildOf(Map.class) &&
isEmpty(pt)) {
isDynaGetterMap = true;
- } else if (pt.length == 1 && pt[0] ==
String.class) {
+ } else if (pt.size() == 1 &&
pt.get(0).is(String.class)) {
// OK.
} else {
return false;
@@ -458,7 +457,8 @@ public class BeanPropertyMeta implements
Comparable<BeanPropertyMeta> {
private final FieldInfo field; // The
bean property field (if it has one).
private final FieldInfo innerField; //
The bean property field (if it has one).
- private final Method getter, setter, extraKeys; // The bean
property getter and setter.
+ private final MethodInfo getter; // The bean property getter.
+ private final Method setter, extraKeys; // The bean property
setter and extraKeys.
private final boolean isUri; // True if
this is a URL/URI or annotated with @URI.
private final boolean isDyna, isDynaGetterMap; // This is a
dyna property (i.e. name="*")
@@ -719,7 +719,7 @@ public class BeanPropertyMeta implements
Comparable<BeanPropertyMeta> {
if (nn(field))
ap.find(a,
field).stream().map(AnnotationInfo::inner).filter(filter).forEach(action);
if (nn(getter))
- ap.find(a, info(getter), SELF,
MATCHING_METHODS, RETURN_TYPE,
PACKAGE).stream().map(AnnotationInfo::inner).filter(filter).forEach(action);
+ ap.find(a, getter, SELF, MATCHING_METHODS,
RETURN_TYPE,
PACKAGE).stream().map(AnnotationInfo::inner).filter(filter).forEach(action);
if (nn(setter))
ap.find(a, info(setter), SELF,
MATCHING_METHODS, RETURN_TYPE,
PACKAGE).stream().map(AnnotationInfo::inner).filter(filter).forEach(action);
}
@@ -761,7 +761,7 @@ public class BeanPropertyMeta implements
Comparable<BeanPropertyMeta> {
var l = new LinkedList<A>();
var ap = bc.getAnnotationProvider();
var fi = field;
- var gi = getter == null ? null : info(getter);
+ var gi = getter;
var si = setter == null ? null : info(setter);
if (a == null)
return l;
@@ -772,7 +772,7 @@ public class BeanPropertyMeta implements
Comparable<BeanPropertyMeta> {
}
if (nn(gi)) {
// Walk up the inheritance hierarchy for the getter
method
- forEachParentMethod(getter, parentGetter -> {
+ forEachParentMethod(getter.inner(), parentGetter -> {
ap.find(a, info(parentGetter), SELF,
MATCHING_METHODS, RETURN_TYPE, PACKAGE).forEach(x -> l.add(x.inner()));
});
ap.find(a, gi, SELF, MATCHING_METHODS, RETURN_TYPE,
PACKAGE).forEach(x -> l.add(x.inner()));
@@ -881,9 +881,9 @@ public class BeanPropertyMeta implements
Comparable<BeanPropertyMeta> {
/**
* Returns the getter method for this property.
*
- * @return The getter method for this bean property, or <jk>null</jk>
if there is no getter method.
+ * @return The getter method info for this bean property, or
<jk>null</jk> if there is no getter method.
*/
- public Method getGetter() { return getter; }
+ public MethodInfo getGetter() { return getter; }
/**
* Returns the field for this property even if the field is private.
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlBeanPropertyMeta.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlBeanPropertyMeta.java
index 608acd1458..2f1aae7f68 100644
---
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlBeanPropertyMeta.java
+++
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlBeanPropertyMeta.java
@@ -85,7 +85,7 @@ public class HtmlBeanPropertyMeta extends
ExtendedBeanPropertyMeta {
if (nn(bpm.getInnerField()))
ap.find(Html.class, bpm.getInnerField()).forEach(x ->
b.findHtmlInfo(x.inner()));
if (nn(bpm.getGetter()))
- ap.find(Html.class, info(bpm.getGetter())).forEach(x ->
b.findHtmlInfo(x.inner()));
+ ap.find(Html.class, bpm.getGetter()).forEach(x ->
b.findHtmlInfo(x.inner()));
if (nn(bpm.getSetter()))
ap.find(Html.class, info(bpm.getSetter())).forEach(x ->
b.findHtmlInfo(x.inner()));
diff --git
a/juneau-utest/src/test/java/org/apache/juneau/commons/reflect/ExecutableInfo_Test.java
b/juneau-utest/src/test/java/org/apache/juneau/commons/reflect/ExecutableInfo_Test.java
index d30f8963d1..f0644a01a4 100644
---
a/juneau-utest/src/test/java/org/apache/juneau/commons/reflect/ExecutableInfo_Test.java
+++
b/juneau-utest/src/test/java/org/apache/juneau/commons/reflect/ExecutableInfo_Test.java
@@ -381,6 +381,38 @@ class ExecutableInfo_Test extends TestBase {
check("String,int",
b1.getDeclaredConstructors().get(0).getParameters().stream().map(ParameterInfo::getParameterType).toList());
}
+
//====================================================================================================
+ // getParameterTypes()
+
//====================================================================================================
+ @Test
+ void a013a_getParameterTypes() {
+ // Test with no parameters
+ check("", b_c1.getParameterTypes());
+ check("", b_m1.getParameterTypes());
+
+ // Test with single parameter
+ check("String", b_c2.getParameterTypes());
+ check("String", b_m2.getParameterTypes());
+
+ // Test with multiple parameters
+ var b1 = ClassInfo.of(B1.class);
+ check("String,int",
b1.getDeclaredConstructors().get(0).getParameterTypes());
+
+ // Test with different parameter types
+ check("int", c_c3.getParameterTypes());
+ check("int", c_m3.getParameterTypes());
+
+ // Test caching - should return same result
+ var types1 = b_c2.getParameterTypes();
+ var types2 = b_c2.getParameterTypes();
+ assertSame(types1, types2, "getParameterTypes() should return
cached result");
+
+ // Verify that getParameterTypes() returns the same types as
getParameters().stream().map(ParameterInfo::getParameterType)
+ var typesFromMethod = b_c2.getParameterTypes();
+ var typesFromParams =
b_c2.getParameters().stream().map(ParameterInfo::getParameterType).toList();
+ assertEquals(typesFromMethod, typesFromParams,
"getParameterTypes() should match types from getParameters()");
+ }
+
//====================================================================================================
// getShortName()
//====================================================================================================