diff --git a/src/dorkbox/util/ClassHelper.java b/src/dorkbox/util/ClassHelper.java
index 692b40d..024c666 100644
--- a/src/dorkbox/util/ClassHelper.java
+++ b/src/dorkbox/util/ClassHelper.java
@@ -15,39 +15,42 @@
*/
package dorkbox.util;
-import java.lang.reflect.*;
+import java.lang.reflect.Type;
public final
class ClassHelper {
/**
- * Retrieves the generic type parameter for the PARENT (super) class of the specified class. This ONLY works
- * on parent classes because of how type erasure works in java!
+ * Retrieves the generic type parameter for the PARENT (super) class of the specified class or lambda expression.
*
- * @param clazz class to get the parameter from
+ * Because of how type erasure works in java, this will work on lambda expressions and ONLY parent/super classes.
+ *
+ * @param clazz class that defines what the parameters can be
+ * @param subClazz class to actually get the parameter from
* @param genericParameterToGet 0-based index of parameter as class to get
+ *
+ * @return null if the generic type could not be found.
*/
@SuppressWarnings({"StatementWithEmptyBody", "UnnecessaryLocalVariable"})
public static
- Class> getGenericParameterAsClassForSuperClass(Class> clazz, int genericParameterToGet) {
- Class> classToCheck = clazz;
+ Class> getGenericParameterAsClassForSuperClass(Class> clazz, Class> subClazz, int genericParameterToGet) {
+ Class> classToCheck = subClazz;
+
+ // this will ALWAYS return something, if it is unknown, it will return TypeResolver.Unknown.class
+ Class>[] classes = TypeResolver.resolveRawArguments(clazz, classToCheck);
+ if (classes.length > genericParameterToGet && classes[genericParameterToGet] != TypeResolver.Unknown.class) {
+ return classes[genericParameterToGet];
+ }
// case of multiple inheritance, we are trying to get the first available generic info
// don't check for Object.class (this is where superclass is null)
while (classToCheck != Object.class) {
// check to see if we have what we are looking for on our CURRENT class
Type superClassGeneric = classToCheck.getGenericSuperclass();
- if (superClassGeneric instanceof ParameterizedType) {
- Type[] actualTypeArguments = ((ParameterizedType) superClassGeneric).getActualTypeArguments();
- // is it possible?
- if (actualTypeArguments.length > genericParameterToGet) {
- Class> rawTypeAsClass = getRawTypeAsClass(actualTypeArguments[genericParameterToGet]);
- return rawTypeAsClass;
- }
- else {
- // record the parameters.
- }
+ classes = TypeResolver.resolveRawArguments(superClassGeneric, classToCheck);
+ if (classes.length > genericParameterToGet && classes[genericParameterToGet] != TypeResolver.Unknown.class) {
+ return classes[genericParameterToGet];
}
// NO MATCH, so walk up.
@@ -55,21 +58,15 @@ class ClassHelper {
}
// NOTHING! now check interfaces!
- classToCheck = clazz;
+ classToCheck = subClazz;
while (classToCheck != Object.class) {
// check to see if we have what we are looking for on our CURRENT class interfaces
Type[] genericInterfaces = classToCheck.getGenericInterfaces();
for (Type genericInterface : genericInterfaces) {
- if (genericInterface instanceof ParameterizedType) {
- Type[] actualTypeArguments = ((ParameterizedType) genericInterface).getActualTypeArguments();
- // is it possible?
- if (actualTypeArguments.length > genericParameterToGet) {
- Class> rawTypeAsClass = ClassHelper.getRawTypeAsClass(actualTypeArguments[genericParameterToGet]);
- return rawTypeAsClass;
- }
- else {
- // record the parameters.
- }
+
+ classes = TypeResolver.resolveRawArguments(genericInterface, classToCheck);
+ if (classes.length > genericParameterToGet && classes[genericParameterToGet] != TypeResolver.Unknown.class) {
+ return classes[genericParameterToGet];
}
}
@@ -78,76 +75,30 @@ class ClassHelper {
classToCheck = classToCheck.getSuperclass();
}
-
// couldn't find it.
return null;
}
/**
- * Return the class that is this type.
- */
- @SuppressWarnings("UnnecessaryLocalVariable")
- public static
- Class> getRawTypeAsClass(Type type) {
- if (type instanceof Class) {
- Class> class1 = (Class>) type;
-
-// if (class1.isArray()) {
-// System.err.println("CLASS IS ARRAY TYPE: SHOULD WE DO ANYTHING WITH IT? " + class1.getSimpleName());
-// return class1.getComponentType();
-// } else {
- return class1;
-// }
- }
- else if (type instanceof GenericArrayType) {
- // note: cannot have primitive types here, only objects that are arrays (byte[], Integer[], etc)
- Type type2 = ((GenericArrayType) type).getGenericComponentType();
- Class> rawType = getRawTypeAsClass(type2);
-
- return Array.newInstance(rawType, 0)
- .getClass();
- }
- else if (type instanceof ParameterizedType) {
- // we cannot use parameterized types, because java can't go between classes and ptypes - and this
- // going "in-between" is the magic -- and value -- of this entire infrastructure.
- // return the type.
-
- return (Class>) ((ParameterizedType) type).getRawType();
-
-// Type[] actualTypeArguments = ((ParameterizedType) type).getActualTypeArguments();
-// return (Class>) actualTypeArguments[0];
- }
- else if (type instanceof TypeVariable) {
- // we have a COMPLEX type parameter
- Type[] bounds = ((TypeVariable>) type).getBounds();
- if (bounds.length > 0) {
- return getRawTypeAsClass(bounds[0]);
- }
- }
-
- throw new RuntimeException("Unknown/messed up type parameter . Can't figure it out... Quit being complex!");
- }
-
- /**
- * Check to see if clazz or interface directly has one of the interfaces defined by clazzItMustHave
+ * Check to see if clazz or interface directly has one of the interfaces defined by requiredClass
*
* If the class DOES NOT directly have the interface it will fail.
*/
public static
- boolean hasInterface(Class> clazzItMustHave, Class> clazz) {
- if (clazzItMustHave == clazz) {
+ boolean hasInterface(Class> requiredClass, Class> clazz) {
+ if (requiredClass == clazz) {
return true;
}
Class>[] interfaces = clazz.getInterfaces();
for (Class> iface : interfaces) {
- if (iface == clazzItMustHave) {
+ if (iface == requiredClass) {
return true;
}
}
// now walk up to see if we can find it.
for (Class> iface : interfaces) {
- boolean b = hasInterface(clazzItMustHave, iface);
+ boolean b = hasInterface(requiredClass, iface);
if (b) {
return b;
}
@@ -160,7 +111,7 @@ class ClassHelper {
// don't check for Object.class (this is where superclass is null)
while (superClass != null && superClass != Object.class) {
// check to see if we have what we are looking for on our CURRENT class
- if (hasInterface(clazzItMustHave, superClass)) {
+ if (hasInterface(requiredClass, superClass)) {
return true;
}
diff --git a/src/dorkbox/util/TypeResolver.java b/src/dorkbox/util/TypeResolver.java
new file mode 100644
index 0000000..2ccf777
--- /dev/null
+++ b/src/dorkbox/util/TypeResolver.java
@@ -0,0 +1,616 @@
+/*
+ * Copyright 2002-2017 Jonathan Halterman
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * From: https://github.com/jhalterman/typetools
+ */
+package dorkbox.util;
+
+import java.lang.ref.Reference;
+import java.lang.ref.WeakReference;
+import java.lang.reflect.AccessibleObject;
+import java.lang.reflect.Array;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.GenericArrayType;
+import java.lang.reflect.Member;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.lang.reflect.TypeVariable;
+import java.security.AccessController;
+import java.security.PrivilegedExceptionAction;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.WeakHashMap;
+
+import sun.misc.Unsafe;
+
+/**
+ * Enhanced type resolution utilities.
+ *
+ * @author Jonathan Halterman
+ */
+@SuppressWarnings("restriction")
+public final
+class TypeResolver {
+ /**
+ * Cache of type variable/argument pairs
+ */
+ private static final Map, Reference