/** Create a name for the given class. The resulting name will be in a resolved state. */ public MemberName(Class<?> type) { init( type.getDeclaringClass(), type.getSimpleName(), type, flagsMods(IS_TYPE, type.getModifiers())); vmindex = 0; // isResolved assert (isResolved()); }
/*non-public*/ static boolean canConvert(Class<?> src, Class<?> dst) { // short-circuit a few cases: if (src == dst || dst == Object.class) return true; // the remainder of this logic is documented in MethodHandle.asType if (src.isPrimitive()) { // can force void to an explicit null, a la reflect.Method.invoke // can also force void to a primitive zero, by analogy if (src == void.class) return true; // or !dst.isPrimitive()? Wrapper sw = Wrapper.forPrimitiveType(src); if (dst.isPrimitive()) { // P->P must widen return Wrapper.forPrimitiveType(dst).isConvertibleFrom(sw); } else { // P->R must box and widen return dst.isAssignableFrom(sw.wrapperType()); } } else if (dst.isPrimitive()) { // any value can be dropped if (dst == void.class) return true; Wrapper dw = Wrapper.forPrimitiveType(dst); // R->P must be able to unbox (from a dynamically chosen type) and widen // For example: // Byte/Number/Comparable/Object -> dw:Byte -> byte. // Character/Comparable/Object -> dw:Character -> char // Boolean/Comparable/Object -> dw:Boolean -> boolean // This means that dw must be cast-compatible with src. if (src.isAssignableFrom(dw.wrapperType())) { return true; } // The above does not work if the source reference is strongly typed // to a wrapper whose primitive must be widened. For example: // Byte -> unbox:byte -> short/int/long/float/double // Character -> unbox:char -> int/long/float/double if (Wrapper.isWrapperType(src) && dw.isConvertibleFrom(Wrapper.forWrapperType(src))) { // can unbox from src and then widen to dst return true; } // We have already covered cases which arise due to runtime unboxing // of a reference type which covers several wrapper types: // Object -> cast:Integer -> unbox:int -> long/float/double // Serializable -> cast:Byte -> unbox:byte -> byte/short/int/long/float/double // An marginal case is Number -> dw:Character -> char, which would be OK if there were a // subclass of Number which wraps a value that can convert to char. // Since there is none, we don't need an extra check here to cover char or boolean. return false; } else { // R->R always works, since null is always valid dynamically return true; } }
/** * Produce a resolved version of the given member. Super types are searched (for inherited * members) if {@code searchSupers} is true. Access checking is performed on behalf of the given * {@code lookupClass}. If lookup fails or access is not permitted, a {@linkplain * ReflectiveOperationException} is thrown. Otherwise a fresh copy of the given member is * returned, with modifier bits filled in. */ public <NoSuchMemberException extends ReflectiveOperationException> MemberName resolveOrFail( MemberName m, boolean searchSupers, Class<?> lookupClass, Class<NoSuchMemberException> nsmClass) throws IllegalAccessException, NoSuchMemberException { MemberName result = resolveOrNull(m, searchSupers, lookupClass); if (result != null) return result; ReflectiveOperationException ex = m.makeAccessException("no access"); if (ex instanceof IllegalAccessException) throw (IllegalAccessException) ex; throw nsmClass.cast(ex); }
/** * Returns a string representation of the method type, of the form {@code "(PT0,PT1...)RT"}. The * string representation of a method type is a parenthesis enclosed, comma separated list of type * names, followed immediately by the return type. * * <p>Each type is represented by its {@link java.lang.Class#getSimpleName simple name}. */ @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append("("); for (int i = 0; i < ptypes.length; i++) { if (i > 0) sb.append(","); sb.append(ptypes[i].getSimpleName()); } sb.append(")"); sb.append(rtype.getSimpleName()); return sb.toString(); }
/** Utility method producing the class loader of the declaring class. */ public ClassLoader getClassLoader() { return clazz.getClassLoader(); }
/** * Returns the hash code value for this method type. It is defined to be the same as the hashcode * of a List whose elements are the return type followed by the parameter types. * * @return the hash code value for this method type * @see Object#hashCode() * @see #equals(Object) * @see List#hashCode() */ @Override public int hashCode() { int hashCode = 31 + rtype.hashCode(); for (Class<?> ptype : ptypes) hashCode = 31 * hashCode + ptype.hashCode(); return hashCode; }
private static int checkPtype(Class<?> ptype) { ptype.getClass(); // NPE if (ptype == void.class) throw newIllegalArgumentException("parameter type cannot be void"); if (ptype == double.class || ptype == long.class) return 1; return 0; }
private static void checkRtype(Class<?> rtype) { rtype.equals(rtype); // null check }