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 c995488 JUNEAU-137 - Juneau cannot reflect parameterized types on
Spring bean methods.
c995488 is described below
commit c99548873f8f429f7136794b318565f5c755cbec
Author: JamesBognar <[email protected]>
AuthorDate: Thu Sep 5 20:01:26 2019 -0400
JUNEAU-137 - Juneau cannot reflect parameterized types on Spring bean
methods.
---
.../juneau/reflection/ConstructorInfoTest.java | 4 +-
.../apache/juneau/reflection/MethodInfoTest.java | 4 +-
.../org/apache/juneau/internal/ClassUtils.java | 4 +-
.../java/org/apache/juneau/reflect/ClassInfo.java | 80 +++++++++++++++++++---
.../org/apache/juneau/reflect/ConstructorInfo.java | 12 ++--
.../org/apache/juneau/reflect/ExecutableInfo.java | 10 +--
.../java/org/apache/juneau/reflect/MethodInfo.java | 12 ++--
.../java/org/apache/juneau/rest/RestContext.java | 16 ++---
8 files changed, 105 insertions(+), 37 deletions(-)
diff --git
a/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/reflection/ConstructorInfoTest.java
b/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/reflection/ConstructorInfoTest.java
index 9712a30..d552ff8 100644
---
a/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/reflection/ConstructorInfoTest.java
+++
b/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/reflection/ConstructorInfoTest.java
@@ -67,7 +67,7 @@ public class ConstructorInfoTest {
@Test
public void of_withDeclaringClass() throws Exception {
- check("A()", ConstructorInfo.of(ClassInfo.of(A.class),
a.inner()));
+ check("A()", ConstructorInfo.of(ClassInfo.of(A.class),
a.inner(), null));
}
@Test
@@ -83,7 +83,7 @@ public class ConstructorInfoTest {
@Test
public void of_null() throws Exception {
check(null, ConstructorInfo.of(null));
- check(null, ConstructorInfo.of(null, null));
+ check(null, ConstructorInfo.of(null, null, null));
}
//-----------------------------------------------------------------------------------------------------------------
diff --git
a/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/reflection/MethodInfoTest.java
b/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/reflection/MethodInfoTest.java
index 3e752fd..c37097c 100644
---
a/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/reflection/MethodInfoTest.java
+++
b/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/reflection/MethodInfoTest.java
@@ -120,7 +120,7 @@ public class MethodInfoTest {
@Test
public void of_withDeclaringClass() {
check("A1.m()", a_m);
- check("A1.m()", MethodInfo.of(ClassInfo.of(A1.class),
a_m.inner()));
+ check("A1.m()", MethodInfo.of(ClassInfo.of(A1.class),
a_m.inner(), null));
}
@Test
@@ -132,7 +132,7 @@ public class MethodInfoTest {
@Test
public void of_null() {
check(null, MethodInfo.of(null));
- check(null, MethodInfo.of(null, null));
+ check(null, MethodInfo.of(null, null, null));
}
//-----------------------------------------------------------------------------------------------------------------
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/ClassUtils.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/ClassUtils.java
index b2d72e1..c1f7005 100644
---
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/ClassUtils.java
+++
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/ClassUtils.java
@@ -55,7 +55,7 @@ public final class ClassUtils {
}
/**
- * Shortcut for calling {@link MethodInfo#of(ClassInfo, Method)}.
+ * Shortcut for calling {@link MethodInfo#of(ClassInfo, Method,
Method)}.
*
* @param c
* The class containing the method.
@@ -65,7 +65,7 @@ public final class ClassUtils {
* @return The wrapped method.
*/
public static MethodInfo getMethodInfo(Class<?> c, Method m) {
- return MethodInfo.of(ClassInfo.of(c), m);
+ return MethodInfo.of(ClassInfo.of(c), m, m);
}
/**
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/ClassInfo.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/ClassInfo.java
index f226c67..8ed4f3e 100644
---
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/ClassInfo.java
+++
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/ClassInfo.java
@@ -58,6 +58,7 @@ public final class ClassInfo {
private final Type t;
final Class<?> c;
+ private ClassInfo proxyFor;
private final boolean isParameterizedType;
private List<ClassInfo> interfaces, declaredInterfaces, parents,
allParents;
private List<MethodInfo> publicMethods, declaredMethods, allMethods,
allMethodsParentFirst;
@@ -76,10 +77,12 @@ public final class ClassInfo {
*
* @param c The class type.
* @param t The generic type (if parameterized type).
+ * @param proxyFor If the class is a CGLIB proxy, this is the
underlying wrapped class.
*/
- protected ClassInfo(Class<?> c, Type t) {
+ protected ClassInfo(Class<?> c, Type t, Class<?> proxyFor) {
this.t = t;
this.c = c;
+ this.proxyFor = proxyFor == null ? null :
ClassInfo.of(proxyFor);
this.isParameterizedType = t == null ? false : (t instanceof
ParameterizedType);
}
@@ -92,7 +95,7 @@ public final class ClassInfo {
public static ClassInfo of(Type t) {
if (t == null)
return null;
- return new ClassInfo(ClassUtils.toClass(t), t);
+ return new ClassInfo(ClassUtils.toClass(t), t, null);
}
/**
@@ -104,7 +107,7 @@ public final class ClassInfo {
public static ClassInfo of(Class<?> c) {
if (c == null)
return null;
- return new ClassInfo(c, c);
+ return new ClassInfo(c, c, null);
}
/**
@@ -115,7 +118,7 @@ public final class ClassInfo {
* @return The constructed class info, or <jk>null</jk> if the type was
<jk>null</jk>.
*/
public static ClassInfo of(Class<?> c, Type t) {
- return new ClassInfo(c, t);
+ return new ClassInfo(c, t, null);
}
/**
@@ -127,7 +130,28 @@ public final class ClassInfo {
public static ClassInfo of(Object o) {
if (o == null)
return null;
- return new ClassInfo(o.getClass(), o.getClass());
+ return new ClassInfo(o.getClass(), o.getClass(),
getProxyFor(o));
+ }
+
+ /**
+ * When this metadata is against a CGLIB proxy, this method finds the
underlying "real" class.
+ *
+ * @param o The class instance.
+ * @return The non-proxy class, or <jk>null</jk> if it's not a CGLIB
proxy.
+ */
+ private static Class<?> getProxyFor(Object o) {
+ Class<?> c = o.getClass();
+ String s = c.getName();
+ if (s.indexOf('$') == -1 || !
s.contains("$$EnhancerBySpringCGLIB$$"))
+ return null;
+ for (Method m : c.getMethods()) {
+ if (m.getName().equals("getTargetClass") &&
m.getParameterCount() == 0 && m.getReturnType().equals(Class.class)) {
+ try {
+ return (Class<?>) m.invoke(o);
+ } catch (Exception e) {}
+ }
+ }
+ return null;
}
/**
@@ -160,6 +184,26 @@ public final class ClassInfo {
return this;
}
+ /**
+ * Identifies the inner target class when this class info represents a
CGLIB proxy class.
+ *
+ * @param proxyFor The inner non-proxied class.
+ * @return This object (for method chaining).
+ */
+ public ClassInfo proxyFor(Class<?> proxyFor) {
+ this.proxyFor = ClassInfo.of(proxyFor);
+ return this;
+ }
+
+ /**
+ * Returns the non-proxied inner class of a CGLIB proxy class.
+ *
+ * @return The non-proxied inner class of a CGLIB proxy class, or the
inner class if it's not a proxy.
+ */
+ public Class<?> getProxiedClass() {
+ return proxyFor == null ? c : proxyFor.inner();
+ }
+
//-----------------------------------------------------------------------------------------------------------------
// Parent classes and interfaces.
//-----------------------------------------------------------------------------------------------------------------
@@ -308,13 +352,31 @@ public final class ClassInfo {
List<MethodInfo> l = new ArrayList<>(mm.length);
for (Method m : mm)
if (m.getDeclaringClass() != Object.class)
- l.add(MethodInfo.of(this, m));
+ l.add(MethodInfo.of(this, m,
getProxyTarget(m)));
l.sort(null);
publicMethods = Collections.unmodifiableList(l);
}
return publicMethods;
}
+ private Method getProxyTarget(Method m) {
+ if (proxyFor != null) {
+ MethodInfo m2 = proxyFor.getMethod(m.getName(),
m.getParameterTypes());
+ if (m2 != null)
+ return m2.inner();
+ }
+ return m;
+ }
+
+ private Constructor<?> getProxyTarget(Constructor<?> c) {
+ if (proxyFor != null) {
+ ConstructorInfo c2 =
proxyFor.getConstructor(Visibility.PRIVATE, c.getParameterTypes());
+ if (c2 != null)
+ return c2.inner();
+ }
+ return c;
+ }
+
/**
* Returns the public method with the specified method name and
argument types.
*
@@ -358,7 +420,7 @@ public final class ClassInfo {
List<MethodInfo> l = new ArrayList<>(mm.length);
for (Method m : mm)
if (! "$jacocoInit".equals(m.getName())) //
Jacoco adds its own simulated methods.
- l.add(MethodInfo.of(this, m));
+ l.add(MethodInfo.of(this, m,
getProxyTarget(m)));
l.sort(null);
declaredMethods = Collections.unmodifiableList(l);
}
@@ -516,7 +578,7 @@ public final class ClassInfo {
Constructor<?>[] cc = c == null ? new Constructor[0] :
c.getConstructors();
List<ConstructorInfo> l = new ArrayList<>(cc.length);
for (Constructor<?> ccc : cc)
- l.add(ConstructorInfo.of(this, ccc));
+ l.add(ConstructorInfo.of(this, ccc,
getProxyTarget(ccc)));
l.sort(null);
publicConstructors = Collections.unmodifiableList(l);
}
@@ -575,7 +637,7 @@ public final class ClassInfo {
Constructor<?>[] cc = c == null ? new Constructor[0] :
c.getDeclaredConstructors();
List<ConstructorInfo> l = new ArrayList<>(cc.length);
for (Constructor<?> ccc : cc)
- l.add(ConstructorInfo.of(this, ccc));
+ l.add(ConstructorInfo.of(this, ccc,
getProxyTarget(ccc)));
l.sort(null);
declaredConstructors = Collections.unmodifiableList(l);
}
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/ConstructorInfo.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/ConstructorInfo.java
index cb66dd5..36c01b9 100644
---
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/ConstructorInfo.java
+++
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/ConstructorInfo.java
@@ -34,9 +34,10 @@ public final class ConstructorInfo extends ExecutableInfo
implements Comparable<
*
* @param declaringClass The class that declares this method.
* @param c The constructor being wrapped.
+ * @param rc The "real" constructor if the constructor above is defined
against a CGLIB proxy.
*/
- protected ConstructorInfo(ClassInfo declaringClass, Constructor<?> c) {
- super(declaringClass, c);
+ protected ConstructorInfo(ClassInfo declaringClass, Constructor<?> c,
Constructor<?> rc) {
+ super(declaringClass, c, rc);
this.c = c;
}
@@ -45,12 +46,13 @@ public final class ConstructorInfo extends ExecutableInfo
implements Comparable<
*
* @param declaringClass The class that declares this method.
* @param c The constructor being wrapped.
+ * @param rc The "real" constructor if the constructor above is defined
against a CGLIB proxy.
* @return A new {@link ConstructorInfo} object, or <jk>null</jk> if
the method was null;
*/
- public static ConstructorInfo of(ClassInfo declaringClass,
Constructor<?> c) {
+ public static ConstructorInfo of(ClassInfo declaringClass,
Constructor<?> c, Constructor<?> rc) {
if (c == null)
return null;
- return new ConstructorInfo(declaringClass, c);
+ return new ConstructorInfo(declaringClass, c, rc);
}
/**
@@ -62,7 +64,7 @@ public final class ConstructorInfo extends ExecutableInfo
implements Comparable<
public static ConstructorInfo of(Constructor<?> c) {
if (c == null)
return null;
- return new ConstructorInfo(ClassInfo.of(c.getDeclaringClass()),
c);
+ return new ConstructorInfo(ClassInfo.of(c.getDeclaringClass()),
c, c);
}
/**
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/ExecutableInfo.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/ExecutableInfo.java
index df1d89c..f07c120 100644
---
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/ExecutableInfo.java
+++
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/ExecutableInfo.java
@@ -28,7 +28,7 @@ import org.apache.juneau.internal.*;
public abstract class ExecutableInfo {
final ClassInfo declaringClass;
- final Executable e;
+ final Executable e, re;
final boolean isConstructor;
private List<ParamInfo> params;
@@ -43,10 +43,12 @@ public abstract class ExecutableInfo {
*
* @param declaringClass The class that declares this method or
constructor.
* @param e The constructor or method that this info represents.
+ * @param re The "real" constructor if the constructor above is defined
against a CGLIB proxy.
*/
- protected ExecutableInfo(ClassInfo declaringClass, Executable e) {
+ protected ExecutableInfo(ClassInfo declaringClass, Executable e,
Executable re) {
this.declaringClass = declaringClass;
this.e = e;
+ this.re = re == null ? e : re;
this.isConstructor = e instanceof Constructor;
}
@@ -259,13 +261,13 @@ public abstract class ExecutableInfo {
Type[] rawGenericParamTypes() {
if (rawGenericParamTypes == null)
- rawGenericParamTypes = e.getGenericParameterTypes();
+ rawGenericParamTypes = re.getGenericParameterTypes();
return rawGenericParamTypes;
}
Parameter[] rawParameters() {
if (rawParameters == null)
- rawParameters = e.getParameters();
+ rawParameters = re.getParameters();
return rawParameters;
}
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/MethodInfo.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/MethodInfo.java
index 861d99d..2d189cb 100644
---
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/MethodInfo.java
+++
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/MethodInfo.java
@@ -43,9 +43,10 @@ public final class MethodInfo extends ExecutableInfo
implements Comparable<Metho
*
* @param declaringClass The class that declares this method.
* @param m The method being wrapped.
+ * @param rm The "real" method if the method above is defined against a
CGLIB proxy.
*/
- protected MethodInfo(ClassInfo declaringClass, Method m) {
- super(declaringClass, m);
+ protected MethodInfo(ClassInfo declaringClass, Method m, Method rm) {
+ super(declaringClass, m, rm);
this.m = m;
}
@@ -54,12 +55,13 @@ public final class MethodInfo extends ExecutableInfo
implements Comparable<Metho
*
* @param declaringClass The class that declares this method.
* @param m The method being wrapped.
+ * @param rm The "real" method if the method above is defined against a
CGLIB proxy.
* @return A new {@link MethodInfo} object, or <jk>null</jk> if the
method was null;
*/
- public static MethodInfo of(ClassInfo declaringClass, Method m) {
+ public static MethodInfo of(ClassInfo declaringClass, Method m, Method
rm) {
if (m == null)
return null;
- return new MethodInfo(declaringClass, m);
+ return new MethodInfo(declaringClass, m, rm);
}
/**
@@ -71,7 +73,7 @@ public final class MethodInfo extends ExecutableInfo
implements Comparable<Metho
public static MethodInfo of(Method m) {
if (m == null)
return null;
- return new MethodInfo(ClassInfo.of(m.getDeclaringClass()), m);
+ return new MethodInfo(ClassInfo.of(m.getDeclaringClass()), m,
m);
}
/**
diff --git
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContext.java
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContext.java
index 57cb7b2..ad65e00 100644
---
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContext.java
+++
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContext.java
@@ -3600,8 +3600,8 @@ public final class RestContext extends BeanContext {
VarResolverSession vrs =
this.varResolver.createSession();
config = builder.config.resolving(vrs);
- Class<?> resourceClass = resource.getClass();
- ClassInfo rci = getClassInfo(resourceClass);
+ ClassInfo rci = getClassInfo(resource);
+
PropertyStore ps = getPropertyStore();
uriContext =
nullIfEmpty(getStringProperty(REST_uriContext, null));
@@ -3683,7 +3683,7 @@ public final class RestContext extends BeanContext {
ClasspathResourceFinder rf =
getInstanceProperty(REST_classpathResourceFinder,
ClasspathResourceFinder.class, ClasspathResourceFinderBasic.class,
resourceResolver, this);
useClasspathResourceCaching =
getProperty(REST_useClasspathResourceCaching, boolean.class, true);
- staticResourceManager = new
ClasspathResourceManager(resourceClass, rf, useClasspathResourceCaching);
+ staticResourceManager = new
ClasspathResourceManager(rci.getProxiedClass(), rf,
useClasspathResourceCaching);
consumes = getListProperty(REST_consumes,
MediaType.class, parsers.getSupportedMediaTypes());
produces = getListProperty(REST_produces,
MediaType.class, serializers.getSupportedMediaTypes());
@@ -3696,11 +3696,11 @@ public final class RestContext extends BeanContext {
MessageBundleLocation[] mbl =
getInstanceArrayProperty(REST_messages, MessageBundleLocation.class, new
MessageBundleLocation[0]);
if (mbl.length == 0)
- msgs = new MessageBundle(resourceClass, "");
+ msgs = new MessageBundle(rci.getProxiedClass(),
"");
else {
- msgs = new MessageBundle(mbl[0] != null ?
mbl[0].baseClass : resourceClass, mbl[0].bundlePath);
+ msgs = new MessageBundle(mbl[0] != null ?
mbl[0].baseClass : rci.getProxiedClass(), mbl[0].bundlePath);
for (int i = 1; i < mbl.length; i++)
- msgs.addSearchPath(mbl[i] != null ?
mbl[i].baseClass : resourceClass, mbl[i].bundlePath);
+ msgs.addSearchPath(mbl[i] != null ?
mbl[i].baseClass : rci.getProxiedClass(), mbl[i].bundlePath);
}
this.fullPath = (builder.parentContext == null ? "" :
(builder.parentContext.fullPath + '/')) + builder.getPath();
@@ -3743,7 +3743,7 @@ public final class RestContext extends BeanContext {
methodsFound.add(mi.getSimpleName() +
"," + emptyIfNull(firstNonEmpty(a.name(), a.method())) + "," +
fixMethodPath(a.path()));
try {
if (mi.isNotPublic())
- throw new
RestServletException("@RestMethod method {0}.{1} must be defined as public.",
resourceClass.getName(), mi.getSimpleName());
+ throw new
RestServletException("@RestMethod method {0}.{1} must be defined as public.",
rci.getProxiedClass().getName(), mi.getSimpleName());
RestMethodContextBuilder rmcb =
new RestMethodContextBuilder(resource, mi.inner(), this);
RestMethodContext sm = new
RestMethodContext(rmcb);
@@ -3816,7 +3816,7 @@ public final class RestContext extends BeanContext {
addToRouter(routers,
httpMethod, sm);
}
} catch (Throwable e) {
- throw new
RestServletException("Problem occurred trying to serialize methods on class
{0}, methods={1}", resourceClass.getName(),
SimpleJsonSerializer.DEFAULT.serialize(methodsFound)).initCause(e);
+ throw new
RestServletException("Problem occurred trying to serialize methods on class
{0}, methods={1}", rci.getProxiedClass().getName(),
SimpleJsonSerializer.DEFAULT.serialize(methodsFound)).initCause(e);
}
}
}