mirror of https://github.com/apache/openjpa.git
OPENJPA-1686: Support when a parameterized type has parameterized type arguments
git-svn-id: https://svn.apache.org/repos/asf/openjpa/trunk@953717 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
6b38f0cb8e
commit
59c7001e09
|
@ -23,9 +23,11 @@ import java.lang.reflect.Method;
|
||||||
import java.security.AccessController;
|
import java.security.AccessController;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Utilities for dealing with different Java spec versions.
|
* Utilities for dealing with different Java specification versions.
|
||||||
*
|
*
|
||||||
* @author Abe White
|
* @author Abe White
|
||||||
|
* @author Pinaki Poddar
|
||||||
|
*
|
||||||
* @nojavadoc
|
* @nojavadoc
|
||||||
*/
|
*/
|
||||||
public class JavaVersions {
|
public class JavaVersions {
|
||||||
|
@ -35,15 +37,17 @@ public class JavaVersions {
|
||||||
*/
|
*/
|
||||||
public static final int VERSION;
|
public static final int VERSION;
|
||||||
|
|
||||||
private static final Class[] EMPTY_CLASSES = new Class[0];
|
private static final Class<?>[] EMPTY_CLASSES = new Class[0];
|
||||||
|
|
||||||
private static Class PARAM_TYPE = null;
|
private static Class<?> PARAM_TYPE = null;
|
||||||
private static Class ENUM_TYPE = null;
|
private static Class<?> ENUM_TYPE = null;
|
||||||
private static Class ANNO_TYPE = null;
|
private static Class<?> ANNO_TYPE = null;
|
||||||
private static Method GET_STACK = null;
|
private static Method GET_STACK = null;
|
||||||
private static Method SET_STACK = null;
|
private static Method SET_STACK = null;
|
||||||
private static Method GET_CAUSE = null;
|
private static Method GET_CAUSE = null;
|
||||||
private static Method INIT_CAUSE = null;
|
private static Method INIT_CAUSE = null;
|
||||||
|
private static Object[] NO_ARGS = null;
|
||||||
|
private static Class<?>[] NO_CLASS_ARGS = null;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
String specVersion = AccessController.doPrivileged(
|
String specVersion = AccessController.doPrivileged(
|
||||||
|
@ -63,8 +67,7 @@ public class JavaVersions {
|
||||||
|
|
||||||
if (VERSION >= 5) {
|
if (VERSION >= 5) {
|
||||||
try {
|
try {
|
||||||
PARAM_TYPE = Class.forName
|
PARAM_TYPE = Class.forName("java.lang.reflect.ParameterizedType");
|
||||||
("java.lang.reflect.ParameterizedType");
|
|
||||||
ENUM_TYPE = Class.forName("java.lang.Enum");
|
ENUM_TYPE = Class.forName("java.lang.Enum");
|
||||||
ANNO_TYPE = Class.forName("java.lang.annotation.Annotation");
|
ANNO_TYPE = Class.forName("java.lang.annotation.Annotation");
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
|
@ -73,15 +76,11 @@ public class JavaVersions {
|
||||||
|
|
||||||
if (VERSION >= 4) {
|
if (VERSION >= 4) {
|
||||||
try {
|
try {
|
||||||
Class stack = Class.forName("[Ljava.lang.StackTraceElement;");
|
Class<?> stack = Class.forName("[Ljava.lang.StackTraceElement;");
|
||||||
GET_STACK = Throwable.class.getMethod("getStackTrace",
|
GET_STACK = Throwable.class.getMethod("getStackTrace", NO_CLASS_ARGS);
|
||||||
(Class[]) null);
|
SET_STACK = Throwable.class.getMethod("setStackTrace", new Class[]{ stack });
|
||||||
SET_STACK = Throwable.class.getMethod("setStackTrace",
|
GET_CAUSE = Throwable.class.getMethod("getCause", NO_CLASS_ARGS);
|
||||||
new Class[]{ stack });
|
INIT_CAUSE = Throwable.class.getMethod("initCause", new Class[]{ Throwable.class });
|
||||||
GET_CAUSE = Throwable.class.getMethod("getCause",
|
|
||||||
(Class[]) null);
|
|
||||||
INIT_CAUSE = Throwable.class.getMethod("initCause",
|
|
||||||
new Class[]{ Throwable.class });
|
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -94,7 +93,7 @@ public class JavaVersions {
|
||||||
* @return the JDK-version-specific version of the class
|
* @return the JDK-version-specific version of the class
|
||||||
* @see #getVersionSpecificClass(String)
|
* @see #getVersionSpecificClass(String)
|
||||||
*/
|
*/
|
||||||
public static Class getVersionSpecificClass(Class base) {
|
public static Class<?> getVersionSpecificClass(Class<?> base) {
|
||||||
try {
|
try {
|
||||||
return getVersionSpecificClass(base.getName());
|
return getVersionSpecificClass(base.getName());
|
||||||
} catch (ClassNotFoundException e) {
|
} catch (ClassNotFoundException e) {
|
||||||
|
@ -125,14 +124,13 @@ public class JavaVersions {
|
||||||
* @param base the base name of the class to load
|
* @param base the base name of the class to load
|
||||||
* @return the subclass appropriate for the current Java version
|
* @return the subclass appropriate for the current Java version
|
||||||
*/
|
*/
|
||||||
public static Class getVersionSpecificClass(String base)
|
public static Class<?> getVersionSpecificClass(String base)
|
||||||
throws ClassNotFoundException {
|
throws ClassNotFoundException {
|
||||||
for (int i = VERSION; i >= 1; i--) {
|
for (int i = VERSION; i >= 1; i--) {
|
||||||
try {
|
try {
|
||||||
return Class.forName(base + i);
|
return Class.forName(base + i);
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
// throwables might occur with bytecode that we
|
// throwables might occur with bytecode that we cannot understand
|
||||||
// cannot understand
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Class.forName(base);
|
return Class.forName(base);
|
||||||
|
@ -141,29 +139,28 @@ public class JavaVersions {
|
||||||
/**
|
/**
|
||||||
* Return true if the given type is an annotation.
|
* Return true if the given type is an annotation.
|
||||||
*/
|
*/
|
||||||
public static boolean isAnnotation(Class cls) {
|
public static boolean isAnnotation(Class<?> cls) {
|
||||||
return ANNO_TYPE != null && ANNO_TYPE.isAssignableFrom(cls);
|
return ANNO_TYPE != null && ANNO_TYPE.isAssignableFrom(cls);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return true if the given type is an enumeration.
|
* Return true if the given type is an enumeration.
|
||||||
*/
|
*/
|
||||||
public static boolean isEnumeration(Class cls) {
|
public static boolean isEnumeration(Class<?> cls) {
|
||||||
return ENUM_TYPE != null && ENUM_TYPE.isAssignableFrom(cls);
|
return ENUM_TYPE != null && ENUM_TYPE.isAssignableFrom(cls);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Collects the parameterized type declarations for a given field.
|
* Collects the parameterized type declarations for a given field.
|
||||||
*/
|
*/
|
||||||
public static Class[] getParameterizedTypes(Field f) {
|
public static Class<?>[] getParameterizedTypes(Field f) {
|
||||||
if (f == null)
|
if (f == null)
|
||||||
return null;
|
return null;
|
||||||
if (VERSION < 5)
|
if (VERSION < 5)
|
||||||
return EMPTY_CLASSES;
|
return EMPTY_CLASSES;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Object type = Field.class.getMethod("getGenericType",
|
Object type = invokeGetter(f, "getGenericType");
|
||||||
(Class[]) null).invoke(f, (Object[]) null);
|
|
||||||
return collectParameterizedTypes(type, f.getType());
|
return collectParameterizedTypes(type, f.getType());
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
return EMPTY_CLASSES;
|
return EMPTY_CLASSES;
|
||||||
|
@ -173,15 +170,14 @@ public class JavaVersions {
|
||||||
/**
|
/**
|
||||||
* Collects the parameterized return type declarations for a given method.
|
* Collects the parameterized return type declarations for a given method.
|
||||||
*/
|
*/
|
||||||
public static Class[] getParameterizedTypes(Method meth) {
|
public static Class<?>[] getParameterizedTypes(Method meth) {
|
||||||
if (meth == null)
|
if (meth == null)
|
||||||
return null;
|
return null;
|
||||||
if (VERSION < 5)
|
if (VERSION < 5)
|
||||||
return EMPTY_CLASSES;
|
return EMPTY_CLASSES;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Object type = Method.class.getMethod("getGenericReturnType",
|
Object type = invokeGetter(meth, "getGenericReturnType");
|
||||||
(Class[]) null).invoke(meth, (Object[]) null);
|
|
||||||
return collectParameterizedTypes(type, meth.getReturnType());
|
return collectParameterizedTypes(type, meth.getReturnType());
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
return EMPTY_CLASSES;
|
return EMPTY_CLASSES;
|
||||||
|
@ -191,28 +187,46 @@ public class JavaVersions {
|
||||||
/**
|
/**
|
||||||
* Return all parameterized classes for the given type.
|
* Return all parameterized classes for the given type.
|
||||||
*/
|
*/
|
||||||
private static Class[] collectParameterizedTypes(Object type, Class<?> cls)
|
private static Class<?>[] collectParameterizedTypes(Object type, Class<?> cls) throws Exception {
|
||||||
throws Exception {
|
if (isParameterizedType(type)) {
|
||||||
if (PARAM_TYPE == null || !PARAM_TYPE.isInstance(type)) {
|
Object[] args = (Object[]) invokeGetter(type, "getActualTypeArguments");
|
||||||
if (cls.getSuperclass() != Object.class) {
|
Class<?>[] clss = new Class[args.length];
|
||||||
return collectParameterizedTypes(cls.getGenericSuperclass(), cls.getSuperclass());
|
for (int i = 0; i < args.length; i++) {
|
||||||
|
Class<?> c = extractClass(args[i]);
|
||||||
|
if (c == null) {
|
||||||
|
return EMPTY_CLASSES;
|
||||||
|
}
|
||||||
|
clss[i] = c;
|
||||||
}
|
}
|
||||||
|
return clss;
|
||||||
|
} else if (cls.getSuperclass() != Object.class) {
|
||||||
|
return collectParameterizedTypes(cls.getGenericSuperclass(), cls.getSuperclass());
|
||||||
|
} else {
|
||||||
return EMPTY_CLASSES;
|
return EMPTY_CLASSES;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
Object[] args = (Object[]) PARAM_TYPE.getMethod
|
|
||||||
("getActualTypeArguments", (Class[]) null).invoke(type,
|
/**
|
||||||
(Object[]) null);
|
* Extracts the class from the given argument, if possible. Null otherwise.
|
||||||
if (args.length == 0)
|
*/
|
||||||
return EMPTY_CLASSES;
|
static Class<?> extractClass(Object o) throws Exception {
|
||||||
|
if (o == null)
|
||||||
Class[] clss = new Class[args.length];
|
return null;
|
||||||
for (int i = 0; i < args.length; i++) {
|
if (o instanceof Class)
|
||||||
if (!(args[i] instanceof Class))
|
return (Class<?>)o;
|
||||||
return EMPTY_CLASSES;
|
|
||||||
clss[i] = (Class) args[i];
|
if (isParameterizedType(o)) {
|
||||||
|
return extractClass(invokeGetter(o, "getRawType"));
|
||||||
}
|
}
|
||||||
return clss;
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Object invokeGetter(Object target, String method) throws Exception {
|
||||||
|
return target.getClass().getMethod(method, NO_CLASS_ARGS).invoke(target, NO_ARGS);
|
||||||
|
}
|
||||||
|
|
||||||
|
static boolean isParameterizedType(Object cls) {
|
||||||
|
return PARAM_TYPE != null && PARAM_TYPE.isInstance(cls);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -220,12 +234,11 @@ public class JavaVersions {
|
||||||
* false if it cannot be done, possibly due to an unsupported Java version.
|
* false if it cannot be done, possibly due to an unsupported Java version.
|
||||||
*/
|
*/
|
||||||
public static boolean transferStackTrace(Throwable from, Throwable to) {
|
public static boolean transferStackTrace(Throwable from, Throwable to) {
|
||||||
if (GET_STACK == null || SET_STACK == null || from == null
|
if (GET_STACK == null || SET_STACK == null || from == null || to == null)
|
||||||
|| to == null)
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Object stack = GET_STACK.invoke(from, (Object[]) null);
|
Object stack = GET_STACK.invoke(from, NO_ARGS);
|
||||||
SET_STACK.invoke(to, new Object[]{ stack });
|
SET_STACK.invoke(to, new Object[]{ stack });
|
||||||
return true;
|
return true;
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
|
@ -241,7 +254,7 @@ public class JavaVersions {
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return (Throwable) GET_CAUSE.invoke(ex, (Object[]) null);
|
return (Throwable) GET_CAUSE.invoke(ex, NO_ARGS);
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue