diff --git a/src/com/massivecraft/massivecore/command/type/RegistryType.java b/src/com/massivecraft/massivecore/command/type/RegistryType.java index 71f74c7f..952bd07a 100644 --- a/src/com/massivecraft/massivecore/command/type/RegistryType.java +++ b/src/com/massivecraft/massivecore/command/type/RegistryType.java @@ -4,7 +4,6 @@ import java.lang.reflect.Field; import java.lang.reflect.ParameterizedType; import java.util.List; import java.util.Map; -import java.util.Map.Entry; import java.util.Set; import com.massivecraft.massivecore.collections.ExceptionSet; @@ -127,28 +126,28 @@ public class RegistryType { if (fieldType instanceof ParameterizedType) { - Class fieldClass = field.getType(); + Class fieldClass = field == null ? null : field.getType(); List> innerTypes; - if (List.class.isAssignableFrom(fieldClass)) + if (ReflectionUtil.isRawTypeAssignableFromAny(List.class, fieldType, fieldClass)) { innerTypes = getInnerTypes(field, fieldType, 1); return TypeList.get(innerTypes.get(0)); } - if (Set.class.isAssignableFrom(fieldClass)) + if (ReflectionUtil.isRawTypeAssignableFromAny(Set.class, fieldType, fieldClass)) { innerTypes = getInnerTypes(field, fieldType, 1); return TypeSet.get(innerTypes.get(0)); } - if (Entry.class.isAssignableFrom(fieldClass)) + if (ReflectionUtil.isRawTypeAssignableFromAny(Map.Entry.class, fieldType, fieldClass)) { innerTypes = getInnerTypes(field, fieldType, 2); return TypeEntry.get(innerTypes.get(0), innerTypes.get(1)); } - if (Map.class.isAssignableFrom(fieldClass)) + if (ReflectionUtil.isRawTypeAssignableFromAny(Map.class, fieldType, fieldClass)) { innerTypes = getInnerTypes(field, fieldType, 2); return TypeMap.get(innerTypes.get(0), innerTypes.get(1)); diff --git a/src/com/massivecraft/massivecore/util/ReflectionUtil.java b/src/com/massivecraft/massivecore/util/ReflectionUtil.java index 011abdc0..b813e99d 100644 --- a/src/com/massivecraft/massivecore/util/ReflectionUtil.java +++ b/src/com/massivecraft/massivecore/util/ReflectionUtil.java @@ -3,9 +3,13 @@ package com.massivecraft.massivecore.util; import java.lang.annotation.Annotation; import java.lang.reflect.Constructor; import java.lang.reflect.Field; +import java.lang.reflect.GenericDeclaration; import java.lang.reflect.InvocationTargetException; 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.util.ArrayList; import java.util.List; @@ -488,4 +492,46 @@ public class ReflectionUtil } } + // -------------------------------------------- // + // TYPE CHECKS + // -------------------------------------------- // + + public static boolean isRawTypeAssignableFromAny(Type goal, Type... subjects) + { + // Cache this value since it will save us calculations + Class classGoal = classify(goal); + + for (Type t: subjects) + { + if (isRawTypeAssignableFrom(classGoal, t)) return true; + } + return false; + } + + public static boolean isRawTypeAssignableFrom(Type a, Type b) + { + if (a == null || b == null) return false; + + // Yes, this is a different sense of "Classifying" + Class classifiedA = classify(a); + Class classifiedB = classify(b); + + // In case one of the methods failed to retrieve a class + if (classifiedA == null || classifiedB == null) return a.equals(b); + + return classifiedA.isAssignableFrom(classifiedB); + } + + private static Class classify(Type type) + { + // Use loop structure rather than recursion to avoid stack size issues + while (!(type instanceof Class)) + { + // Check for parameterized type + if (!(type instanceof ParameterizedType)) return null; + type = ((ParameterizedType) type).getRawType(); + } + return (Class) type; + } + }