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();
}
/**