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 de509a1aeb Utility class cleanup
de509a1aeb is described below

commit de509a1aeb7e720ef973914607df4f92d64de0e6
Author: James Bognar <[email protected]>
AuthorDate: Fri Oct 31 12:01:47 2025 -0400

    Utility class cleanup
---
 TODO-reflectionMigrationPlan.md                    | 232 +++++++++++++++++++++
 .../java/org/apache/juneau/reflect/ParamInfo.java  |  58 +++++-
 2 files changed, 280 insertions(+), 10 deletions(-)

diff --git a/TODO-reflectionMigrationPlan.md b/TODO-reflectionMigrationPlan.md
new file mode 100644
index 0000000000..76de713a78
--- /dev/null
+++ b/TODO-reflectionMigrationPlan.md
@@ -0,0 +1,232 @@
+# Reflection Classes Migration Plan
+
+## Goal
+Move the following classes from `org.apache.juneau.reflect` (juneau-marshall) 
to `org.apache.juneau.common.reflect` (juneau-common):
+- `ClassInfo`
+- `ConstructorInfo`
+- `ExecutableInfo`
+- `FieldInfo`
+- `MethodInfo`
+- `ParamInfo`
+
+## Current Location
+All six classes are currently in:
+- **Package**: `org.apache.juneau.reflect`
+- **Module**: `juneau-core/juneau-marshall`
+- **Path**: 
`juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/`
+
+## Target Location
+- **Package**: `org.apache.juneau.common.reflect`
+- **Module**: `juneau-core/juneau-common`
+- **Path**: 
`juneau-core/juneau-common/src/main/java/org/apache/juneau/common/reflect/`
+
+## Dependency Analysis
+
+### 1. ClassInfo.java
+**Status**: ✅ **READY TO MOVE**
+
+**Current Imports from juneau-marshall**: None
+
+**Dependencies**:
+- ✅ `org.apache.juneau.common.collections.*` - Already in juneau-common
+- ✅ `org.apache.juneau.common.reflect.*` - Already in juneau-common
+- ✅ `org.apache.juneau.common.utils.*` - Already in juneau-common
+
+**Issues**: None
+
+---
+
+### 2. FieldInfo.java
+**Status**: ⚠️ **HAS UNUSED IMPORT**
+
+**Current Imports from juneau-marshall**:
+- `import org.apache.juneau.*;` (line 28)
+
+**Dependencies**:
+- ✅ `org.apache.juneau.common.collections.*` - Already in juneau-common
+- ✅ `org.apache.juneau.common.reflect.*` - Already in juneau-common
+
+**Issues**: 
+- The wildcard import `org.apache.juneau.*` appears to be unused (no 
references found to BeanContext, Context, etc.)
+
+**Resolution**:
+- Remove the unused `import org.apache.juneau.*;` statement
+
+---
+
+### 3. ParamInfo.java
+**Status**: ✅ **READY TO MOVE**
+
+**Current Imports from juneau-marshall**: None
+
+**Dependencies**:
+- ✅ `org.apache.juneau.common.collections.*` - Already in juneau-common
+- ✅ `org.apache.juneau.common.reflect.*` - Already in juneau-common
+
+**Issues**: None
+
+**Resolution Applied**: 
+- **Used reflection to work with any @Name annotation**
+- Removed compile-time dependency on `org.apache.juneau.annotation.Name`
+- `ParamInfo` now searches for any annotation with simple name "Name" using 
reflection
+- Calls the annotation's `value()` method dynamically to extract the parameter 
name
+- Works with `@Name` from any package without requiring a compile-time 
dependency
+- Maintains backward compatibility with existing `@Name` annotations
+- Implementation in `getNameFromAnnotation()` helper method
+
+---
+
+### 4. MethodInfo.java
+**Status**: ❌ **BLOCKED - Requires ClassUtils2.getMatchingArgs()**
+
+**Current Imports from juneau-marshall**:
+- `import org.apache.juneau.internal.*;` (line 31)
+
+**Dependencies**:
+- ✅ `org.apache.juneau.common.collections.*` - Already in juneau-common
+- ✅ `org.apache.juneau.common.reflect.*` - Already in juneau-common
+- ❌ **`ClassUtils2.getMatchingArgs()`** - Currently in 
`org.apache.juneau.internal.ClassUtils2` (juneau-marshall)
+
+**Usage of ClassUtils2**:
+- Line 667: `return m.invoke(pojo, 
ClassUtils2.getMatchingArgs(m.getParameterTypes(), args));`
+
+**Issues**:
+- `MethodInfo.invoke()` uses `ClassUtils2.getMatchingArgs()` to match varargs 
parameters
+- `ClassUtils2` is in juneau-marshall's internal package
+
+**Resolution Options**:
+1. **Move getMatchingArgs() to ClassUtils in juneau-common** (RECOMMENDED)
+   - Extract `ClassUtils2.getMatchingArgs()` method
+   - Move to `org.apache.juneau.common.utils.ClassUtils`
+   - Make it public API (it's a useful utility)
+   - Update call in `MethodInfo`
+
+2. **Inline the logic**
+   - Copy the parameter matching logic directly into `MethodInfo.invoke()`
+   - Removes dependency but duplicates code
+
+3. **Remove the feature**
+   - Make `MethodInfo.invoke()` not support parameter reordering
+   - Would be a breaking change
+
+---
+
+### 5. ConstructorInfo.java
+**Status**: ❌ **BLOCKED - Requires ClassUtils2.getMatchingArgs()**
+
+**Current Imports from juneau-marshall**:
+- `import org.apache.juneau.internal.*;` (line 28)
+
+**Dependencies**:
+- ✅ `org.apache.juneau.common.collections.*` - Already in juneau-common
+- ✅ `org.apache.juneau.common.reflect.*` - Already in juneau-common
+- ❌ **`ClassUtils2.getMatchingArgs()`** - Currently in 
`org.apache.juneau.internal.ClassUtils2` (juneau-marshall)
+
+**Usage of ClassUtils2**:
+- Line 249: `return invoke(ClassUtils2.getMatchingArgs(c.getParameterTypes(), 
args));`
+
+**Issues**: 
+- Same as MethodInfo - uses `ClassUtils2.getMatchingArgs()`
+
+**Resolution**:
+- Same as MethodInfo resolution
+
+---
+
+### 6. ExecutableInfo.java
+**Status**: ✅ **READY TO MOVE**
+
+**Current Imports from juneau-marshall**: None
+
+**Dependencies**:
+- ✅ `org.apache.juneau.common.reflect.*` - Already in juneau-common
+
+**Issues**: None
+
+---
+
+## Migration Plan
+
+### Phase 1: Prepare juneau-common
+1. **Add getMatchingArgs() to ClassUtils**
+   - Extract `ClassUtils2.getMatchingArgs()` logic
+   - Add as public method to `org.apache.juneau.common.utils.ClassUtils`
+   - Add comprehensive javadoc
+   - Add unit tests in juneau-common
+
+### Phase 2: Update reflection classes
+1. **Update imports in all 6 classes**
+   - Change package from `org.apache.juneau.reflect` to 
`org.apache.juneau.common.reflect`
+   - Update `FieldInfo`: Remove unused `import org.apache.juneau.*;`
+   - Update `MethodInfo`: Change `ClassUtils2.getMatchingArgs()` to 
`ClassUtils.getMatchingArgs()`
+   - Update `ConstructorInfo`: Change `ClassUtils2.getMatchingArgs()` to 
`ClassUtils.getMatchingArgs()`
+   - Note: `ParamInfo` already fixed to use reflection for @Name
+
+2. **Move all 6 files**
+   - Move from 
`juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/`
+   - To 
`juneau-core/juneau-common/src/main/java/org/apache/juneau/common/reflect/`
+
+### Phase 3: Create backward compatibility
+1. **Add deprecated aliases in juneau-marshall**
+   - Create `@Deprecated` classes in old package `org.apache.juneau.reflect`
+   - Each class extends/wraps the new location
+   - Point users to new location in deprecation message
+
+2. **Update juneau-marshall imports**
+   - Update all files in juneau-marshall that import these classes
+   - Change to use new package location
+
+### Phase 4: Testing & Documentation
+1. **Run all tests** to ensure nothing broke
+2. **Update documentation** to reference new package
+3. **Update MIGRATION.md** with notes about deprecated classes
+
+## Summary of Blockers
+
+### Must be resolved before migration:
+
+1. **ClassUtils2.getMatchingArgs()** (affects MethodInfo, ConstructorInfo)
+   - Current location: `org.apache.juneau.internal.ClassUtils2` 
(juneau-marshall)
+   - Needs to be: `org.apache.juneau.common.utils.ClassUtils` (juneau-common)
+   - Impact: Used for smart parameter matching in reflection invoke operations
+
+### Can be fixed during migration:
+
+2. **Unused import** (affects FieldInfo)
+   - `import org.apache.juneau.*;` appears to be unused
+   - Simply remove it
+
+### ✅ Already Resolved:
+
+3. **@Name annotation dependency** (was affecting ParamInfo) - **FIXED**
+   - Used reflection to work with any annotation named "Name"
+   - No longer requires compile-time dependency on specific annotation
+   - Works with `@Name` from any package
+
+## Recommended Approach
+
+**Option A: Complete Migration** (RECOMMENDED)
+- Resolve remaining blocker (getMatchingArgs)
+- Move getMatchingArgs() to ClassUtils
+- Then move all 6 classes together
+- Provides full reflection capability in juneau-common
+
+**Option B: Partial Migration**
+- Move ClassInfo, ExecutableInfo, FieldInfo, ParamInfo first (ready now)
+- Leave MethodInfo, ConstructorInfo until getMatchingArgs dependency resolved
+- Requires careful dependency management
+
+**Option C: Keep Current Structure**
+- Don't move anything
+- Keep all reflection in juneau-marshall
+- Simplest but doesn't achieve the stated goal
+
+## Next Steps
+
+1. **Review and approve** this plan
+2. **Decide on approach** (A, B, or C)
+3. **Implement Phase 1** (prepare juneau-common)
+4. **Implement Phase 2** (move classes)
+5. **Implement Phase 3** (backward compatibility)
+6. **Test and document**
+
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/ParamInfo.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/ParamInfo.java
index 7cbf536abf..80c9207399 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/ParamInfo.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/ParamInfo.java
@@ -26,7 +26,6 @@ import java.util.*;
 import java.util.concurrent.*;
 import java.util.function.*;
 
-import org.apache.juneau.annotation.*;
 import org.apache.juneau.common.collections.*;
 import org.apache.juneau.common.reflect.*;
 
@@ -213,20 +212,55 @@ public class ParamInfo {
         */
        public MethodInfo getMethod() { return eInfo.isConstructor() ? null : 
(MethodInfo)eInfo; }
 
+       /**
+        * Helper method to extract the name from any annotation with the 
simple name "Name".
+        *
+        * <p>
+        * This method uses reflection to find any annotation with the simple 
name "Name"
+        * and dynamically invokes its <c>value()</c> method to retrieve the 
parameter name.
+        * This allows it to work with any <c>@Name</c> annotation from any 
package without
+        * creating a compile-time dependency.
+        *
+        * @return The name from the annotation, or <jk>null</jk> if no 
compatible annotation is found.
+        */
+       private String getNameFromAnnotation() {
+               for (var annotation : p.getAnnotations()) {
+                       var annotationType = annotation.annotationType();
+                       if ("Name".equals(annotationType.getSimpleName())) {
+                               try {
+                                       var valueMethod = 
annotationType.getMethod("value");
+                                       if (valueMethod.getReturnType() == 
String.class) {
+                                               var value = 
valueMethod.invoke(annotation);
+                                               if (value instanceof String)
+                                                       return (String)value;
+                                       }
+                               } catch (Exception e) {
+                                       // Ignore - annotation doesn't have a 
compatible value() method
+                               }
+                       }
+               }
+               return null;
+       }
+
        /**
         * Returns the name of the parameter.
         *
         * <p>
-        * If the parameter's name is present, then this method returns the 
name provided by the class file.
-        * Otherwise, this method synthesizes a name of the form argN, where N 
is the index of the parameter in the descriptor of the method which declares 
the parameter.
+        * If the parameter has an annotation with the simple name "Name" and a 
"value()" method, 
+        * then this method returns the value from that annotation.
+        * Otherwise, if the parameter's name is present in the class file, 
then this method returns that name.
+        * Otherwise, this method returns <jk>null</jk>.
         *
-        * @return The name of the parameter.
+        * <p>
+        * This method works with any annotation named "Name" (from any 
package) that has a <c>String value()</c> method.
+        *
+        * @return The name of the parameter, or <jk>null</jk> if not available.
         * @see Parameter#getName()
         */
        public String getName() {
-               Name n = p.getAnnotation(Name.class);
-               if (nn(n))
-                       return n.value();
+               String name = getNameFromAnnotation();
+               if (name != null)
+                       return name;
                if (p.isNamePresent())
                        return p.getName();
                return null;
@@ -252,12 +286,16 @@ public class ParamInfo {
        }
 
        /**
-        * Returns <jk>true</jk> if the parameter has a name provided by the 
class file.
+        * Returns <jk>true</jk> if the parameter has a name.
+        *
+        * <p>
+        * This returns <jk>true</jk> if the parameter has an annotation with 
the simple name "Name", 
+        * or if the parameter's name is present in the class file.
         *
-        * @return <jk>true</jk> if the parameter has a name provided by the 
class file.
+        * @return <jk>true</jk> if the parameter has a name.
         */
        public boolean hasName() {
-               return p.isNamePresent() || p.isAnnotationPresent(Name.class);
+               return getNameFromAnnotation() != null || p.isNamePresent();
        }
 
        /**

Reply via email to