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 8805a94369 Marshall module improvements
8805a94369 is described below

commit 8805a943693aa9ef486b7825a233681c56879ffd
Author: James Bognar <[email protected]>
AuthorDate: Mon Dec 8 18:59:39 2025 -0500

    Marshall module improvements
---
 .../src/main/java/org/apache/juneau/BeanMeta.java  | 688 ++++++++++-----------
 1 file changed, 335 insertions(+), 353 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 cd09e9ec51..d936bf8012 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
@@ -238,342 +238,6 @@ public class BeanMeta<T> {
                }
        }
 
-       private static class Builder<T> {
-               ClassMeta<T> _classMeta;
-               BeanContext _ctx;
-               AnnotationProvider _ap;
-               BeanFilter _beanFilter;
-               String[] _pNames;
-               Map<String,BeanPropertyMeta> _properties;
-               Map<String,BeanPropertyMeta> _hiddenProperties = map();
-               Map<Method,String> _getterProps = map();
-               Map<Method,String> _setterProps = map();
-               BeanPropertyMeta _dynaProperty;
-
-               ConstructorInfo _constructor, _implClassConstructor;
-               String[] _constructorArgs = {};
-               PropertyNamer _propertyNamer;
-               BeanRegistry _beanRegistry;
-               String _typePropertyName;
-               boolean _sortProperties, _fluentSetters;
-               String notABeanReason;
-
-               Builder(ClassMeta<T> classMeta, BeanContext ctx, BeanFilter 
beanFilter, String[] pNames, ConstructorInfo implClassConstructor) {
-                       this._classMeta = classMeta;
-                       this._ctx = ctx;
-                       this._ap = ctx.getAnnotationProvider();
-                       this._beanFilter = beanFilter;
-                       this._pNames = pNames;
-                       this._implClassConstructor = implClassConstructor;
-               }
-
-               void init(BeanMeta<T> beanMeta) {
-                       var c = _classMeta.inner();
-                       var ci = _classMeta;
-                       var ap = _ctx.getAnnotationProvider();
-
-                       try {
-                               var conVis = 
_ctx.getBeanConstructorVisibility();
-                               var mVis = _ctx.getBeanMethodVisibility();
-                               var fVis = _ctx.getBeanFieldVisibility();
-
-                               List<Class<?>> bdClasses = list();
-                               if (nn(_beanFilter) && 
nn(_beanFilter.getBeanDictionary()))
-                                       addAll(bdClasses, 
_beanFilter.getBeanDictionary());
-
-                               var typeName = Value.<String>empty();
-                               _classMeta.forEachAnnotation(Bean.class, x -> 
isNotEmpty(x.typeName()), x -> typeName.set(x.typeName()));
-                               if (typeName.isPresent())
-                                       bdClasses.add(_classMeta.inner());
-                               this._beanRegistry = new BeanRegistry(_ctx, 
null, bdClasses.toArray(new Class<?>[bdClasses.size()]));
-
-                               var typePropertyName = Value.<String>empty();
-                               _classMeta.forEachAnnotation(Bean.class, x -> 
isNotEmpty(x.typePropertyName()), x -> 
typePropertyName.set(x.typePropertyName()));
-                               this._typePropertyName = 
typePropertyName.orElseGet(() -> _ctx.getBeanTypePropertyName());
-
-                               _fluentSetters = (_ctx.isFindFluentSetters() || 
(nn(_beanFilter) && _beanFilter.isFluentSetters()));
-
-                               // If @Bean.interfaceClass is specified on the 
parent class, then we want
-                               // to use the properties defined on that class, 
not the subclass.
-                               var c2 = (nn(_beanFilter) && 
nn(_beanFilter.getInterfaceClass()) ? _beanFilter.getInterfaceClass() : c);
-
-                               var stopClass = (nn(_beanFilter) ? 
_beanFilter.getStopClass() : Object.class);
-                               if (stopClass == null)
-                                       stopClass = Object.class;
-
-                               Map<String,BeanPropertyMeta.Builder> 
normalProps = map();  // NOAI
-
-                               var hasBean = ap.has(Bean.class, ci);
-
-                               // Look for @Beanc constructor on public 
constructors.
-                               ci.getPublicConstructors().stream().filter(x -> 
ap.has(Beanc.class, x)).forEach(x -> {
-                                       if (nn(_constructor))
-                                               throw bex(c, "Multiple 
instances of '@Beanc' found.");
-                                       _constructor = x;
-                                       _constructorArgs = new String[0];
-                                       ap.find(Beanc.class, x).stream().map(x2 
-> 
x2.inner().properties()).filter(StringUtils::isNotBlank).findFirst().ifPresent(z
 -> _constructorArgs = splita(z));
-                                       if (! 
x.hasNumParameters(_constructorArgs.length)) {
-                                               if (_constructorArgs.length != 
0)
-                                                       throw bex(c, "Number of 
properties defined in '@Beanc' annotation does not match number of parameters 
in constructor.");
-                                               _constructorArgs = new 
String[x.getParameterCount()];
-                                               var i = IntegerValue.create();
-                                               x.getParameters().forEach(pi -> 
{
-                                                       var pn = pi.getName();
-                                                       if (pn == null)
-                                                               throw bex(c, 
"Could not find name for parameter #{0} of constructor ''{1}''", i, 
x.getFullName());
-                                                       
_constructorArgs[i.getAndIncrement()] = pn;
-                                               });
-                                       }
-                                       _constructor.setAccessible();
-                               });
-
-                               // Look for @Beanc on all other constructors.
-                               if (_constructor == null) {
-                                       
ci.getDeclaredConstructors().stream().filter(x -> ap.has(Beanc.class, 
x)).forEach(x -> {
-                                               if (nn(_constructor))
-                                                       throw bex(c, "Multiple 
instances of '@Beanc' found.");
-                                               _constructor = x;
-                                               _constructorArgs = new 
String[0];
-                                               ap.find(Beanc.class, 
x).stream().map(x2 -> 
x2.inner().properties()).filter(Utils::isNotEmpty).findFirst().ifPresent(z -> 
_constructorArgs = splita(z));
-                                               if (! 
x.hasNumParameters(_constructorArgs.length)) {
-                                                       if 
(_constructorArgs.length != 0)
-                                                               throw bex(c, 
"Number of properties defined in '@Beanc' annotation does not match number of 
parameters in constructor.");
-                                                       _constructorArgs = new 
String[x.getParameterCount()];
-                                                       var i = 
IntegerValue.create();
-                                                       
x.getParameters().forEach(y -> {
-                                                               var pn = 
y.getName();
-                                                               if (pn == null)
-                                                                       throw 
bex(c, "Could not find name for parameter #{0} of constructor ''{1}''", i, 
x.getFullName());
-                                                               
_constructorArgs[i.getAndIncrement()] = pn;
-                                                       });
-                                               }
-                                               _constructor.setAccessible();
-                                       });
-                               }
-
-                               // If this is an interface, look for impl 
classes defined in the context.
-                               if (_constructor == null)
-                                       _constructor = _implClassConstructor;
-
-                               if (_constructor == null)
-                                       _constructor = 
ci.getNoArgConstructor(hasBean ? Visibility.PRIVATE : conVis).orElse(null);
-
-                               if (_constructor == null && _beanFilter == null 
&& _ctx.isBeansRequireDefaultConstructor())
-                                       notABeanReason = "Class does not have 
the required no-arg constructor";
-
-                               if (nn(_constructor))
-                                       _constructor.setAccessible();
-
-                               // Explicitly defined property names in @Bean 
annotation.
-                               Set<String> fixedBeanProps = set();
-                               Set<String> bpi = set();
-                               Set<String> bpx = set();
-                               Set<String> bpro = set();
-                               Set<String> bpwo = set();
-
-                               Set<String> filterProps = set();  // Names of 
properties defined in @Bean(properties)
-
-                               if (nn(_beanFilter)) {
-
-                                       var bfbpi = _beanFilter.getProperties();
-
-                                       filterProps.addAll(bfbpi);
-
-                                       // Get the 'properties' attribute if 
specified.
-                                       if (bpi.isEmpty())
-                                               fixedBeanProps.addAll(bfbpi);
-
-                                       if (nn(_beanFilter.getPropertyNamer()))
-                                               _propertyNamer = 
_beanFilter.getPropertyNamer();
-
-                                       
bpro.addAll(_beanFilter.getReadOnlyProperties());
-                                       
bpwo.addAll(_beanFilter.getWriteOnlyProperties());
-                               }
-
-                               fixedBeanProps.addAll(bpi);
-
-                               if (_propertyNamer == null)
-                                       _propertyNamer = 
_ctx.getPropertyNamer();
-
-                               // First populate the properties with those 
specified in the bean annotation to
-                               // ensure that ordering first.
-                               fixedBeanProps.forEach(x -> normalProps.put(x, 
BeanPropertyMeta.builder(beanMeta, x)));
-
-                               if (_ctx.isUseJavaBeanIntrospector()) {
-                                       var bi = (BeanInfo)null;
-                                       if (! c2.isInterface())
-                                               bi = 
Introspector.getBeanInfo(c2, stopClass);
-                                       else
-                                               bi = 
Introspector.getBeanInfo(c2, null);
-                                       if (nn(bi)) {
-                                               for (var pd : 
bi.getPropertyDescriptors()) {
-                                                       var name = pd.getName();
-                                                       if (! 
normalProps.containsKey(name))
-                                                               
normalProps.put(name, BeanPropertyMeta.builder(beanMeta, name));
-                                                       
normalProps.get(name).setGetter(pd.getReadMethod()).setSetter(pd.getWriteMethod());
-                                               }
-                                       }
-
-                               } else /* Use 'better' introspection */ {
-
-                                       findBeanFields(_ctx, c2, stopClass, 
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))
-                                                               
normalProps.put(name, BeanPropertyMeta.builder(beanMeta, name));
-                                                       
normalProps.get(name).setField(x);
-                                               }
-                                       });
-
-                                       var bms = findBeanMethods(_ctx, c2, 
stopClass, mVis, _propertyNamer, _fluentSetters);
-
-                                       // Iterate through all the getters.
-                                       bms.forEach(x -> {
-                                               var pn = x.propertyName;
-                                               var m = x.method;
-                                               var mi = info(m);
-                                               if (! 
normalProps.containsKey(pn))
-                                                       normalProps.put(pn, new 
BeanPropertyMeta.Builder(beanMeta, pn));
-                                               var bpm = normalProps.get(pn);
-                                               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().
-                                                       }
-                                                       bpm.setGetter(m);
-                                               }
-                                       });
-
-                                       // Now iterate through all the setters.
-                                       bms.forEach(x -> {
-                                               if (x.methodType == SETTER) {
-                                                       var bpm = 
normalProps.get(x.propertyName);
-                                                       if 
(x.matchesPropertyType(bpm))
-                                                               
bpm.setSetter(x.method);
-                                               }
-                                       });
-
-                                       // Now iterate through all the 
extraKeys.
-                                       bms.forEach(x -> {
-                                               if (x.methodType == EXTRAKEYS) {
-                                                       var bpm = 
normalProps.get(x.propertyName);
-                                                       
bpm.setExtraKeys(x.method);
-                                               }
-                                       });
-                               }
-
-                               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();) {
-                                       var p = i.next();
-                                       try {
-                                               if (p.field == null)
-                                                       
p.setInnerField(findInnerBeanField(_ctx, c, stopClass, p.name));
-
-                                               if (p.validate(_ctx, 
_beanRegistry, typeVarImpls, bpro, bpwo)) {
-
-                                                       if (nn(p.getter))
-                                                               
_getterProps.put(p.getter, p.name);
-
-                                                       if (nn(p.setter))
-                                                               
_setterProps.put(p.setter, p.name);
-
-                                               } else {
-                                                       i.remove();
-                                               }
-                                       } catch (ClassNotFoundException e) {
-                                               throw bex(c, lm(e));
-                                       }
-                               }
-
-                               // Check for missing properties.
-                               fixedBeanProps.forEach(x -> {
-                                       if (! normalProps.containsKey(x))
-                                               throw bex(c, "The property 
''{0}'' was defined on the @Bean(properties=X) annotation of class ''{1}'' but 
was not found on the class definition.", x, ci.getNameSimple());
-                               });
-
-                               // Mark constructor arg properties.
-                               for (var fp : _constructorArgs) {
-                                       var m = normalProps.get(fp);
-                                       if (m == null)
-                                               throw bex(c, "The property 
''{0}'' was defined on the @Beanc(properties=X) annotation but was not found on 
the class definition.", fp);
-                                       m.setAsConstructorArg();
-                               }
-
-                               // Make sure at least one property was found.
-                               if (_beanFilter == null && 
_ctx.isBeansRequireSomeProperties() && normalProps.isEmpty())
-                                       notABeanReason = "No properties 
detected on bean class";
-
-                               _sortProperties = (_ctx.isSortProperties() || 
(nn(_beanFilter) && _beanFilter.isSortProperties())) && 
fixedBeanProps.isEmpty();
-
-                               _properties = _sortProperties ? sortedMap() : 
map();
-
-                               normalProps.forEach((k, v) -> {
-                                       var pMeta = v.build();
-                                       if (pMeta.isDyna())
-                                               _dynaProperty = pMeta;
-                                       _properties.put(k, pMeta);
-                               });
-
-                               // If a beanFilter is defined, look for 
inclusion and exclusion lists.
-                               if (nn(_beanFilter)) {
-
-                                       // Eliminated excluded properties if 
BeanFilter.excludeKeys is specified.
-                                       Set<String> bfbpi = 
_beanFilter.getProperties();
-                                       Set<String> bfbpx = 
_beanFilter.getExcludeProperties();
-
-                                       if (bpi.isEmpty() && ! bfbpi.isEmpty()) 
{
-                                               // Only include specified 
properties if BeanFilter.includeKeys is specified.
-                                               // Note that the order must 
match includeKeys.
-                                               Map<String,BeanPropertyMeta> 
properties2 = map();  // NOAI
-                                               bfbpi.forEach(x -> {
-                                                       if 
(_properties.containsKey(x))
-                                                               
properties2.put(x, _properties.remove(x));
-                                               });
-                                               
_hiddenProperties.putAll(_properties);
-                                               _properties = properties2;
-                                       }
-                                       if (bpx.isEmpty() && ! bfbpx.isEmpty()) 
{
-                                               bfbpx.forEach(x -> 
_hiddenProperties.put(x, _properties.remove(x)));
-                                       }
-                               }
-
-                               if (! bpi.isEmpty()) {
-                                       Map<String,BeanPropertyMeta> 
properties2 = map();  // NOAI
-                                       bpi.forEach(x -> {
-                                               if (_properties.containsKey(x))
-                                                       properties2.put(x, 
_properties.remove(x));
-                                       });
-                                       _hiddenProperties.putAll(_properties);
-                                       _properties = properties2;
-                               }
-
-                               bpx.forEach(x -> _hiddenProperties.put(x, 
_properties.remove(x)));
-
-                               if (nn(_pNames)) {
-                                       Map<String,BeanPropertyMeta> 
properties2 = map();
-                                       for (var k : _pNames) {
-                                               if (_properties.containsKey(k))
-                                                       properties2.put(k, 
_properties.get(k));
-                                               else
-                                                       
_hiddenProperties.put(k, _properties.get(k));
-                                       }
-                                       _properties = properties2;
-                               }
-
-                       } catch (BeanRuntimeException e) {
-                               throw e;
-                       } catch (Exception e) {
-                               notABeanReason = "Exception:  " + 
getStackTrace(e);
-                       }
-               }
-       }
 
        /**
         * Possible property method types.
@@ -945,25 +609,343 @@ public class BeanMeta<T> {
                this.classMeta = classMeta;
                this.ctx = classMeta.getBeanContext();
                this.c = classMeta.inner();
+               this.beanFilter = beanFilter;
 
-               Builder<T> b = new Builder<>(classMeta, 
classMeta.getBeanContext(), beanFilter, pNames, implClassConstructor);
-               b.init(this);
-               notABeanReason = b.notABeanReason;
+               // Local variables for initialization
+               var ap = ctx.getAnnotationProvider();
+               var c = classMeta.inner();
+               var ci = classMeta;
+               String notABeanReason = null;
+               var properties = Value.<Map<String,BeanPropertyMeta>>empty();
+               Map<String,BeanPropertyMeta> hiddenProperties = map();
+               Map<Method,String> getterProps = map();
+               Map<Method,String> setterProps = map();
+               var dynaProperty = Value.<BeanPropertyMeta>empty();
+               var constructor = Value.<ConstructorInfo>empty();
+               var constructorArgs = Value.<String[]>of(new String[0]);
+               var propertyNamer = Value.<PropertyNamer>empty();
+               BeanRegistry beanRegistry = null;
+               String typePropertyName = null;
+               boolean sortProperties = false;
+               boolean fluentSetters = false;
 
-               this.beanFilter = beanFilter;
-               properties = u(b._properties);
-               propertyArray = properties == null ? EMPTY_PROPERTIES : 
array(properties.values(), BeanPropertyMeta.class);
-               hiddenProperties = u(b._hiddenProperties);
-               getterProps = u(b._getterProps);
-               setterProps = u(b._setterProps);
-               dynaProperty = b._dynaProperty;
-               constructor = b._constructor;
-               constructorArgs = b._constructorArgs;
-               beanRegistry = b._beanRegistry;
-               typePropertyName = b._typePropertyName;
-               typeProperty = BeanPropertyMeta.builder(this, 
typePropertyName).canRead().canWrite().rawMetaType(ctx.string()).beanRegistry(beanRegistry).build();
-               sortProperties = b._sortProperties;
-               fluentSetters = b._fluentSetters;
+               try {
+                       var conVis = ctx.getBeanConstructorVisibility();
+                       var mVis = ctx.getBeanMethodVisibility();
+                       var fVis = ctx.getBeanFieldVisibility();
+
+                       List<Class<?>> bdClasses = list();
+                       if (nn(beanFilter) && 
nn(beanFilter.getBeanDictionary()))
+                               addAll(bdClasses, 
beanFilter.getBeanDictionary());
+
+                       var typeName = Value.<String>empty();
+                       classMeta.forEachAnnotation(Bean.class, x -> 
isNotEmpty(x.typeName()), x -> typeName.set(x.typeName()));
+                       if (typeName.isPresent())
+                               bdClasses.add(classMeta.inner());
+                       beanRegistry = new BeanRegistry(ctx, null, 
bdClasses.toArray(new Class<?>[bdClasses.size()]));
+
+                       var typePropertyNameValue = Value.<String>empty();
+                       classMeta.forEachAnnotation(Bean.class, x -> 
isNotEmpty(x.typePropertyName()), x -> 
typePropertyNameValue.set(x.typePropertyName()));
+                       typePropertyName = typePropertyNameValue.orElseGet(() 
-> ctx.getBeanTypePropertyName());
+
+                       fluentSetters = (ctx.isFindFluentSetters() || 
(nn(beanFilter) && beanFilter.isFluentSetters()));
+
+                       // If @Bean.interfaceClass is specified on the parent 
class, then we want
+                       // to use the properties defined on that class, not the 
subclass.
+                       var c2 = (nn(beanFilter) && 
nn(beanFilter.getInterfaceClass()) ? beanFilter.getInterfaceClass() : c);
+
+                       var stopClass = (nn(beanFilter) ? 
beanFilter.getStopClass() : Object.class);
+                       if (stopClass == null)
+                               stopClass = Object.class;
+
+                       Map<String,BeanPropertyMeta.Builder> normalProps = 
map();  // NOAI
+
+                       var hasBean = ap.has(Bean.class, ci);
+
+                       // Look for @Beanc constructor on public constructors.
+                       ci.getPublicConstructors().stream().filter(x -> 
ap.has(Beanc.class, x)).forEach(x -> {
+                               if (constructor.isPresent())
+                                       throw bex(c, "Multiple instances of 
'@Beanc' found.");
+                               constructor.set(x);
+                               constructorArgs.set(new String[0]);
+                               ap.find(Beanc.class, x).stream().map(x2 -> 
x2.inner().properties()).filter(StringUtils::isNotBlank).findFirst().ifPresent(z
 -> constructorArgs.set(splita(z)));
+                               if (! 
x.hasNumParameters(constructorArgs.get().length)) {
+                                       if (constructorArgs.get().length != 0)
+                                               throw bex(c, "Number of 
properties defined in '@Beanc' annotation does not match number of parameters 
in constructor.");
+                                       constructorArgs.set(new 
String[x.getParameterCount()]);
+                                       var i = IntegerValue.create();
+                                       x.getParameters().forEach(pi -> {
+                                               var pn = pi.getName();
+                                               if (pn == null)
+                                                       throw bex(c, "Could not 
find name for parameter #{0} of constructor ''{1}''", i, x.getFullName());
+                                               
constructorArgs.get()[i.getAndIncrement()] = pn;
+                                       });
+                               }
+                               constructor.get().setAccessible();
+                       });
+
+                       // Look for @Beanc on all other constructors.
+                       if (! constructor.isPresent()) {
+                               ci.getDeclaredConstructors().stream().filter(x 
-> ap.has(Beanc.class, x)).forEach(x -> {
+                                       if (constructor.isPresent())
+                                               throw bex(c, "Multiple 
instances of '@Beanc' found.");
+                                       constructor.set(x);
+                                       constructorArgs.set(new String[0]);
+                                       ap.find(Beanc.class, x).stream().map(x2 
-> x2.inner().properties()).filter(Utils::isNotEmpty).findFirst().ifPresent(z 
-> constructorArgs.set(splita(z)));
+                                       if (! 
x.hasNumParameters(constructorArgs.get().length)) {
+                                               if 
(constructorArgs.get().length != 0)
+                                                       throw bex(c, "Number of 
properties defined in '@Beanc' annotation does not match number of parameters 
in constructor.");
+                                               constructorArgs.set(new 
String[x.getParameterCount()]);
+                                               var i = IntegerValue.create();
+                                               x.getParameters().forEach(y -> {
+                                                       var pn = y.getName();
+                                                       if (pn == null)
+                                                               throw bex(c, 
"Could not find name for parameter #{0} of constructor ''{1}''", i, 
x.getFullName());
+                                                       
constructorArgs.get()[i.getAndIncrement()] = pn;
+                                               });
+                                       }
+                                       constructor.get().setAccessible();
+                               });
+                       }
+
+                       // If this is an interface, look for impl classes 
defined in the context.
+                       if (! constructor.isPresent())
+                               constructor.set(implClassConstructor);
+
+                       if (! constructor.isPresent())
+                               constructor.set(ci.getNoArgConstructor(hasBean 
? Visibility.PRIVATE : conVis).orElse(null));
+
+                       if (! constructor.isPresent() && beanFilter == null && 
ctx.isBeansRequireDefaultConstructor())
+                               notABeanReason = "Class does not have the 
required no-arg constructor";
+
+                       if (constructor.isPresent())
+                               constructor.get().setAccessible();
+
+                       // Explicitly defined property names in @Bean 
annotation.
+                       Set<String> fixedBeanProps = set();
+                       Set<String> bpi = set();
+                       Set<String> bpx = set();
+                       Set<String> bpro = set();
+                       Set<String> bpwo = set();
+
+                       Set<String> filterProps = set();  // Names of 
properties defined in @Bean(properties)
+
+                       if (nn(beanFilter)) {
+
+                               var bfbpi = beanFilter.getProperties();
+
+                               filterProps.addAll(bfbpi);
+
+                               // Get the 'properties' attribute if specified.
+                               if (bpi.isEmpty())
+                                       fixedBeanProps.addAll(bfbpi);
+
+                               if (nn(beanFilter.getPropertyNamer()))
+                                       
propertyNamer.set(beanFilter.getPropertyNamer());
+
+                               bpro.addAll(beanFilter.getReadOnlyProperties());
+                               
bpwo.addAll(beanFilter.getWriteOnlyProperties());
+                       }
+
+                       fixedBeanProps.addAll(bpi);
+
+                       if (! propertyNamer.isPresent())
+                               propertyNamer.set(ctx.getPropertyNamer());
+
+                       // First populate the properties with those specified 
in the bean annotation to
+                       // ensure that ordering first.
+                       fixedBeanProps.forEach(x -> normalProps.put(x, 
BeanPropertyMeta.builder(this, x)));
+
+                       if (ctx.isUseJavaBeanIntrospector()) {
+                               var bi = (BeanInfo)null;
+                               if (! c2.isInterface())
+                                       bi = Introspector.getBeanInfo(c2, 
stopClass);
+                               else
+                                       bi = Introspector.getBeanInfo(c2, null);
+                               if (nn(bi)) {
+                                       for (var pd : 
bi.getPropertyDescriptors()) {
+                                               var name = pd.getName();
+                                               if (! 
normalProps.containsKey(name))
+                                                       normalProps.put(name, 
BeanPropertyMeta.builder(this, name));
+                                               
normalProps.get(name).setGetter(pd.getReadMethod()).setSetter(pd.getWriteMethod());
+                                       }
+                               }
+
+                       } else /* Use 'better' introspection */ {
+
+                               findBeanFields(ctx, c2, stopClass, 
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.get().getPropertyName(x.getName()));
+                                       if (nn(name)) {
+                                               if (! 
normalProps.containsKey(name))
+                                                       normalProps.put(name, 
BeanPropertyMeta.builder(this, name));
+                                               
normalProps.get(name).setField(x);
+                                       }
+                               });
+
+                               var bms = findBeanMethods(ctx, c2, stopClass, 
mVis, propertyNamer.get(), fluentSetters);
+
+                               // Iterate through all the getters.
+                               bms.forEach(x -> {
+                                       var pn = x.propertyName;
+                                       var m = x.method;
+                                       var mi = info(m);
+                                       if (! normalProps.containsKey(pn))
+                                               normalProps.put(pn, new 
BeanPropertyMeta.Builder(this, pn));
+                                       var bpm = normalProps.get(pn);
+                                       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().
+                                               }
+                                               bpm.setGetter(m);
+                                       }
+                               });
+
+                               // Now iterate through all the setters.
+                               bms.forEach(x -> {
+                                       if (x.methodType == SETTER) {
+                                               var bpm = 
normalProps.get(x.propertyName);
+                                               if (x.matchesPropertyType(bpm))
+                                                       bpm.setSetter(x.method);
+                                       }
+                               });
+
+                               // Now iterate through all the extraKeys.
+                               bms.forEach(x -> {
+                                       if (x.methodType == EXTRAKEYS) {
+                                               var bpm = 
normalProps.get(x.propertyName);
+                                               bpm.setExtraKeys(x.method);
+                                       }
+                               });
+                       }
+
+                       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();) {
+                               var p = i.next();
+                               try {
+                                       if (p.field == null)
+                                               
p.setInnerField(findInnerBeanField(ctx, c, stopClass, p.name));
+
+                                       if (p.validate(ctx, beanRegistry, 
typeVarImpls, bpro, bpwo)) {
+
+                                               if (nn(p.getter))
+                                                       
getterProps.put(p.getter, p.name);
+
+                                               if (nn(p.setter))
+                                                       
setterProps.put(p.setter, p.name);
+
+                                       } else {
+                                               i.remove();
+                                       }
+                               } catch (ClassNotFoundException e) {
+                                       throw bex(c, lm(e));
+                               }
+                       }
+
+                       // Check for missing properties.
+                       fixedBeanProps.forEach(x -> {
+                               if (! normalProps.containsKey(x))
+                                       throw bex(c, "The property ''{0}'' was 
defined on the @Bean(properties=X) annotation of class ''{1}'' but was not 
found on the class definition.", x, ci.getNameSimple());
+                       });
+
+                       // Mark constructor arg properties.
+                       for (var fp : constructorArgs.get()) {
+                               var m = normalProps.get(fp);
+                               if (m == null)
+                                       throw bex(c, "The property ''{0}'' was 
defined on the @Beanc(properties=X) annotation but was not found on the class 
definition.", fp);
+                               m.setAsConstructorArg();
+                       }
+
+                       // Make sure at least one property was found.
+                       if (beanFilter == null && 
ctx.isBeansRequireSomeProperties() && normalProps.isEmpty())
+                               notABeanReason = "No properties detected on 
bean class";
+
+                       sortProperties = (ctx.isSortProperties() || 
(nn(beanFilter) && beanFilter.isSortProperties())) && fixedBeanProps.isEmpty();
+
+                       properties.set(sortProperties ? sortedMap() : map());
+
+                       normalProps.forEach((k, v) -> {
+                               var pMeta = v.build();
+                               if (pMeta.isDyna())
+                                       dynaProperty.set(pMeta);
+                               properties.get().put(k, pMeta);
+                       });
+
+                       // If a beanFilter is defined, look for inclusion and 
exclusion lists.
+                       if (nn(beanFilter)) {
+
+                               // Eliminated excluded properties if 
BeanFilter.excludeKeys is specified.
+                               Set<String> bfbpi = beanFilter.getProperties();
+                               Set<String> bfbpx = 
beanFilter.getExcludeProperties();
+
+                               if (bpi.isEmpty() && ! bfbpi.isEmpty()) {
+                                       // Only include specified properties if 
BeanFilter.includeKeys is specified.
+                                       // Note that the order must match 
includeKeys.
+                                       Map<String,BeanPropertyMeta> 
properties2 = map();  // NOAI
+                                       bfbpi.forEach(x -> {
+                                               if 
(properties.get().containsKey(x))
+                                                       properties2.put(x, 
properties.get().remove(x));
+                                       });
+                                       
hiddenProperties.putAll(properties.get());
+                                       properties.set(properties2);
+                               }
+                               if (bpx.isEmpty() && ! bfbpx.isEmpty()) {
+                                       bfbpx.forEach(x -> 
hiddenProperties.put(x, properties.get().remove(x)));
+                               }
+                       }
+
+                       if (! bpi.isEmpty()) {
+                               Map<String,BeanPropertyMeta> properties2 = 
map();  // NOAI
+                               bpi.forEach(x -> {
+                                       if (properties.get().containsKey(x))
+                                               properties2.put(x, 
properties.get().remove(x));
+                               });
+                               hiddenProperties.putAll(properties.get());
+                               properties.set(properties2);
+                       }
+
+                       bpx.forEach(x -> hiddenProperties.put(x, 
properties.get().remove(x)));
+
+                       if (nn(pNames)) {
+                               Map<String,BeanPropertyMeta> properties2 = 
map();
+                               for (var k : pNames) {
+                                       if (properties.get().containsKey(k))
+                                               properties2.put(k, 
properties.get().get(k));
+                                       else
+                                               hiddenProperties.put(k, 
properties.get().get(k));
+                               }
+                               properties.set(properties2);
+                       }
+
+               } catch (BeanRuntimeException e) {
+                       throw e;
+               } catch (Exception e) {
+                       notABeanReason = "Exception:  " + getStackTrace(e);
+               }
+
+               // Assign to final fields
+               this.notABeanReason = notABeanReason;
+               this.properties = u(properties.get());
+               this.propertyArray = this.properties == null ? EMPTY_PROPERTIES 
: array(this.properties.values(), BeanPropertyMeta.class);
+               this.hiddenProperties = u(hiddenProperties);
+               this.getterProps = u(getterProps);
+               this.setterProps = u(setterProps);
+               this.dynaProperty = dynaProperty.get();
+               this.constructor = constructor.get();
+               this.constructorArgs = constructorArgs.get();
+               this.beanRegistry = beanRegistry;
+               this.typePropertyName = typePropertyName;
+               this.sortProperties = sortProperties;
+               this.fluentSetters = fluentSetters;
+
+               this.typeProperty = BeanPropertyMeta.builder(this, 
typePropertyName).canRead().canWrite().rawMetaType(ctx.string()).beanRegistry(beanRegistry).build();
 
                if (sortProperties)
                        Arrays.sort(propertyArray);

Reply via email to