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
commit 1a58c4422ac226c554f5c20ff34a16f78fe9e161 Author: James Bognar <[email protected]> AuthorDate: Wed May 13 10:14:13 2026 -0400 refactor: clear commons-side imports from 7 bean-runtime files (TODO-5 Phase C Task 5 Step F audit) Address all 8 tasks from the Step F audit. The 7 bean-runtime files (BeanMap, BeanMapEntry, BeanMeta, BeanPropertyMeta, BeanPropertyValue, BeanPropertyConsumer, BeanProxyInvocationHandler) now import only JDK and org.apache.juneau.commons.* — no juneau-marshall imports. - Lift @Marshalled annotation reads from BeanMeta to MarshalledBeanMetaInitializer - Move @Name annotation to commons.bean (+ sweep import references) - Retype BeanPropertyMeta.setPropertyValue and BeanMap.session to BeanSession - Remove defensive (ObjectSwap) cast in setPropertyValue (writeTransform already unswaps) - Replace FilteredKeyMap usage in BeanMap.getProperties with inline AbstractMap view - Narrow ParseException/SerializeException catch to commons BasicRuntimeException - Clean up wildcard imports; use fully-qualified Javadoc links for marshalling types Three files are fully move-ready (BeanMapEntry, BeanPropertyConsumer, BeanProxyInvocationHandler); the other four have a handful of code-level move-blockers documented in todo/TODO-5-bean-runtime-types-to-commons.md. Full build + test suite green. Co-authored-by: Cursor <[email protected]> --- .../org/apache/juneau/commons/bean/BeanCtor.java | 4 +- .../org/apache/juneau/commons/bean/BeanProp.java | 2 +- .../java/org/apache/juneau/commons/bean}/Name.java | 8 +-- .../juneau/commons/reflect/AnnotationInfo.java | 2 +- .../src/main/java/org/apache/juneau/BeanMap.java | 69 +++++++++++++------ .../main/java/org/apache/juneau/BeanMapEntry.java | 11 ++- .../src/main/java/org/apache/juneau/BeanMeta.java | 45 ++++++------- .../java/org/apache/juneau/BeanPropertyMeta.java | 78 ++++++++++------------ .../juneau/MarshalledBeanMetaInitializer.java | 21 +++--- .../juneau/commons/reflect/ParameterInfo_Test.java | 22 +++--- todo/TODO-5-bean-runtime-types-to-commons.md | 63 +++++++++++++++++ 11 files changed, 203 insertions(+), 122 deletions(-) diff --git a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/bean/BeanCtor.java b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/bean/BeanCtor.java index 11102bab05..94971dd980 100644 --- a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/bean/BeanCtor.java +++ b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/bean/BeanCtor.java @@ -109,8 +109,8 @@ public @interface BeanCtor { * } * </p> * <p> - * Note that the {@link org.apache.juneau.annotation.Name @Name} annotation can also be used to identify bean property names on constructor - * arguments. If neither this annotation or {@link org.apache.juneau.annotation.Name @Name} is used, then we try to get the property names + * Note that the {@link Name @Name} annotation can also be used to identify bean property names on constructor + * arguments. If neither this annotation or {@link Name @Name} is used, then we try to get the property names * from the parameter names if they are available in the bytecode. * </p> * diff --git a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/bean/BeanProp.java b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/bean/BeanProp.java index 63e9ef8e90..7d08eac3e7 100644 --- a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/bean/BeanProp.java +++ b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/bean/BeanProp.java @@ -186,7 +186,7 @@ public @interface BeanProp { * </p> * * <div class='info'> - * Note that the {@link org.apache.juneau.annotation.Name @Name} annotation can also be used for identifying a property name. + * Note that the {@link Name @Name} annotation can also be used for identifying a property name. * </div> * * @return The annotation value. diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/annotation/Name.java b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/bean/Name.java similarity index 89% rename from juneau-core/juneau-marshall/src/main/java/org/apache/juneau/annotation/Name.java rename to juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/bean/Name.java index e07733b8eb..523f404278 100644 --- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/annotation/Name.java +++ b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/bean/Name.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.juneau.annotation; +package org.apache.juneau.commons.bean; import static java.lang.annotation.ElementType.*; import static java.lang.annotation.RetentionPolicy.*; @@ -48,10 +48,10 @@ import org.apache.juneau.commons.inject.BeanStore; * * <h5 class='section'>Comparison with @Named:</h5> * <p> - * Do not confuse this annotation with {@link Named @Named}, which serves a different purpose: + * Do not confuse this annotation with {@link org.apache.juneau.annotation.Named @Named}, which serves a different purpose: * <ul> * <li><b>{@link Name @Name}</b> - Specifies the parameter name for bean property mapping - * <li><b>{@link Named @Named}</b> - Specifies which named bean to inject (bean qualifier) + * <li><b>{@link org.apache.juneau.annotation.Named @Named}</b> - Specifies which named bean to inject (bean qualifier) * </ul> * * <h5 class='section'>Example showing the difference:</h5> @@ -68,7 +68,7 @@ import org.apache.juneau.commons.inject.BeanStore; * </p> * * <h5 class='section'>See Also:</h5><ul> - * <li class='ja'>{@link Named} + * <li class='ja'>{@link org.apache.juneau.annotation.Named} * <li class='jc'>{@link BeanStore} * </ul> */ diff --git a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/reflect/AnnotationInfo.java b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/reflect/AnnotationInfo.java index 58299aedd2..fdcb34f8a2 100644 --- a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/reflect/AnnotationInfo.java +++ b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/reflect/AnnotationInfo.java @@ -640,7 +640,7 @@ public class AnnotationInfo<T extends Annotation> { * * <h5 class='section'>Example:</h5> * <p class='bjava'> - * <jk>boolean</jk> <jv>isName</jv> = <jv>annotationInfo</jv>.hasName(<js>"org.apache.juneau.annotation.Name"</js>); + * <jk>boolean</jk> <jv>isName</jv> = <jv>annotationInfo</jv>.hasName(<js>"org.apache.juneau.commons.bean.Name"</js>); * </p> * * @param value The fully-qualified name to check. diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanMap.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanMap.java index 4ba73a7f2d..37f1ad92a9 100644 --- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanMap.java +++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanMap.java @@ -25,11 +25,8 @@ import static org.apache.juneau.commons.utils.Utils.*; import java.util.*; import java.util.function.*; -import org.apache.juneau.annotation.*; import org.apache.juneau.commons.bean.*; import org.apache.juneau.commons.reflect.*; -import org.apache.juneau.internal.*; -import org.apache.juneau.swap.*; /** * Java bean wrapper class. @@ -40,7 +37,7 @@ import org.apache.juneau.swap.*; * object can be accessed using the {@link Map#get(Object) get()} and {@link Map#put(Object,Object) put()} methods. * * <p> - * Use the {@link MarshallingContext} class to create instances of this class. + * Use the {@link org.apache.juneau.MarshallingContext} class to create instances of this class. * * <h5 class='topic'>Bean property order</h5> * @@ -48,16 +45,16 @@ import org.apache.juneau.swap.*; * methods are as follows: * <ul class='spaced-list'> * <li> - * If {@link Bean @Marshalled} annotation is specified on class, then the order is the same as the list of properties + * If {@link org.apache.juneau.annotation.Marshalled @Marshalled} annotation is specified on class, then the order is the same as the list of properties * in the annotation. * <li> - * If {@link Bean @Marshalled} annotation is not specified on the class, then the order is the same as that returned + * If {@link org.apache.juneau.annotation.Marshalled @Marshalled} annotation is not specified on the class, then the order is the same as that returned * by the {@link java.beans.BeanInfo} class (i.e. ordered by definition in the class). * </ul> * * <h5 class='topic'>POJO swaps</h5> * - * If {@link ObjectSwap ObjectSwaps} are defined on the class types of the properties of this bean or the bean properties + * If {@link org.apache.juneau.swap.ObjectSwap ObjectSwaps} are defined on the class types of the properties of this bean or the bean properties * themselves, the {@link #get(Object)} and {@link #put(String, Object)} methods will automatically transform the * property value to and from the serialized form. * @@ -109,7 +106,7 @@ public class BeanMap<T> extends AbstractMap<String,Object> implements Delegate<T /** The BeanMeta associated with the class of the object. */ protected BeanMeta<T> meta; - private MarshallingSession session; + private BeanSession session; private final String typePropertyName; @@ -117,8 +114,8 @@ public class BeanMap<T> extends AbstractMap<String,Object> implements Delegate<T * Constructor. * * <p> - * Bean-modeling-only constructor. Does not carry a {@link MarshallingSession} reference. - * The marshalling layer wires the session in via {@link #setMarshallingSession(MarshallingSession)} + * Bean-modeling-only constructor. Does not carry a {@link BeanSession} reference. + * The marshalling layer wires the session in via {@link #setMarshallingSession(BeanSession)} * immediately after construction. * * @param bean The bean to wrap inside this map. @@ -133,18 +130,18 @@ public class BeanMap<T> extends AbstractMap<String,Object> implements Delegate<T } /** - * Wires this bean map to a {@link MarshallingSession}. + * Wires this bean map to a {@link BeanSession}. * * <p> - * Transitional API used by the marshalling layer (e.g. {@link MarshallingSession#toBeanMap(Object)}) + * Transitional API used by the marshalling layer (e.g. {@link org.apache.juneau.MarshallingSession#toBeanMap(Object)}) * to wire a session into a {@link BeanMap} immediately after construction. Required for any * marshalling-side operation that depends on session-aware behavior (type conversion, child * collection construction, etc.). Will be removed when {@link BeanMap} is fully decoupled from * the marshalling layer (TODO-5 Step 5+). * - * @param value The marshalling session that produced this bean map. + * @param value The bean session that produced this bean map. Typically a {@link org.apache.juneau.MarshallingSession}. */ - protected void setMarshallingSession(MarshallingSession value) { + protected void setMarshallingSession(BeanSession value) { this.session = value; } @@ -330,11 +327,11 @@ public class BeanMap<T> extends AbstractMap<String,Object> implements Delegate<T * Gets a property on the bean. * * <p> - * If there is a {@link ObjectSwap} associated with this bean property or bean property type class, then this method + * If there is a {@link org.apache.juneau.swap.ObjectSwap} associated with this bean property or bean property type class, then this method * will return the transformed value. * For example, if the bean property type class is a {@link Date} and the bean property has the * {@link org.apache.juneau.swaps.TemporalDateSwap.IsoInstant} swap associated with it through the - * {@link Swap#value() @Swap(value)} annotation, this method will return a String containing an + * {@link org.apache.juneau.annotation.Swap#value() @Swap(value)} annotation, this method will return a String containing an * ISO8601 date-time string value. * * <h5 class='section'>Example:</h5> @@ -502,9 +499,15 @@ public class BeanMap<T> extends AbstractMap<String,Object> implements Delegate<T /** * Returns the bean session that created this bean map. * + * <p> + * The returned value is the bean-modeling SPI seam. Marshalling-side callers needing the concrete + * {@link org.apache.juneau.MarshallingSession} can cast — every session wired in via + * {@link #setMarshallingSession(BeanSession)} on the marshalling-side path is a + * {@link org.apache.juneau.MarshallingSession}. + * * @return The bean session that created this bean map. */ - public final MarshallingSession getMarshallingSession() { return session; } + public final BeanSession getBeanSession() { return session; } /** * Returns the {@link BeanTypeInfo} of the wrapped bean. @@ -524,13 +527,39 @@ public class BeanMap<T> extends AbstractMap<String,Object> implements Delegate<T /** * Extracts the specified field values from this bean and returns it as a simple Map. * + * <p> + * The returned map is a <i>live</i> view over this bean map: each entry's {@code getValue} reads through to + * {@code BeanMap.get} and {@code setValue} writes through to {@code BeanMap.put}. Unknown {@code fields} + * (keys not present in this bean map) are silently skipped. + * * @param fields The fields to extract. * @return * A new map with fields as key-value pairs. * <br>Note that modifying the values in this map will also modify the underlying bean. */ + @SuppressWarnings({ + "unchecked" // BeanMap<T> is unconditionally a Map<String,Object> via AbstractMap superclass. + }) public Map<String,Object> getProperties(String...fields) { - return new FilteredKeyMap<>(null, this, fields); + var thisMap = (Map<String,Object>) this; + var entries = new ArrayList<Map.Entry<String,Object>>(fields.length); + for (var k : fields) { + if (thisMap.containsKey(k)) { + entries.add(new Map.Entry<>() { + @Override public String getKey() { return k; } + @Override public Object getValue() { return thisMap.get(k); } + @Override public Object setValue(Object v) { return thisMap.put(k, v); } + }); + } + } + return new AbstractMap<>() { + @Override public Set<Map.Entry<String,Object>> entrySet() { + return new AbstractSet<>() { + @Override public Iterator<Map.Entry<String,Object>> iterator() { return entries.iterator(); } + @Override public int size() { return entries.size(); } + }; + } + }; } /** @@ -623,11 +652,11 @@ public class BeanMap<T> extends AbstractMap<String,Object> implements Delegate<T * Sets a property on the bean. * * <p> - * If there is a {@link ObjectSwap} associated with this bean property or bean property type class, then you must pass + * If there is a {@link org.apache.juneau.swap.ObjectSwap} associated with this bean property or bean property type class, then you must pass * in a transformed value. * For example, if the bean property type class is a {@link Date} and the bean property has the * {@link org.apache.juneau.swaps.TemporalDateSwap.IsoInstant} swap associated with it through the - * {@link Swap#value() @Swap(value)} annotation, the value being passed in must be + * {@link org.apache.juneau.annotation.Swap#value() @Swap(value)} annotation, the value being passed in must be * a String containing an ISO8601 date-time string value. * * <h5 class='section'>Example:</h5> diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanMapEntry.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanMapEntry.java index ef94157713..548d390066 100644 --- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanMapEntry.java +++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanMapEntry.java @@ -18,9 +18,6 @@ package org.apache.juneau; import java.util.*; -import org.apache.juneau.annotation.*; -import org.apache.juneau.swap.*; - /** * Represents a single entry in a bean map. * @@ -88,11 +85,11 @@ public class BeanMapEntry implements Map.Entry<String,Object> { * Returns the value of this property. * * <p> - * If there is a {@link ObjectSwap} associated with this bean property or bean property type class, then this method + * If there is a {@link org.apache.juneau.swap.ObjectSwap} associated with this bean property or bean property type class, then this method * will return the transformed value. * For example, if the bean property type class is a {@link Date} and the bean property has the * {@link org.apache.juneau.swaps.TemporalDateSwap.IsoInstant} swap associated with it through the - * {@link Swap#value() @Swap(value)} annotation, this method will return a String containing an + * {@link org.apache.juneau.annotation.Swap#value() @Swap(value)} annotation, this method will return a String containing an * ISO8601 date-time string value. */ @Override /* Overridden from Map.Entry */ @@ -109,11 +106,11 @@ public class BeanMapEntry implements Map.Entry<String,Object> { * If the property is a bean type {@code X}, then the value can either be an {@code X} or a {@code Map}. * * <p> - * If there is a {@link ObjectSwap} associated with this bean property or bean property type class, then you must pass + * If there is a {@link org.apache.juneau.swap.ObjectSwap} associated with this bean property or bean property type class, then you must pass * in a transformed value. * For example, if the bean property type class is a {@link Date} and the bean property has the * {@link org.apache.juneau.swaps.TemporalDateSwap.IsoInstant} swap associated with it through the - * {@link Swap#value() @Swap(value)} annotation, the value being passed in must be a String + * {@link org.apache.juneau.annotation.Swap#value() @Swap(value)} annotation, the value being passed in must be a String * containing an ISO8601 date-time string value. * * @return The set value after it's been converted. 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 1136b1e611..772fdb35dd 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 @@ -31,7 +31,6 @@ import java.lang.reflect.*; import java.util.*; 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.lang.*; @@ -46,8 +45,9 @@ import org.apache.juneau.commons.bean.*; * * <h5 class='topic'>Description</h5> * - * Uses introspection to find all the properties associated with this class. If the {@link Marshalled @Marshalled} annotation - * is present on the class, then that information is used to determine the properties on the class. + * Uses introspection to find all the properties associated with this class. If the + * {@link org.apache.juneau.annotation.Marshalled @Marshalled} annotation is present on the class, then that information is used to + * determine the properties on the class. * Otherwise, the {@code BeanInfo} functionality in Java is used to determine the properties on the class. * * <h5 class='topic'>Bean property ordering</h5> @@ -55,10 +55,11 @@ import org.apache.juneau.commons.bean.*; * The order of the properties are as follows: * <ul class='spaced-list'> * <li> - * If {@link Bean @Marshalled} annotation is specified on class, then the order is the same as the list of properties - * in the annotation. + * If {@link org.apache.juneau.annotation.Marshalled @Marshalled} annotation is specified on class, then the order is the same + * as the list of properties in the annotation. * <li> - * If {@link Bean @Marshalled} annotation is not specified on the class, then the order is based on the following. + * If {@link org.apache.juneau.annotation.Marshalled @Marshalled} annotation is not specified on the class, then the order is + * based on the following. * <ul> * <li>Public fields (same order as {@code Class.getFields()}). * <li>Properties returned by {@code BeanInfo.getPropertyDescriptors()}. @@ -218,18 +219,19 @@ public class BeanMeta<T> { try { var bc = cm.getMarshallingContext(); var ap = bc.getAnnotationProvider(); + var cfg = bc.getBeanConfigContext(); // Sanity checks first. if (bc.isNotABean(cm)) return notABean("Class matches exclude-class list"); - if (bc.isBeansRequireSerializable() && ! cm.isAssignableTo(Serializable.class) && ! ap.has(Marshalled.class, cm) && ! ap.has(BeanType.class, cm)) + if (bc.isBeansRequireSerializable() && ! cm.isAssignableTo(Serializable.class) && ! MarshalledBeanMetaInitializer.hasBeanRegistrationAnnotation(cfg, cm)) return notABean("Class is not serializable"); if (ap.has(BeanIgnore.class, cm)) return notABean("Class is annotated with @BeanIgnore"); - if ((! bc.getBeanClassVisibility().isVisible(cm.getModifiers()) || cm.isAnonymousClass()) && ! ap.has(Marshalled.class, cm) && ! ap.has(BeanType.class, cm)) + if ((! bc.getBeanClassVisibility().isVisible(cm.getModifiers()) || cm.isAnonymousClass()) && ! MarshalledBeanMetaInitializer.hasBeanRegistrationAnnotation(cfg, cm)) return notABean("Class is not public"); var bm = new BeanMeta<>(cm, MarshalledBeanMetaInitializer.findMarshalledFilter(cm), null, implClass); @@ -450,11 +452,10 @@ public class BeanMeta<T> { var dynaPropertyValue = Value.<BeanPropertyMeta>empty(); var propertyBeanRegistriesTemp = CollectionUtils.<BeanPropertyMeta,BeanRegistryLookup>map(); // Per-property BeanRegistry side-map (TODO-5 Step 5). var unsortedPropertiesTemp = false; - var ba = ap.find(Marshalled.class, classInfo); var btList = ap.find(org.apache.juneau.commons.bean.BeanType.class, classInfo); var propertyNamer = opt(bf).map(x -> x.getPropertyNamer()).orElse(config.getPropertyNamer()); - this.typePropertyName = ba.stream().map(x -> x.inner().typePropertyName()).filter(Utils::ne).findFirst().orElseGet(config::getBeanTypePropertyName); + this.typePropertyName = MarshalledBeanMetaInitializer.resolveTypePropertyName(config, classInfo); // Check if constructor is required but not found (records are exempt since they use canonical constructors) if (! beanConstructor.constructor().isPresent() && bf == null && config.isBeansRequireDefaultConstructor() && ! ci.isRecord()) @@ -696,7 +697,7 @@ public class BeanMeta<T> { * property inclusion/exclusion, property ordering, and type name mapping. * * <p> - * The bean filter is typically created from the {@link Bean @Marshalled} annotation on the class. If no {@link Bean @Marshalled} + * The bean filter is typically created from the {@link org.apache.juneau.annotation.Marshalled @Marshalled} annotation on the class. If no {@link org.apache.juneau.annotation.Marshalled @Marshalled} * annotation is present, this method returns <jk>null</jk>. * * @return The bean filter for this bean, or <jk>null</jk> if no bean filter is associated with this bean. @@ -722,7 +723,7 @@ public class BeanMeta<T> { * * <p> * The bean registry is used to resolve dictionary names to class types. It's created when a bean class has a - * {@link Bean#dictionary() @Marshalled(dictionary)} annotation that specifies a list of possible subclasses. + * {@link org.apache.juneau.annotation.Marshalled#dictionary() @Marshalled(dictionary)} annotation that specifies a list of possible subclasses. * * <p> * Returns the bean-modeling-side SPI type ({@link BeanRegistryLookup}). Marshalling-side callers that need @@ -800,7 +801,7 @@ public class BeanMeta<T> { public BeanConfigContext getConfig() { return config; } /** - * Returns the dictionary name for this bean as defined through the {@link Bean#typeName() @Marshalled(typeName)} annotation. + * Returns the dictionary name for this bean as defined through the {@link org.apache.juneau.annotation.Marshalled#typeName() @Marshalled(typeName)} annotation. * * @return The dictionary name for this bean, or <jk>null</jk> if it has no dictionary name defined. */ @@ -861,7 +862,7 @@ public class BeanMeta<T> { * <p> * The value is determined from: * <ul> - * <li>The {@link Bean#typePropertyName() @Marshalled(typePropertyName)} annotation on the class, if present. + * <li>The {@link org.apache.juneau.annotation.Marshalled#typePropertyName() @Marshalled(typePropertyName)} annotation on the class, if present. * <li>Otherwise, the default value from {@link MarshallingContext#getBeanTypePropertyName()}. * </ul> * @@ -1116,9 +1117,9 @@ public class BeanMeta<T> { * <li><b>Implementation class constructor:</b> If an {@link #implClassConstructor} was provided during bean * metadata creation, it is used with an empty property list. * <li><b>No-arg constructor:</b> Searches for a no-argument constructor. The visibility required depends on - * whether the class has a {@link Bean @Marshalled} annotation: + * whether the class has a {@link org.apache.juneau.annotation.Marshalled @Marshalled} annotation: * <ul> - * <li>If {@link Bean @Marshalled} is present, private constructors are allowed + * <li>If {@link org.apache.juneau.annotation.Marshalled @Marshalled} is present, private constructors are allowed * <li>Otherwise, the visibility is determined by {@link MarshallingContext#getBeanConstructorVisibility()} * </ul> * <li><b>No constructor:</b> Returns an empty {@link Optional} if no suitable constructor is found. @@ -1175,9 +1176,7 @@ public class BeanMeta<T> { if (implClassConstructor != null) return new BeanConstructor(opt(implClassConstructor.accessible()), liste()); - var ba = ap.find(Marshalled.class, classInfo); - var btList = ap.find(org.apache.juneau.commons.bean.BeanType.class, classInfo); - var con = ci.getNoArgConstructor((! ba.isEmpty() || ! btList.isEmpty()) ? Visibility.PRIVATE : vis).orElse(null); + var con = ci.getNoArgConstructor(MarshalledBeanMetaInitializer.hasBeanRegistrationAnnotation(config, classInfo) ? Visibility.PRIVATE : vis).orElse(null); if (con != null) return new BeanConstructor(opt(con.accessible()), liste()); @@ -1416,8 +1415,8 @@ public class BeanMeta<T> { * <ul> * <li><b>Bean filter dictionary:</b> Classes specified in the {@link MarshalledFilter#getBeanDictionary() bean filter's dictionary} * (if a bean filter is present) - * <li><b>{@link Marshalled @Marshalled} annotation:</b> If the class has a {@link Marshalled @Marshalled} annotation with a non-empty - * {@link Marshalled#typeName() typeName()}, the class itself is added to the dictionary + * <li><b>{@link org.apache.juneau.annotation.Marshalled @Marshalled} annotation:</b> If the class has a {@link org.apache.juneau.annotation.Marshalled @Marshalled} annotation with a non-empty + * {@link org.apache.juneau.annotation.Marshalled#typeName() typeName()}, the class itself is added to the dictionary * </ul> * * <p> @@ -1512,8 +1511,8 @@ public class BeanMeta<T> { * <li><b>Parent class registry lookup:</b> Searches through parent classes and interfaces (starting from the * second one, skipping the class itself) and checks if any of their bean registries contain a type name * for this class. - * <li><b>{@link Marshalled @Marshalled} annotation:</b> If the class has a {@link Marshalled @Marshalled} annotation with a non-empty - * {@link Bean#typeName() typeName()}, that value is used. + * <li><b>{@link org.apache.juneau.annotation.Marshalled @Marshalled} annotation:</b> If the class has a {@link org.apache.juneau.annotation.Marshalled @Marshalled} annotation with a non-empty + * {@link org.apache.juneau.annotation.Marshalled#typeName() typeName()}, that value is used. * <li><b>No dictionary name:</b> Returns <jk>null</jk> if no dictionary name is found. * </ol> * 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 b2dda12be2..824db3d978 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 @@ -32,16 +32,12 @@ import java.util.*; import java.util.function.*; import java.util.stream.*; -import org.apache.juneau.annotation.*; import org.apache.juneau.commons.bean.*; import org.apache.juneau.commons.collections.*; import org.apache.juneau.commons.lang.*; import org.apache.juneau.commons.reflect.*; import org.apache.juneau.commons.reflect.ReflectionUtils; import org.apache.juneau.commons.inject.*; -import org.apache.juneau.parser.*; -import org.apache.juneau.serializer.*; -import org.apache.juneau.swap.*; /** * Contains metadata about a bean property. @@ -90,16 +86,16 @@ public class BeanPropertyMeta implements Comparable<BeanPropertyMeta> { MethodInfo getter; // Package-private for BeanMeta access MethodInfo setter; // Package-private for BeanMeta access MethodInfo extraKeys; // Package-private for BeanMeta access - BeanTypeInfo<?> rawTypeMeta; // Package-private for BeanMeta access (used to install swap-aware transforms). Null on commons-side path (no type resolution). Concrete instances are always {@link ClassMeta} since it's the only in-tree implementation; the field is typed against the bean-modeling SPI seam so the field can live in commons.bean. + BeanTypeInfo<?> rawTypeMeta; // Package-private for BeanMeta access (used to install swap-aware transforms). Null on commons-side path (no type resolution). Concrete instances are always {@link org.apache.juneau.ClassMeta} since it's the only in-tree implementation; the field is typed against the bean-modeling SPI seam so the field can live in commons.bean. Object swap; // Object-typed so the field can live in commons.bean; cast to ObjectSwap by marshalling-side consumers. Set only via MarshalledPropertyPostProcessor (marshalling-side post-processor). - BiFunction<BeanSession,Object,Object> readTransform; // Package-private; defaults to identity if null. Typed against the commons.bean SPI seam; marshalling-side installers cast the session argument back to {@link MarshallingSession} where needed (see {@link MarshalledPropertyPostProcessor#installSwapAwareTransforms}). + BiFunction<BeanSession,Object,Object> readTransform; // Package-private; defaults to identity if null. Typed against the commons.bean SPI seam; marshalling-side installers cast the session argument back to {@link org.apache.juneau.MarshallingSession} where needed (see {@link org.apache.juneau.MarshalledPropertyPostProcessor#installSwapAwareTransforms}). BiFunction<BeanSession,Object,Object> writeTransform; // Package-private; defaults to identity if null. Typed against the commons.bean SPI seam (see readTransform note). List<ClassInfo> dictionaryClasses; // Package-private for BeanMeta access; @MarshalledProp(dictionary={}) classes scanned during validate(). private boolean isConstructorArg; boolean isUri; // Package-private so MarshalledPropertyPostProcessor can set @Uri-derived flag. Mirrors rawTypeMeta.isUri() plus @Uri annotation reads on field/getter/setter. private boolean isDyna; private boolean isDynaGetterMap; - BeanTypeInfo<?> typeMeta; // Package-private so the marshalling-side post-processor can override after @Swap/@MarshalledProp detection. Concrete instances are always {@link ClassMeta}; typed against the bean-modeling SPI seam. + BeanTypeInfo<?> typeMeta; // Package-private so the marshalling-side post-processor can override after @Swap/@MarshalledProp detection. Concrete instances are always {@link org.apache.juneau.ClassMeta}; typed against the bean-modeling SPI seam. private Object overrideValue; private BeanPropertyMeta delegateFor; private boolean canRead; @@ -140,9 +136,9 @@ public class BeanPropertyMeta implements Comparable<BeanPropertyMeta> { * caller. Defaults to identity (raw value passes through unchanged). * * <p> - * Used by the marshalling layer to install {@link ObjectSwap}-aware behavior at bean-meta construction time; + * Used by the marshalling layer to install {@link org.apache.juneau.swap.ObjectSwap}-aware behavior at bean-meta construction time; * the bean-modeling layer itself only invokes the function and does not directly reference - * {@link ObjectSwap}. + * {@link org.apache.juneau.swap.ObjectSwap}. * * @param value The transform function. Must not be <jk>null</jk>. * @return This object. @@ -160,9 +156,9 @@ public class BeanPropertyMeta implements Comparable<BeanPropertyMeta> { * invoked. Defaults to identity (raw value passes through unchanged). * * <p> - * Used by the marshalling layer to install {@link ObjectSwap}-aware behavior at bean-meta construction time; + * Used by the marshalling layer to install {@link org.apache.juneau.swap.ObjectSwap}-aware behavior at bean-meta construction time; * the bean-modeling layer itself only invokes the function and does not directly reference - * {@link ObjectSwap}. + * {@link org.apache.juneau.swap.ObjectSwap}. * * @param value The transform function. Must not be <jk>null</jk>. * @return This object. @@ -189,7 +185,7 @@ public class BeanPropertyMeta implements Comparable<BeanPropertyMeta> { * @param value The raw metadata type for this bean property. * @return This object. */ - public Builder rawMetaType(ClassMeta<?> value) { + public Builder rawMetaType(BeanTypeInfo<?> value) { rawTypeMeta = assertArgNotNull(ARG_value, value); typeMeta = rawTypeMeta; return this; @@ -315,14 +311,14 @@ public class BeanPropertyMeta implements Comparable<BeanPropertyMeta> { * * <p> * After validation succeeds, marshalling-side callers (currently {@link BeanMeta}) read the - * {@link #dictionaryClasses} field to construct the property-level {@link BeanRegistry} and store it in a + * {@link #dictionaryClasses} field to construct the property-level {@link org.apache.juneau.BeanRegistry} and store it in a * side-map keyed by the built {@link BeanPropertyMeta}. The bean-modeling layer itself no longer carries a - * {@link BeanRegistry} reference. + * {@link org.apache.juneau.BeanRegistry} reference. * * <p> * When {@code bc} is <jk>null</jk> (commons-side path), this method runs in raw-reflection mode: * annotation reads are routed through {@link BeanConfigContext#getAnnotationProvider()} but no - * {@link ClassMeta} resolution or {@link ObjectSwap} discovery is performed; the property's + * {@link org.apache.juneau.ClassMeta} resolution or {@link org.apache.juneau.swap.ObjectSwap} discovery is performed; the property's * {@code rawTypeMeta}/{@code typeMeta} stay <jk>null</jk> and the resulting {@link BeanPropertyMeta} * exposes raw getter/setter invocation only. * @@ -357,7 +353,7 @@ public class BeanPropertyMeta implements Comparable<BeanPropertyMeta> { var si = setter; // @MarshalledProp / @Swap annotation reads have been lifted out to the marshalling-side post-processor - // (see {@link MarshalledPropertyPostProcessor#process}). They are processed by {@link BeanMeta} + // (see {@link org.apache.juneau.MarshalledPropertyPostProcessor#process}). They are processed by {@link BeanMeta} // after this method returns. The post-processor mutates {@link #swap}, {@link #properties}, // {@link #dictionaryClasses}, and {@link #typeMeta} (when a swap is detected) on this builder. dictionaryClasses = liste(); @@ -513,12 +509,12 @@ public class BeanPropertyMeta implements Comparable<BeanPropertyMeta> { private final boolean isUri; // True if this is a URL/URI or annotated with @URI. private final String name; // The name of the property. private final Object overrideValue; // The bean property value (if it's an overridden delegate). - private final BeanTypeInfo<?> rawTypeMeta; // The real class type of the bean property. Concrete instances are always {@link ClassMeta}; typed against the bean-modeling SPI seam for the eventual move to commons.bean. + private final BeanTypeInfo<?> rawTypeMeta; // The real class type of the bean property. Concrete instances are always {@link org.apache.juneau.ClassMeta}; typed against the bean-modeling SPI seam for the eventual move to commons.bean. private final BiFunction<BeanSession,Object,Object> readTransform; // Applied to raw getter result; identity by default. Typed against the commons.bean SPI seam. private final boolean readOnly; // True if this property is read-only. private final MethodInfo setter; // The bean property setter. private final Object swap; // ObjectSwap, but Object-typed so the field can live in commons.bean; cast at marshalling-side use sites. Defined only via @MarshalledProp(format=...) or @Swap. - private final BeanTypeInfo<?> typeMeta; // The transformed class type of the bean property. Concrete instances are always {@link ClassMeta}; typed against the bean-modeling SPI seam. + private final BeanTypeInfo<?> typeMeta; // The transformed class type of the bean property. Concrete instances are always {@link org.apache.juneau.ClassMeta}; typed against the bean-modeling SPI seam. private final BiFunction<BeanSession,Object,Object> writeTransform; // Applied to incoming value before raw setter; identity by default. Typed against the commons.bean SPI seam. private final boolean writeOnly; // True if this property is write-only. @@ -567,7 +563,7 @@ public class BeanPropertyMeta implements Comparable<BeanPropertyMeta> { * <p> * <b>Marshalling-only path.</b> Requires a property built via the marshalling-side construction path * (i.e. with a non-null {@link #getClassMeta() rawTypeMeta} and a non-null backing - * {@link MarshallingSession} on the supplied {@link BeanMap}). When the owning {@link BeanMeta} was built via + * {@link org.apache.juneau.MarshallingSession} on the supplied {@link BeanMap}). When the owning {@link BeanMeta} was built via * {@link BeanMeta#of(Class, BeanConfigContext)}, this method throws * {@link UnsupportedOperationException} because adding into a Collection/array property requires * type-aware element conversion (the marshalling session's {@code convertToType}) that is not available in the @@ -598,7 +594,7 @@ public class BeanPropertyMeta implements Comparable<BeanPropertyMeta> { return; } - var session = m.getMarshallingSession(); + var session = m.getBeanSession(); var isCollection = rawTypeMeta.isCollection(); var isArray = rawTypeMeta.isArray(); @@ -669,7 +665,7 @@ public class BeanPropertyMeta implements Comparable<BeanPropertyMeta> { * <p> * <b>Marshalling-only path.</b> Requires a property built via the marshalling-side construction path * (i.e. with a non-null {@link #getClassMeta() rawTypeMeta} and a non-null backing - * {@link MarshallingSession} on the supplied {@link BeanMap}). When the owning {@link BeanMeta} was built via + * {@link org.apache.juneau.MarshallingSession} on the supplied {@link BeanMap}). When the owning {@link BeanMeta} was built via * {@link BeanMeta#of(Class, BeanConfigContext)}, this method throws * {@link UnsupportedOperationException} because adding into a Map/bean property requires type-aware * value conversion (the marshalling session's {@code convertToType} / {@code toBeanMap}) that is not available @@ -701,7 +697,7 @@ public class BeanPropertyMeta implements Comparable<BeanPropertyMeta> { return; } - var session = m.getMarshallingSession(); + var session = m.getBeanSession(); var isMap = rawTypeMeta.isMap(); var isBean = rawTypeMeta.isBean(); @@ -736,13 +732,13 @@ public class BeanPropertyMeta implements Comparable<BeanPropertyMeta> { var b = invokeGetter(bean, pName); if (nn(b)) { - session.toBeanMap(b).put(key, v); + ((Map) session.toBeanMap(b)).put(key, v); return; } if (rawTypeMeta.canCreateNewInstance(m.getBean(false))) { b = rawTypeMeta.newInstance(); - session.toBeanMap(b).put(key, v); + ((Map) session.toBeanMap(b)).put(key, v); } invokeSetter(bean, pName, b); @@ -872,12 +868,12 @@ public class BeanPropertyMeta implements Comparable<BeanPropertyMeta> { * <p> * The order of lookup for the dictionary is as follows: * <ol> - * <li>Dictionary defined via {@link MarshalledProp#dictionary() @MarshalledProp(dictionary)}. - * <li>Dictionary defined via {@link MarshallingContext.Builder#beanDictionary(Class...)}. + * <li>Dictionary defined via {@link org.apache.juneau.annotation.MarshalledProp#dictionary() @MarshalledProp(dictionary)}. + * <li>Dictionary defined via {@link org.apache.juneau.MarshallingContext.Builder#beanDictionary(Class...)}. * </ol> * * <p> - * The per-property {@link BeanRegistry} no longer lives on this object; it is stored in a marshalling-side + * The per-property {@link org.apache.juneau.BeanRegistry} no longer lives on this object; it is stored in a marshalling-side * side-map on {@link BeanMeta} keyed by {@link BeanPropertyMeta}. This method delegates to * {@link BeanMeta#getPropertyBeanRegistry(BeanPropertyMeta)} for backwards compatibility with existing call sites * in the marshalling layer (parser/serializer sessions, XML content-property handling, etc.). @@ -890,14 +886,14 @@ public class BeanPropertyMeta implements Comparable<BeanPropertyMeta> { * Returns the {@link BeanTypeInfo} of the class of this property. * * <p> - * If this property or the property type class has a {@link ObjectSwap} associated with it, this method returns the + * If this property or the property type class has a {@link org.apache.juneau.swap.ObjectSwap} associated with it, this method returns the * transformed class meta. * This matches the class type that is used by the {@link #get(BeanMap,String)} and * {@link #set(BeanMap,String,Object)} methods. * * <p> * Returns the bean-modeling-side SPI type ({@link BeanTypeInfo}). Marshalling-side callers that need the - * {@link ClassMeta} narrowing must cast — the concrete instance in-tree is always a {@link ClassMeta}. + * {@link org.apache.juneau.ClassMeta} narrowing must cast — the concrete instance in-tree is always a {@link org.apache.juneau.ClassMeta}. * * @return The {@link BeanTypeInfo} of the class of this property, or <jk>null</jk> if this property was built via * the bean-modeling-only path. @@ -1068,7 +1064,7 @@ public class BeanPropertyMeta implements Comparable<BeanPropertyMeta> { if (readOnly) return null; - var session = m.getMarshallingSession(); + var session = m.getBeanSession(); // Apply the install-time write transform (identity by default; swap-aware in the marshalling layer). value1 = writeTransform.apply(session, value1); @@ -1104,7 +1100,11 @@ public class BeanPropertyMeta implements Comparable<BeanPropertyMeta> { var bean = m.getBean(true); // Don't use getBean() because it triggers array creation! return setPropertyValue(m, pName, value1, bean, isMap, isCollection, session); - } catch (ParseException e2) { + } catch (org.apache.juneau.commons.BasicRuntimeException e2) { + // Preserve previous behavior: marshalling-side BasicRuntimeException (notably ParseException raised by + // session.parseToMap/parseToList or writeTransform) gets wrapped in BeanRuntimeException so callers can + // uniformly catch BeanRuntimeException. BeanRuntimeException itself does not extend BasicRuntimeException + // so it propagates unchanged. throw bex(e2); } } @@ -1113,7 +1113,7 @@ public class BeanPropertyMeta implements Comparable<BeanPropertyMeta> { "java:S3776", // Cognitive complexity acceptable for complex property setter "java:S6541" // Brain method acceptable - complex property value setting logic requires high LOC/complexity }) - private Object setPropertyValue(BeanMap<?> m, String pName, Object value1, Object bean, boolean isMap, boolean isCollection, MarshallingSession session) { + private Object setPropertyValue(BeanMap<?> m, String pName, Object value1, Object bean, boolean isMap, boolean isCollection, BeanSession session) { try { var r = (config.isBeanMapPutReturnsOldValue() || isMap || isCollection) && (nn(getter) || nn(field)) ? get(m, pName) : null; var propertyClass = rawTypeMeta.inner(); @@ -1243,17 +1243,7 @@ public class BeanPropertyMeta implements Comparable<BeanPropertyMeta> { }); } else { - if (nn(swap) && value1 != null && ((ObjectSwap)swap).getSwapClass().isAssignableFrom(value1.getClass())) { - // Defensive double-unswap path: value1 is still in swapped form (the outer writeTransform - // did not normalize it for some reason). Route through the install-time write transform so - // BeanPropertyMeta itself does not invoke ObjectSwap directly. Note: cast lives here because - // the field is Object-typed for the eventual move to commons.bean; this entire branch is - // expected to migrate to a marshalling-side post-processor in Phase C. - value1 = writeTransform.apply(session, value1); - } else { - // Pass bean as outer for non-static inner class instantiation (e.g. J2 with string constructor) - value1 = session.convertToMemberType(bean, value1, rawTypeMeta); - } + value1 = session.convertToMemberType(bean, value1, rawTypeMeta); invokeSetter(bean, pName, value1); } @@ -1301,7 +1291,7 @@ public class BeanPropertyMeta implements Comparable<BeanPropertyMeta> { if (bean == null) return m.propertyCache.get(name); - var session = m.getMarshallingSession(); + var session = m.getBeanSession(); var o = getRaw(m, pName); return readTransform.apply(session, o); diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/MarshalledBeanMetaInitializer.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/MarshalledBeanMetaInitializer.java index 3b0c49c0a1..d9aa6cdbe1 100644 --- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/MarshalledBeanMetaInitializer.java +++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/MarshalledBeanMetaInitializer.java @@ -164,20 +164,23 @@ final class MarshalledBeanMetaInitializer { } /** - * Looks up the {@link Marshalled#typePropertyName() @Marshalled(typePropertyName)} value for a bean class. + * Resolves the {@link Marshalled#typePropertyName() @Marshalled(typePropertyName)} value for a bean class, falling + * back to {@link BeanConfigContext#getBeanTypePropertyName()} when no annotation supplies one. * * <p> - * Returns the configured value, or an empty string if no {@link Marshalled @Marshalled} annotation specifies one. - * The caller (typically {@link BeanMeta}'s constructor) falls back to a config-supplied default when this method - * returns an empty string. + * Encapsulates the {@link Marshalled @Marshalled} annotation read previously performed inline by + * {@link BeanMeta}'s constructor, so {@link BeanMeta} itself no longer references {@link Marshalled}. * - * @param config The bean-modeling configuration (used to access the annotation provider). + * @param config The bean-modeling configuration (used to access the annotation provider and the fallback default). * @param classInfo The bean's class info. - * @return The configured type property name, or empty if not set. + * @return The resolved type property name. Never <jk>null</jk>. */ - static String findTypePropertyName(BeanConfigContext config, ClassInfo classInfo) { - var ba = config.getAnnotationProvider().find(Marshalled.class, classInfo); - return ba.stream().map(x -> x.inner().typePropertyName()).filter(Utils::ne).findFirst().orElse(""); + static String resolveTypePropertyName(BeanConfigContext config, ClassInfo classInfo) { + return config.getAnnotationProvider().find(Marshalled.class, classInfo).stream() + .map(x -> x.inner().typePropertyName()) + .filter(Utils::ne) + .findFirst() + .orElseGet(config::getBeanTypePropertyName); } /** diff --git a/juneau-utest/src/test/java/org/apache/juneau/commons/reflect/ParameterInfo_Test.java b/juneau-utest/src/test/java/org/apache/juneau/commons/reflect/ParameterInfo_Test.java index 2ed377c07c..bd273f7365 100644 --- a/juneau-utest/src/test/java/org/apache/juneau/commons/reflect/ParameterInfo_Test.java +++ b/juneau-utest/src/test/java/org/apache/juneau/commons/reflect/ParameterInfo_Test.java @@ -29,7 +29,7 @@ import java.util.function.*; import java.util.stream.*; import org.apache.juneau.*; -import org.apache.juneau.annotation.Name; +import org.apache.juneau.commons.bean.Name; import org.junit.jupiter.api.*; @SuppressWarnings({ @@ -201,9 +201,9 @@ class ParameterInfo_Test extends TestBase { dc_a1 = dc.getMethod(x -> x.hasName("a1")).get().getParameter(0); static class E { - public void a1(int a, @org.apache.juneau.annotation.Name("b") int b) {} + public void a1(int a, @org.apache.juneau.commons.bean.Name("b") int b) {} // Parameter with both @Name and another annotation to test line 622 both branches - public void test(@CA("test") @org.apache.juneau.annotation.Name("paramName") String param) {} + public void test(@CA("test") @org.apache.juneau.commons.bean.Name("paramName") String param) {} } // Test classes for getResolvedQualifier() - line 643 @@ -281,15 +281,15 @@ class ParameterInfo_Test extends TestBase { // Test class for toString() comprehensive tests public static class ToStringTestClass { public void basicMethod(int a, String b) {} - public void namedMethod(@org.apache.juneau.annotation.Name("x") int x, @org.apache.juneau.annotation.Name("y") String y) {} + public void namedMethod(@org.apache.juneau.commons.bean.Name("x") int x, @org.apache.juneau.commons.bean.Name("y") String y) {} public void finalMethod(final int value) {} - public void genericMethod(@org.apache.juneau.annotation.Name("list") java.util.List<String> list, @org.apache.juneau.annotation.Name("map") java.util.Map<String, Integer> map) {} - public void varargsMethod(@org.apache.juneau.annotation.Name("values") String... values) {} - public void finalVarargsMethod(final @org.apache.juneau.annotation.Name("args") String... args) {} - public void arrayMethod(@org.apache.juneau.annotation.Name("numbers") int[] numbers, @org.apache.juneau.annotation.Name("matrix") String[][] matrix) {} - public void genericArrayMethod(@org.apache.juneau.annotation.Name("lists") java.util.List<String>[] lists) {} - public void primitiveMethod(@org.apache.juneau.annotation.Name("flag") boolean flag, @org.apache.juneau.annotation.Name("value") double value, @org.apache.juneau.annotation.Name("count") long count) {} - public ToStringTestClass(@org.apache.juneau.annotation.Name("id") int id, @org.apache.juneau.annotation.Name("name") String name) {} + public void genericMethod(@org.apache.juneau.commons.bean.Name("list") java.util.List<String> list, @org.apache.juneau.commons.bean.Name("map") java.util.Map<String, Integer> map) {} + public void varargsMethod(@org.apache.juneau.commons.bean.Name("values") String... values) {} + public void finalVarargsMethod(final @org.apache.juneau.commons.bean.Name("args") String... args) {} + public void arrayMethod(@org.apache.juneau.commons.bean.Name("numbers") int[] numbers, @org.apache.juneau.commons.bean.Name("matrix") String[][] matrix) {} + public void genericArrayMethod(@org.apache.juneau.commons.bean.Name("lists") java.util.List<String>[] lists) {} + public void primitiveMethod(@org.apache.juneau.commons.bean.Name("flag") boolean flag, @org.apache.juneau.commons.bean.Name("value") double value, @org.apache.juneau.commons.bean.Name("count") long count) {} + public ToStringTestClass(@org.apache.juneau.commons.bean.Name("id") int id, @org.apache.juneau.commons.bean.Name("name") String name) {} public void unnamedMethod(int param1, String param2) {} } diff --git a/todo/TODO-5-bean-runtime-types-to-commons.md b/todo/TODO-5-bean-runtime-types-to-commons.md index f7eec1ef29..7cab853f51 100644 --- a/todo/TODO-5-bean-runtime-types-to-commons.md +++ b/todo/TODO-5-bean-runtime-types-to-commons.md @@ -4,6 +4,69 @@ This is the remaining work from **Phase 5 of the bean-layer split**. Phase 5a (t --- +## Status (Phase C Task 5 Step F — import cleanup landed, uncommitted) + +**Step F audit follow-up — Tasks 1–8 LANDED in the working tree (uncommitted).** Build + full test green (`scripts/test.py --full`). The 7 bean-runtime files now import only JDK packages + `org.apache.juneau.commons.*` (plus `org.apache.juneau.BeanMeta.MethodType.*` static self-import on `BeanMeta`). + +### Tasks completed in this checkpoint + +- [x] **Task 1 — `@Marshalled` annotation reads lifted from `BeanMeta` to `MarshalledBeanMetaInitializer`.** Four call sites in `BeanMeta` (lines 226, 232, 453, 1178) now call `MarshalledBeanMetaInitializer.hasBeanRegistrationAnnotation(...)` or `MarshalledBeanMetaInitializer.resolveTypePropertyName(...)` instead of inlining the `ap.has(Marshalled.class, cm)` / `ap.find(Marshalled.class, classInfo).stream()...` reads. Javadoc references to `@Marshalled` in `BeanMeta` are now fully-qualif [...] + +- [x] **Task 2 — `@Name` annotation moved to `commons.bean`.** `git mv juneau-core/juneau-marshall/src/main/java/org/apache/juneau/annotation/Name.java juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/bean/Name.java`; package declaration updated; Javadoc references to `@Named` are now fully-qualified. The associated builder/processor (`NameAnnotation.java`) does not exist — `@Name` has no `*Annotation` companion. The lone direct import in `ParameterInfo_Test.java` was u [...] + +- [x] **Task 3 — `BeanPropertyMeta.setPropertyValue` parameter retyped to `BeanSession`.** Mechanical retype; `session.convertToType`, `session.convertToMemberType`, `session.parseToMap`, `session.parseToList` all exist on `BeanSession`. Caller in `set(...)` reads `m.getBeanSession()` (renamed in Task 5) and passes through. + +- [x] **Task 4 — Defensive `(ObjectSwap) swap` cast removed from `setPropertyValue`.** Picked **option (a)**: deleted the belt-and-braces double-unswap branch entirely. The `writeTransform` already runs the unswap path at the top of `set(...)` (line ~1074), so by the time control reaches the cast site `value1` is already in its unswapped form. The else-branch is now an unconditional `session.convertToMemberType(bean, value1, rawTypeMeta)` call followed by `invokeSetter`. No tests broke — [...] + +- [x] **Task 5 — `BeanMap.session` field retyped to `BeanSession`.** Field type changed from `MarshallingSession` to `BeanSession`. `setMarshallingSession(...)` parameter retyped to `BeanSession` (name preserved — `MarshallingSession implements BeanSession` so existing call sites `bm.setMarshallingSession(this)` in `MarshallingSession.java` and `DelegateBeanMap.java` are unchanged). Getter **renamed** to `getBeanSession()` returning `BeanSession`. The four call sites in `BeanPropertyMeta [...] + +- [x] **Task 6 — `FilteredKeyMap` usage in `BeanMap.getProperties(String...)` replaced with JDK construct.** Picked **option (b)**: the only production caller of `FilteredKeyMap` was `BeanMap.getProperties(String...)` passing `null` as the `classMeta` argument. Replaced with an inline `AbstractMap` over an `ArrayList<Map.Entry>` whose entries delegate `getValue()` / `setValue(...)` back to `this` (live view, identical semantics to `FilteredKeyMap`'s entry behavior). `FilteredKeyMap` itse [...] + +- [x] **Task 7 — `ParseException` / `SerializeException` catch in `BeanPropertyMeta.set(...)` retyped.** Picked **option (a)/(b) hybrid** — narrowed the catch from `ParseException` to `org.apache.juneau.commons.BasicRuntimeException`. Behavior preserved: `ParseException extends marshall.BasicRuntimeException extends commons.BasicRuntimeException`, so the previous wrapping behavior still fires for `ParseException` / `SerializeException` raised by `session.parseToMap` / `session.parseToLis [...] + +- [x] **Task 8 — Wildcard imports cleaned up in the 7 target files.** Per-file: + - `BeanMap.java`: dropped `import org.apache.juneau.annotation.*;`, `import org.apache.juneau.internal.*;`, `import org.apache.juneau.swap.*;`. Javadoc refs to `MarshallingContext` / `Marshalled` / `ObjectSwap` / `Swap` fully-qualified. + - `BeanMapEntry.java`: dropped `import org.apache.juneau.annotation.*;`, `import org.apache.juneau.swap.*;`. Javadoc refs to `ObjectSwap` / `Swap` fully-qualified. + - `BeanMeta.java`: dropped `import org.apache.juneau.annotation.*;`. `BeanIgnore` and `BeanCtor` resolve through `import org.apache.juneau.commons.bean.*;`. Javadoc refs to `Marshalled` / `MarshalledProp` / `Bean#typeName()` etc. fully-qualified. + - `BeanPropertyMeta.java`: dropped `import org.apache.juneau.annotation.*;`, `import org.apache.juneau.parser.*;`, `import org.apache.juneau.serializer.*;`, `import org.apache.juneau.swap.*;`. Javadoc refs to `MarshallingSession` / `ObjectSwap` / `MarshalledProp` / `MarshallingContext` / `ClassMeta` / `BeanRegistry` / `MarshalledPropertyPostProcessor` fully-qualified. `Builder.rawMetaType(ClassMeta<?>)` overload retyped to accept `BeanTypeInfo<?>` (the `ClassMeta` overload was unused i [...] + - `BeanPropertyValue.java`, `BeanPropertyConsumer.java`, `BeanProxyInvocationHandler.java`: already clean (no changes needed). + +### Per-file move-readiness summary + +After Tasks 1–8: + +- ✅ **`BeanMapEntry.java`** — fully move-ready. Imports only `java.util.*`. No code-level `juneau-marshall` references. +- ✅ **`BeanPropertyConsumer.java`** — fully move-ready. Imports only `org.apache.juneau.commons.function.*`. +- ✅ **`BeanProxyInvocationHandler.java`** — fully move-ready. Imports only JDK + `commons.*`. +- ⚠️ **`BeanMap.java`** — imports clean, but a few code-level move-blockers remain: + - `getMarshallingSession()` was renamed to `getBeanSession()` (returns `BeanSession`); the old name is gone. Callers updated. + - `Map<String,BeanPropertyValue>` references (lines 292+) — `BeanPropertyValue` itself migrates with the cluster, so no issue. +- ⚠️ **`BeanPropertyValue.java`** — imports clean, but `getClassMeta()` still returns `ClassMeta<?>` (line 78). External callers (`BsonSerializerSession`, `MsgPackSerializerSession`, `CborSerializerSession`, `BeanMap`) consume the return type as `ClassMeta<?>`. Retype to `BeanTypeInfo<?>` would require casts at each call site. **Move-blocker — needs a follow-up checkpoint.** +- ⚠️ **`BeanPropertyMeta.java`** — imports clean, but code-level references remain: + - `public BeanRegistry getBeanRegistry()` (line 883) returns marshalling-side `BeanRegistry`. Many callers (parser/serializer sessions). **Move-blocker — needs either `BeanRegistry` move to commons or wide return type.** + - `Builder.rawMetaType(BeanTypeInfo<?>)` (was `ClassMeta<?>`) — now commons-friendly. +- ⚠️ **`BeanMeta.java`** — imports clean, but several code-level move-blockers remain: + - `static <T> BeanMetaValue<T> create(ClassMeta<T> cm, ClassInfo implClass)` — `ClassMeta` parameter type. + - `getMarshallingContext()` — returns `MarshallingContext`. + - Many calls into `MarshalledBeanMetaInitializer.*` and `MarshalledPropertyPostProcessor.process(...)` — these helpers live in `org.apache.juneau` (marshalling-side). For the move, either: (a) move both helpers to commons (but they reference marshalling annotations/types internally), or (b) add SPI hooks on `BeanConfigContext` so the bean-side code can call into the marshalling helpers via the SPI seam. + +### Build / test status + +- `python3 scripts/test.py --build-only` — **GREEN**. +- `python3 scripts/test.py --full` — **GREEN**. + +### Remaining work before the physical `git mv` + +1. **`BeanPropertyValue.getClassMeta()` → `BeanTypeInfo<?>`** — retype, sweep ~5 call sites in serializer sessions to cast. +2. **`BeanPropertyMeta.getBeanRegistry()` → `Object` (or move `BeanRegistry` to commons)** — narrowing cast at call sites. +3. **`BeanMeta.create(ClassMeta<T>, ClassInfo)`** — accept `BeanTypeInfo<T>` instead; cast at call sites; or keep marshalling-side and add a parallel `BeanMeta.of(BeanTypeInfo<T>, ...)` factory. +4. **`BeanMeta.marshallingContext` field + `getMarshallingContext()` accessor** — field is already `Object`-typed; the accessor returns `MarshallingContext` via cast. For the move, expose only `Object` or a `BeanTypeResolver` accessor; marshalling-side callers cast. +5. **`MarshalledBeanMetaInitializer` / `MarshalledPropertyPostProcessor` SPI seams** — the cleanest path is to add hook methods on `BeanConfigContext` (e.g. `hasBeanRegistrationAnnotation(ClassInfo)`, `resolveTypePropertyName(ClassInfo)`, `findMarshalledTypeName(ClassInfo)`, `process(BeanPropertyMeta.Builder)`) so `BeanMeta` can call through the SPI without referencing the marshalling-side helpers directly. The marshalling-side `MarshallingContext` implementation delegates each hook to t [...] + +After items 1–5 land, the physical `git mv` should be a one-pass mechanical operation followed by a wide reference sweep. + +--- + ## Status (as of `@MarshalledProp(properties)` removal, uncommitted) **`@MarshalledProp(properties=...)` dropped per user direction (breaking change, v9.5).** With breaking changes authorized throughout TODO-5, the per-property child-property filter feature has been removed entirely. This shrinks the Phase C Task 5 surface meaningfully:
