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 40ebc4b4c4 Marshall module improvements
40ebc4b4c4 is described below
commit 40ebc4b4c4436256cba21d41fd57485e25a155e5
Author: James Bognar <[email protected]>
AuthorDate: Tue Dec 9 09:05:04 2025 -0500
Marshall module improvements
---
.../src/main/java/org/apache/juneau/BeanMeta.java | 88 +++++++++++++---------
1 file changed, 52 insertions(+), 36 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 7581ee04e3..4bccb219b5 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
@@ -248,14 +248,6 @@ public class BeanMeta<T> {
private static final BeanPropertyMeta[] EMPTY_PROPERTIES = {};
- private static void forEachClass(ClassInfo c, Class<?> stopClass,
Consumer<ClassInfo> consumer) {
- var sc = c.getSuperclass();
- if (nn(sc) && ! sc.is(stopClass))
- forEachClass(sc, stopClass, consumer);
- c.getInterfaces().forEach(x -> forEachClass(x, stopClass,
consumer));
- consumer.accept(c);
- }
-
static final String bpName(List<Beanp> p, List<Name> n) {
if (p.isEmpty() && n.isEmpty())
return null;
@@ -288,22 +280,37 @@ public class BeanMeta<T> {
return null;
}
- static final Collection<Field> findBeanFields(BeanContext ctx, Class<?>
c, Class<?> stopClass, Visibility v) {
- var l = new LinkedList<Field>();
+ /**
+ * Finds all bean fields in the class hierarchy.
+ *
+ * <p>
+ * Traverses the complete class hierarchy (as defined by {@link
#classHierarchy}) and collects all fields that
+ * meet the bean field criteria:
+ * <ul>
+ * <li>Not static
+ * <li>Not transient (unless transient fields are not ignored)
+ * <li>Not annotated with {@link Transient @Transient} (unless
transient fields are not ignored)
+ * <li>Not annotated with {@link BeanIgnore @BeanIgnore}
+ * <li>Visible according to the specified visibility level, or
annotated with {@link Beanp @Beanp}
+ * </ul>
+ *
+ * @param v The minimum visibility level required for fields to be
included.
+ * @return A collection of all bean fields found in the class hierarchy.
+ */
+ final Collection<Field> findBeanFields(Visibility v) {
var noIgnoreTransients = ! ctx.isIgnoreTransientFields();
- forEachClass(info(c), stopClass, c2 -> {
- // @formatter:off
- c2.getDeclaredFields().stream()
- .filter(x -> x.isNotStatic()
+ var ap = ctx.getAnnotationProvider();
+ // @formatter:off
+ return classHierarchy.get().stream()
+ .flatMap(c2 -> c2.getDeclaredFields().stream())
+ .filter(x -> x.isNotStatic()
&& (x.isNotTransient() || noIgnoreTransients)
&& (! x.hasAnnotation(Transient.class) ||
noIgnoreTransients)
- && !
ctx.getAnnotationProvider().has(BeanIgnore.class, x)
- && (v.isVisible(x.inner()) ||
ctx.getAnnotationProvider().has(Beanp.class, x)))
- .forEach(x -> l.add(x.inner())
- );
- // @formatter:on
- });
- return l;
+ && ! ap.has(BeanIgnore.class, x)
+ && (v.isVisible(x.inner()) ||
ap.has(Beanp.class, x)))
+ .map(FieldInfo::inner)
+ .toList();
+ // @formatter:on
}
/*
@@ -315,28 +322,27 @@ public class BeanMeta<T> {
* @param fixedBeanProps Only include methods whose properties are in
this list.
* @param pn Use this property namer to determine property names from
the method names.
*/
- static final List<BeanMethod> findBeanMethods(BeanContext ctx, Class<?>
c, Class<?> stopClass, Visibility v, PropertyNamer pn, boolean fluentSetters) {
+ final List<BeanMethod> findBeanMethods(Visibility v, PropertyNamer pn,
boolean fluentSetters) {
var l = new LinkedList<BeanMethod>();
var ap = ctx.getAnnotationProvider();
- forEachClass(info(c), stopClass, c2 -> {
+ classHierarchy.get().stream().forEach(c2 -> {
for (var m : c2.getDeclaredMethods()) {
+
if (m.isStatic() || m.isBridge() ||
m.getParameterCount() > 2 || m.getMatchingMethods().stream().anyMatch(m2 ->
ap.has(BeanIgnore.class, m2, SELF, MATCHING_METHODS)))
continue;
- var t = m.getMatchingMethods().stream().map(m2
-> ap.find(Transient.class,
m2).stream().map(AnnotationInfo::inner).findFirst().orElse(null)).filter(Objects::nonNull).findFirst()
- .orElse(null);
- if (nn(t) && t.value())
+ if (m.getMatchingMethods().stream().map(m2 ->
ap.find(Transient.class,
m2).stream().map(AnnotationInfo::inner).findFirst().orElse(null)).filter(Objects::nonNull).map(x
-> x.value()).findFirst().orElse(false))
continue;
- var lp = ap.find(Beanp.class,
m).stream().map(AnnotationInfo::inner).toList();
- var ln = ap.find(Name.class,
m).stream().map(AnnotationInfo::inner).toList();
+ var beanps = ap.find(Beanp.class,
m).stream().map(AnnotationInfo::inner).toList();
+ var names = ap.find(Name.class,
m).stream().map(AnnotationInfo::inner).toList();
// If this method doesn't have @Beanp or @Name,
check if it overrides a parent method that does
// This ensures property names are inherited
correctly, preventing duplicate property definitions
- inheritParentAnnotations(ctx, m, c, stopClass,
lp, ln);
+ inheritParentAnnotations(ctx, m, c, stopClass,
beanps, names);
- if (! (m.isVisible(v) || isNotEmpty(lp) ||
isNotEmpty(ln)))
+ if (! (m.isVisible(v) || isNotEmpty(beanps) ||
isNotEmpty(names)))
continue;
var n = m.getSimpleName();
@@ -344,7 +350,7 @@ public class BeanMeta<T> {
var params = m.getParameters();
var rt = m.getReturnType();
var methodType = UNKNOWN;
- var bpName = bpName(lp, ln);
+ var bpName = bpName(beanps, names);
if (params.isEmpty()) {
if ("*".equals(bpName)) {
@@ -425,10 +431,10 @@ public class BeanMeta<T> {
return l;
}
- static final Field findInnerBeanField(BeanContext ctx, Class<?> c,
Class<?> stopClass, String name) {
+ final Field findInnerBeanField(String name) {
var noIgnoreTransients = ! ctx.isIgnoreTransientFields();
var value = Value.<Field>empty();
- forEachClass(info(c), stopClass, c2 -> {
+ classHierarchy.get().stream().forEach(c2 -> {
// @formatter:off
c2.getDeclaredField(
x -> x.isNotStatic()
@@ -583,6 +589,16 @@ public class BeanMeta<T> {
return u(result);
}
+ private static void forEachClass(ClassInfo c, Class<?> stopClass,
Consumer<ClassInfo> consumer) {
+ var sc = c.getSuperclass();
+ if (nn(sc) && ! sc.is(stopClass))
+ forEachClass(sc, stopClass, consumer);
+ c.getInterfaces().forEach(x -> forEachClass(x, stopClass,
consumer));
+ consumer.accept(c);
+ }
+
+
+
private String findDictionaryName() {
if (nn(beanFilter) && nn(beanFilter.getTypeName()))
return beanFilter.getTypeName();
@@ -772,7 +788,7 @@ public class BeanMeta<T> {
} else /* Use 'better' introspection */ {
- findBeanFields(ctx, c2, stopClass,
fVis).forEach(x -> {
+ findBeanFields(fVis).forEach(x -> {
var name =
ap.find(info(x)).stream().filter(x2 -> x2.isType(Beanp.class) ||
x2.isType(Name.class)).map(x2 ->
name(x2)).filter(Objects::nonNull).findFirst().orElse(propertyNamer.getPropertyName(x.getName()));
if (nn(name)) {
if (!
normalProps.containsKey(name))
@@ -781,7 +797,7 @@ public class BeanMeta<T> {
}
});
- var bms = findBeanMethods(ctx, c2, stopClass,
mVis, propertyNamer, fluentSetters);
+ var bms = findBeanMethods(mVis, propertyNamer,
fluentSetters);
// Iterate through all the getters.
bms.forEach(x -> {
@@ -830,7 +846,7 @@ public class BeanMeta<T> {
var p = i.next();
try {
if (p.field == null)
-
p.setInnerField(findInnerBeanField(ctx, c, stopClass, p.name));
+
p.setInnerField(findInnerBeanField(p.name));
if (p.validate(ctx, beanRegistry.get(),
typeVarImpls, bpro, bpwo)) {