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 98f6327926 Unit tests
98f6327926 is described below
commit 98f63279263ca927cf1b43ca91451eaadf5748d6
Author: James Bognar <[email protected]>
AuthorDate: Wed Dec 3 11:11:39 2025 -0800
Unit tests
---
.../apache/juneau/commons/collections/Value.java | 25 +++-
.../apache/juneau/commons/reflect/ClassInfo.java | 31 +++++
.../apache/juneau/commons/utils/ClassUtils.java | 126 ---------------------
.../org/apache/juneau/httppart/HttpPartSchema.java | 2 +-
.../apache/juneau/rest/arg/ResponseCodeArg.java | 2 +-
.../juneau/commons/collections/Value_Test.java | 3 +-
.../juneau/commons/utils/ClassUtils_Test.java | 117 -------------------
7 files changed, 57 insertions(+), 249 deletions(-)
diff --git
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/collections/Value.java
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/collections/Value.java
index e06522b681..53e4523225 100644
---
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/collections/Value.java
+++
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/collections/Value.java
@@ -17,13 +17,14 @@
package org.apache.juneau.commons.collections;
import static org.apache.juneau.commons.utils.AssertionUtils.*;
-import static org.apache.juneau.commons.utils.ClassUtils.*;
import static org.apache.juneau.commons.utils.Utils.*;
import java.lang.reflect.*;
import java.util.*;
import java.util.function.*;
+import org.apache.juneau.commons.reflect.ClassInfo;
+
/**
* A generic mutable value wrapper.
*
@@ -149,6 +150,26 @@ public class Value<T> {
return new Value<>(object);
}
+ /**
+ * Returns the generic parameter type of the Value type.
+ *
+ * @param t The type to find the parameter type of.
+ * @return The parameter type of the value, or <jk>null</jk> if the
type is not a subclass of <c>Value</c>.
+ */
+ public static Type getParameterType(Type t) {
+ if (t instanceof ParameterizedType t2) {
+ if (t2.getRawType() == Value.class) {
+ var ta = t2.getActualTypeArguments();
+ if (ta.length > 0)
+ return ta[0];
+ }
+ } else if ((t instanceof Class<?> t3) &&
Value.class.isAssignableFrom(t3)) {
+ return ClassInfo.of(t3).getParameterType(0,
Value.class);
+ }
+
+ return null;
+ }
+
/**
* Returns the unwrapped type.
*
@@ -156,7 +177,7 @@ public class Value<T> {
* @return The unwrapped type, or the same type if the type isn't
{@link Value}.
*/
public static Type unwrap(Type t) {
- var x = getValueParameterType(t);
+ var x = getParameterType(t);
return nn(x) ? x : t;
}
diff --git
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/reflect/ClassInfo.java
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/reflect/ClassInfo.java
index 35916f7050..46e1639c9e 100644
---
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/reflect/ClassInfo.java
+++
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/reflect/ClassInfo.java
@@ -1397,6 +1397,37 @@ public class ClassInfo extends ElementInfo implements
Annotatable {
throw illegalArg("Could not resolve variable ''{0}'' to a
type.", actualType.getTypeName());
}
+ /**
+ * Extracts generic type parameter mappings from a class's superclass
declaration and adds them to a type map.
+ *
+ * <p>
+ * This method builds a mapping between type variables (e.g., <c>T</c>,
<c>K</c>, <c>V</c>) and their actual
+ * type arguments in the inheritance hierarchy. It's used to resolve
generic type parameters when navigating
+ * through class hierarchies.
+ *
+ * <p>
+ * The method handles transitive type mappings by checking if an actual
type argument is itself a type variable
+ * that's already been mapped, and resolving it to its final type.
+ *
+ * @param typeMap
+ * The map to populate with type variable to actual type mappings.
+ * <br>Existing entries are used to resolve transitive mappings.
+ * @param c
+ * The class whose generic superclass should be examined for type
parameters.
+ */
+ private static void extractTypes(Map<Type,Type> typeMap, Class<?> c) {
+ var gs = c.getGenericSuperclass();
+ if (gs instanceof ParameterizedType gs2) {
+ var typeParameters =
((Class<?>)gs2.getRawType()).getTypeParameters();
+ var actualTypeArguments = gs2.getActualTypeArguments();
+ for (var i = 0; i < typeParameters.length; i++) {
+ if (typeMap.containsKey(actualTypeArguments[i]))
+ actualTypeArguments[i] =
typeMap.get(actualTypeArguments[i]);
+ typeMap.put(typeParameters[i],
actualTypeArguments[i]);
+ }
+ }
+ }
+
/**
* Returns a list including this class and all parent classes.
*
diff --git
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/utils/ClassUtils.java
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/utils/ClassUtils.java
index 0c69a21332..77afde121f 100644
---
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/utils/ClassUtils.java
+++
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/utils/ClassUtils.java
@@ -18,7 +18,6 @@ package org.apache.juneau.commons.utils;
import static org.apache.juneau.commons.reflect.ReflectionUtils.*;
import static org.apache.juneau.commons.utils.AssertionUtils.*;
-import static org.apache.juneau.commons.utils.ThrowableUtils.*;
import static org.apache.juneau.commons.utils.Utils.*;
import java.lang.reflect.*;
@@ -246,47 +245,6 @@ public class ClassUtils {
return simpleName.replace('$', '.');
}
- /**
- * Extracts generic type parameter mappings from a class's superclass
declaration and adds them to a type map.
- *
- * <p>
- * This method builds a mapping between type variables (e.g., <c>T</c>,
<c>K</c>, <c>V</c>) and their actual
- * type arguments in the inheritance hierarchy. It's used to resolve
generic type parameters when navigating
- * through class hierarchies.
- *
- * <h5 class='section'>Example:</h5>
- * <p class='bjava'>
- * <jc>// Given these classes:</jc>
- * <jk>class</jk> MyList<T> <jk>extends</jk>
ArrayList<T> {}
- * <jk>class</jk> StringList <jk>extends</jk> MyList<String>
{}
- *
- * <jc>// When called on StringList, this would extract:</jc>
- * <jc>// T (from MyList) -> String</jc>
- * </p>
- *
- * <p>
- * The method handles transitive type mappings by checking if an actual
type argument is itself a type variable
- * that's already been mapped, and resolving it to its final type.
- *
- * @param typeMap
- * The map to populate with type variable to actual type mappings.
- * <br>Existing entries are used to resolve transitive mappings.
- * @param c
- * The class whose generic superclass should be examined for type
parameters.
- */
- public static void extractTypes(Map<Type,Type> typeMap, Class<?> c) {
- var gs = c.getGenericSuperclass();
- if (gs instanceof ParameterizedType gs2) {
- var typeParameters =
((Class<?>)gs2.getRawType()).getTypeParameters();
- var actualTypeArguments = gs2.getActualTypeArguments();
- for (var i = 0; i < typeParameters.length; i++) {
- if (typeMap.containsKey(actualTypeArguments[i]))
- actualTypeArguments[i] =
typeMap.get(actualTypeArguments[i]);
- typeMap.put(typeParameters[i],
actualTypeArguments[i]);
- }
- }
- }
-
/**
* Returns the class types for the specified arguments.
*
@@ -393,70 +351,6 @@ public class ClassUtils {
return params;
}
- /**
- * Returns the generic parameter type at the specified index for a
class that extends a parameterized type.
- *
- * @param c The class to examine.
- * @param index The zero-based index of the parameter to retrieve.
- * @param pt The parameterized superclass or interface.
- * @return The parameter type at the specified index.
- * @throws IllegalArgumentException If the class is not a subclass of
the parameterized type or if the index is invalid.
- */
- public static Class<?> getParameterType(Class<?> c, int index, Class<?>
pt) {
- assertArgsNotNull("pt", pt, "c", c);
-
- // We need to make up a mapping of type names.
- var typeMap = new HashMap<Type,Type>();
- var cc = c;
- while (pt != cc.getSuperclass()) {
- extractTypes(typeMap, cc);
- cc = cc.getSuperclass();
- assertArg(nn(cc), "Class ''{0}'' is not a subclass of
parameterized type ''{1}''", cns(c), cns(pt));
- }
-
- var gsc = cc.getGenericSuperclass();
-
- assertArg(gsc instanceof ParameterizedType, "Class ''{0}'' is
not a parameterized type", cns(pt));
-
- var cpt = (ParameterizedType)gsc;
- var atArgs = cpt.getActualTypeArguments();
- assertArg(index < atArgs.length, "Invalid type index.
index={0}, argsLength={1}", index, atArgs.length);
- var actualType = cpt.getActualTypeArguments()[index];
-
- if (typeMap.containsKey(actualType))
- actualType = typeMap.get(actualType);
-
- if (actualType instanceof Class actualType2) {
- return actualType2;
-
- }
- if (actualType instanceof GenericArrayType actualType2) {
- var gct = actualType2.getGenericComponentType();
- if (gct instanceof ParameterizedType gct2)
- return
Array.newInstance((Class<?>)gct2.getRawType(), 0).getClass();
- } else if (actualType instanceof TypeVariable<?> actualType3) {
- var nestedOuterTypes = new LinkedList<Class<?>>();
- for (var ec = cc.getEnclosingClass(); nn(ec); ec =
ec.getEnclosingClass()) {
- var outerClass = cc.getClass();
- nestedOuterTypes.add(outerClass);
- var outerTypeMap = new HashMap<Type,Type>();
- extractTypes(outerTypeMap, outerClass);
- for (var entry : outerTypeMap.entrySet()) {
- var key = entry.getKey();
- var value = entry.getValue();
- if ((key instanceof TypeVariable<?>
key2) && (key2.getName().equals(actualType3.getName()) &&
isInnerClass(key2.getGenericDeclaration(),
actualType3.getGenericDeclaration()))) {
- if (value instanceof Class<?>
value2)
- return value2;
- actualType3 =
(TypeVariable<?>)entry.getValue();
- }
- }
- }
- } else if (actualType instanceof ParameterizedType actualType2)
{
- return (Class<?>)actualType2.getRawType();
- }
- throw illegalArg("Could not resolve variable ''{0}'' to a
type.", actualType.getTypeName());
- }
-
/**
* Attempts to unwrap a proxy object and return the underlying "real"
class.
*
@@ -536,26 +430,6 @@ public class ClassUtils {
return null;
}
- /**
- * Returns the generic parameter type of the Value type.
- *
- * @param t The type to find the parameter type of.
- * @return The parameter type of the value, or <jk>null</jk> if the
type is not a subclass of <c>Value</c>.
- */
- public static Type getValueParameterType(Type t) {
- if (t instanceof ParameterizedType t2) {
- if (t2.getRawType() == Value.class) {
- var ta = t2.getActualTypeArguments();
- if (ta.length > 0)
- return ta[0];
- }
- } else if ((t instanceof Class<?> t3) &&
Value.class.isAssignableFrom(t3)) {
- return getParameterType(t3, 0, Value.class);
- }
-
- return null;
- }
-
/**
* Checks if one generic declaration (typically a class) is an inner
class of another.
*
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/HttpPartSchema.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/HttpPartSchema.java
index 925bd2bb68..72e20b51e8 100644
---
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/HttpPartSchema.java
+++
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/HttpPartSchema.java
@@ -2552,7 +2552,7 @@ public class HttpPartSchema {
if (t instanceof Class<?> c2) {
rstream(AP.find(c, info(c2))).forEach(x ->
apply(x.inner()));
} else if (Value.isType(t)) {
- apply(c, getValueParameterType(t));
+ apply(c, Value.getParameterType(t));
}
return this;
}
diff --git
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/arg/ResponseCodeArg.java
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/arg/ResponseCodeArg.java
index a29d9b290d..b5f748502a 100644
---
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/arg/ResponseCodeArg.java
+++
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/arg/ResponseCodeArg.java
@@ -59,7 +59,7 @@ public class ResponseCodeArg implements RestOpArg {
protected ResponseCodeArg(ParameterInfo paramInfo) {
this.type = paramInfo.getParameterType().innerType();
var c = type instanceof Class ? (Class<?>)type : type
instanceof ParameterizedType ? (Class<?>)((ParameterizedType)type).getRawType()
: null;
- if (c != Value.class || getValueParameterType(type) !=
Integer.class)
+ if (c != Value.class || Value.getParameterType(type) !=
Integer.class)
throw new ArgException(paramInfo, "Type must be
Value<Integer> on parameter annotated with @StatusCode annotation");
}
diff --git
a/juneau-utest/src/test/java/org/apache/juneau/commons/collections/Value_Test.java
b/juneau-utest/src/test/java/org/apache/juneau/commons/collections/Value_Test.java
index 84a0798654..1f14679788 100644
---
a/juneau-utest/src/test/java/org/apache/juneau/commons/collections/Value_Test.java
+++
b/juneau-utest/src/test/java/org/apache/juneau/commons/collections/Value_Test.java
@@ -16,7 +16,6 @@
*/
package org.apache.juneau.commons.collections;
-import static org.apache.juneau.commons.utils.ClassUtils.*;
import static org.apache.juneau.commons.utils.CollectionUtils.*;
import static org.junit.jupiter.api.Assertions.*;
@@ -35,7 +34,7 @@ class Value_Test extends TestBase {
public static class A1 {}
@Test void a01_testSubclass() {
- assertEquals(A1.class, getValueParameterType(A.class));
+ assertEquals(A1.class, Value.getParameterType(A.class));
}
//-----------------------------------------------------------------------------------------------------------------
diff --git
a/juneau-utest/src/test/java/org/apache/juneau/commons/utils/ClassUtils_Test.java
b/juneau-utest/src/test/java/org/apache/juneau/commons/utils/ClassUtils_Test.java
index 706d1681bb..084f73f382 100644
---
a/juneau-utest/src/test/java/org/apache/juneau/commons/utils/ClassUtils_Test.java
+++
b/juneau-utest/src/test/java/org/apache/juneau/commons/utils/ClassUtils_Test.java
@@ -661,122 +661,5 @@ class ClassUtils_Test {
assertNull(result);
}
-
//-----------------------------------------------------------------------------------------------------------------
- // extractTypes(Map<Type,Type>, Class<?>) tests
-
//-----------------------------------------------------------------------------------------------------------------
-
- @Test
- public void n01_extractTypes_basic() {
- class MyList<T> extends ArrayList<T> {}
- class StringList extends MyList<String> {}
-
- var typeMap = new HashMap<Type,Type>();
- extractTypes(typeMap, StringList.class);
- // Should extract T -> String mapping
- assertFalse(typeMap.isEmpty());
- }
-
- @Test
- public void n02_extractTypes_noGenericSuperclass() {
- var typeMap = new HashMap<Type,Type>();
- extractTypes(typeMap, String.class);
- // String doesn't have a generic superclass, so typeMap should
remain empty
- assertTrue(typeMap.isEmpty());
- }
-
- @Test
- public void n03_extractTypes_transitiveMapping() {
- // Test line 284: typeMap.containsKey(actualTypeArguments[i])
branch
- // This tests transitive type mapping where an actual type
argument is itself
- // a type variable that's already been mapped in the typeMap
- class Base<T> {}
- class Middle<U> extends Base<U> {}
- class Top<V> extends Middle<V> {}
- class Concrete extends Top<String> {}
-
- var typeMap = new HashMap<Type,Type>();
- // First extract from Concrete -> Top<String>
- // This will add V -> String to typeMap
- extractTypes(typeMap, Concrete.class);
-
- // Now extract from Top -> Middle<V>
- // When processing Middle<V>, actualTypeArguments[0] is V
(TypeVariable)
- // Since V is already in typeMap (mapped to String), line 284
should execute:
- // actualTypeArguments[i] = typeMap.get(actualTypeArguments[i]);
- // This replaces V with String before putting it in the map
- extractTypes(typeMap, Top.class);
-
- // Verify the transitive mapping worked
- // The typeMap should now contain both V -> String and U ->
String
- assertFalse(typeMap.isEmpty());
- }
-
-
//-----------------------------------------------------------------------------------------------------------------
- // getValueParameterType(Type) tests
-
//-----------------------------------------------------------------------------------------------------------------
-
- @Test
- public void o01_getValueParameterType_parameterizedType() throws
Exception {
- class TestClass {
- Value<String> field;
- }
- var field = TestClass.class.getDeclaredField("field");
- var genericType = field.getGenericType();
- var result = getValueParameterType(genericType);
- assertEquals(String.class, result);
- }
-
- @Test
- public void o02_getValueParameterType_class() {
- class StringValue extends Value<String> {}
- var result = getValueParameterType(StringValue.class);
- assertEquals(String.class, result);
- }
-
- @Test
- public void o03_getValueParameterType_notValue() {
- var result = getValueParameterType(String.class);
- assertNull(result);
- }
-
-
//-----------------------------------------------------------------------------------------------------------------
- // getParameterType(Class<?>, int, Class<?>) tests
-
//-----------------------------------------------------------------------------------------------------------------
-
- @Test
- public void p01_getParameterType_basic() {
- class MyList<T> extends ArrayList<T> {}
- class StringList extends MyList<String> {}
-
- var result = getParameterType(StringList.class, 0,
MyList.class);
- assertEquals(String.class, result);
- }
-
- @Test
- public void p02_getParameterType_invalidIndex() {
- class MyList<T> extends ArrayList<T> {}
- class StringList extends MyList<String> {}
-
- assertThrows(IllegalArgumentException.class, () -> {
- getParameterType(StringList.class, 1, MyList.class);
- });
- }
-
- @Test
- public void p03_getParameterType_notSubclass() {
- assertThrows(IllegalArgumentException.class, () -> {
- getParameterType(String.class, 0, ArrayList.class);
- });
- }
-
- @Test
- public void p04_getParameterType_nullArgs() {
- assertThrows(IllegalArgumentException.class, () -> {
- getParameterType(null, 0, String.class);
- });
- assertThrows(IllegalArgumentException.class, () -> {
- getParameterType(String.class, 0, null);
- });
- }
}