/** * Checks if the subject type may be implicitly cast to the target parameterized type following * the Java generics rules. * * @param type the subject type to be assigned to the target type * @param toParameterizedType the target parameterized type * @return true if <code>type</code> is assignable to <code>toType</code>. */ private static boolean isAssignable( Type type, ParameterizedType toParameterizedType, Map<TypeVariable<?>, Type> typeVarAssigns) { if (type == null) { return true; } // only a null type can be assigned to null type which // would have cause the previous to return true if (toParameterizedType == null) { return false; } // all types are assignable to themselves if (toParameterizedType.equals(type)) { return true; } // get the target type's raw type Class<?> toClass = getRawType(toParameterizedType); // get the subject type's type arguments including owner type arguments // and supertype arguments up to and including the target class. Map<TypeVariable<?>, Type> fromTypeVarAssigns = getTypeArguments(type, toClass, null); // null means the two types are not compatible if (fromTypeVarAssigns == null) { return false; } // compatible types, but there's no type arguments. this is equivalent // to comparing Map< ?, ? > to Map, and raw types are always assignable // to parameterized types. if (fromTypeVarAssigns.isEmpty()) { return true; } // get the target type's type arguments including owner type arguments Map<TypeVariable<?>, Type> toTypeVarAssigns = getTypeArguments(toParameterizedType, toClass, typeVarAssigns); // now to check each type argument for (Map.Entry<TypeVariable<?>, Type> entry : toTypeVarAssigns.entrySet()) { Type toTypeArg = entry.getValue(); Type fromTypeArg = fromTypeVarAssigns.get(entry.getKey()); // parameters must either be absent from the subject type, within // the bounds of the wildcard type, or be an exact match to the // parameters of the target type. if (fromTypeArg != null && !toTypeArg.equals(fromTypeArg) && !(toTypeArg instanceof WildcardType && isAssignable(fromTypeArg, toTypeArg, typeVarAssigns))) { return false; } } return true; }
/** Private recursive helper function to actually do the type-safe checking of assignability. */ private static boolean isAssignableFrom( Type from, ParameterizedType to, Map<String, Type> typeVarMap) { if (from == null) { return false; } if (to.equals(from)) { return true; } // First figure out the class and any type information. Class<?> clazz = getRawType(from); ParameterizedType ptype = null; if (from instanceof ParameterizedType) { ptype = (ParameterizedType) from; } // Load up parameterized variable info if it was parameterized. if (ptype != null) { Type[] tArgs = ptype.getActualTypeArguments(); TypeVariable<?>[] tParams = clazz.getTypeParameters(); for (int i = 0; i < tArgs.length; i++) { Type arg = tArgs[i]; TypeVariable<?> var = tParams[i]; while (arg instanceof TypeVariable) { TypeVariable<?> v = (TypeVariable<?>) arg; arg = typeVarMap.get(v.getName()); } typeVarMap.put(var.getName(), arg); } // check if they are equivalent under our current mapping. if (typeEquals(ptype, to, typeVarMap)) { return true; } } for (Type itype : clazz.getGenericInterfaces()) { if (isAssignableFrom(itype, to, new HashMap<String, Type>(typeVarMap))) { return true; } } // Interfaces didn't work, try the superclass. Type sType = clazz.getGenericSuperclass(); if (isAssignableFrom(sType, to, new HashMap<String, Type>(typeVarMap))) { return true; } return false; }
private static boolean isAssignable( Type paramType, ParameterizedType paramParameterizedType, Map paramMap) { if (paramType == null) return true; if (paramParameterizedType == null) return false; if (paramParameterizedType.equals(paramType)) return true; Class localClass = getRawType(paramParameterizedType); Map localMap = getTypeArguments(paramType, localClass, null); if (localMap == null) return false; if (localMap.isEmpty()) return true; Iterator localIterator = getTypeArguments(paramParameterizedType, localClass, paramMap).entrySet().iterator(); while (localIterator.hasNext()) { Map.Entry localEntry = (Map.Entry) localIterator.next(); Type localType1 = (Type) localEntry.getValue(); Type localType2 = (Type) localMap.get(localEntry.getKey()); if ((localType2 != null) && (!localType1.equals(localType2)) && ((!(localType1 instanceof WildcardType)) || (!isAssignable(localType2, localType1, paramMap)))) return false; } return true; }
private static boolean isAssignableFrom(Type object, ParameterizedType parameterizedType, Map<String, Type> map) { int n2; if (object == null) { return false; } if (parameterizedType.equals(object)) { return true; } Class class_ = $Gson$Types.getRawType((Type)object); ParameterizedType parameterizedType2 = null; if (object instanceof ParameterizedType) { parameterizedType2 = (ParameterizedType)object; } if (parameterizedType2 != null) { Type[] arrtype = parameterizedType2.getActualTypeArguments(); TypeVariable<Class<?>>[] arrtypeVariable = class_.getTypeParameters(); for (n2 = 0; n2 < arrtype.length; ++n2) { object = arrtype[n2]; TypeVariable typeVariable = arrtypeVariable[n2]; while (object instanceof TypeVariable) { object = map.get(((TypeVariable)object).getName()); } map.put(typeVariable.getName(), (Type)object); } if (TypeToken.typeEquals(parameterizedType2, parameterizedType, map)) { return true; } } object = class_.getGenericInterfaces(); int n3 = object.length; for (n2 = 0; n2 < n3; ++n2) { if (!TypeToken.isAssignableFrom(object[n2], parameterizedType, new HashMap<String, Type>(map))) continue; return true; } return TypeToken.isAssignableFrom(class_.getGenericSuperclass(), parameterizedType, new HashMap<String, Type>(map)); }