📄 proxy.java
字号:
* @return the invocation handler, guaranteed non-null. * @throws IllegalArgumentException if * <code>Proxy.isProxyClass(proxy.getClass())</code> returns false. * @throws NullPointerException if proxy is null */ public static InvocationHandler getInvocationHandler(Object proxy) { if (! isProxyClass(proxy.getClass())) throw new IllegalArgumentException("not a proxy instance"); return ((Proxy) proxy).h; } /** * Helper class for mapping unique ClassLoader and interface combinations * to proxy classes. * * @author Eric Blake (ebb9@email.byu.edu) */ private static final class ProxyType { /** * Store the class loader (may be null) */ final ClassLoader loader; /** * Store the interfaces (never null, all elements are interfaces) */ final Class[] interfaces; /** * Construct the helper object. * * @param loader the class loader to define the proxy class in; null * implies the bootstrap class loader * @param interfaces an array of interfaces */ ProxyType(ClassLoader loader, Class[] interfaces) { this.loader = loader; this.interfaces = interfaces; } /** * Calculates the hash code. * * @return a combination of the classloader and interfaces hashcodes. */ public int hashCode() { int hash = loader == null ? 0 : loader.hashCode(); for (int i = 0; i < interfaces.length; i++) hash = hash * 31 + interfaces[i].hashCode(); return hash; } /** * Calculates equality. * * @param other object to compare to * @return true if it is a ProxyType with same data */ public boolean equals(Object other) { ProxyType pt = (ProxyType) other; if (loader != pt.loader || interfaces.length != pt.interfaces.length) return false; for (int i = 0; i < interfaces.length; i++) if (interfaces[i] != pt.interfaces[i]) return false; return true; } } // class ProxyType /** * Helper class which allows hashing of a method name and signature * without worrying about return type, declaring class, or throws clause, * and which reduces the maximally common throws clause between two methods * * @author Eric Blake (ebb9@email.byu.edu) */ private static final class ProxySignature { /** * The core signatures which all Proxy instances handle. */ static final HashMap coreMethods = new HashMap(); static { try { ProxySignature sig = new ProxySignature(Object.class .getMethod("equals", new Class[] {Object.class})); coreMethods.put(sig, sig); sig = new ProxySignature(Object.class.getMethod("hashCode", null)); coreMethods.put(sig, sig); sig = new ProxySignature(Object.class.getMethod("toString", null)); coreMethods.put(sig, sig); } catch (Exception e) { // assert false; throw (Error) new InternalError("Unexpected: " + e).initCause(e); } } /** * The underlying Method object, never null */ final Method method; /** * The set of compatible thrown exceptions, may be empty */ final Set exceptions = new HashSet(); /** * Construct a signature * * @param method the Method this signature is based on, never null */ ProxySignature(Method method) { this.method = method; Class[] exc = method.getExceptionTypes(); int i = exc.length; while (--i >= 0) { // discard unchecked exceptions if (Error.class.isAssignableFrom(exc[i]) || RuntimeException.class.isAssignableFrom(exc[i])) continue; exceptions.add(exc[i]); } } /** * Given a method, make sure it's return type is identical * to this, and adjust this signature's throws clause appropriately * * @param other the signature to merge in * @throws IllegalArgumentException if the return types conflict */ void checkCompatibility(ProxySignature other) { if (method.getReturnType() != other.method.getReturnType()) throw new IllegalArgumentException("incompatible return types: " + method + ", " + other.method); // if you can think of a more efficient way than this O(n^2) search, // implement it! int size1 = exceptions.size(); int size2 = other.exceptions.size(); boolean[] valid1 = new boolean[size1]; boolean[] valid2 = new boolean[size2]; Iterator itr = exceptions.iterator(); int pos = size1; while (--pos >= 0) { Class c1 = (Class) itr.next(); Iterator itr2 = other.exceptions.iterator(); int pos2 = size2; while (--pos2 >= 0) { Class c2 = (Class) itr2.next(); if (c2.isAssignableFrom(c1)) valid1[pos] = true; if (c1.isAssignableFrom(c2)) valid2[pos2] = true; } } pos = size1; itr = exceptions.iterator(); while (--pos >= 0) { itr.next(); if (! valid1[pos]) itr.remove(); } pos = size2; itr = other.exceptions.iterator(); while (--pos >= 0) { itr.next(); if (! valid2[pos]) itr.remove(); } exceptions.addAll(other.exceptions); } /** * Calculates the hash code. * * @return a combination of name and parameter types */ public int hashCode() { int hash = method.getName().hashCode(); Class[] types = method.getParameterTypes(); for (int i = 0; i < types.length; i++) hash = hash * 31 + types[i].hashCode(); return hash; } /** * Calculates equality. * * @param other object to compare to * @return true if it is a ProxySignature with same data */ public boolean equals(Object other) { ProxySignature ps = (ProxySignature) other; Class[] types1 = method.getParameterTypes(); Class[] types2 = ps.method.getParameterTypes(); if (! method.getName().equals(ps.method.getName()) || types1.length != types2.length) return false; int i = types1.length; while (--i >= 0) if (types1[i] != types2[i]) return false; return true; } } // class ProxySignature /** * A flat representation of all data needed to generate bytecode/instantiate * a proxy class. This is basically a struct. * * @author Eric Blake (ebb9@email.byu.edu) */ static final class ProxyData { /** * The package this class is in <b>including the trailing dot</b> * or an empty string for the unnamed (aka default) package. */ String pack = ""; /** * The interfaces this class implements. Non-null, but possibly empty. */ Class[] interfaces; /** * The Method objects this class must pass as the second argument to * invoke (also useful for determining what methods this class has). * Non-null, non-empty (includes at least Object.hashCode, Object.equals, * and Object.toString). */ Method[] methods; /** * The exceptions that do not need to be wrapped in * UndeclaredThrowableException. exceptions[i] is the same as, or a * subset of subclasses, of methods[i].getExceptionTypes(), depending on * compatible throws clauses with multiple inheritance. It is unspecified * if these lists include or exclude subclasses of Error and * RuntimeException, but excluding them is harmless and generates a * smaller class. */ Class[][] exceptions; /** * For unique id's */ private static int count; /** * The id of this proxy class */ final int id = count++; /** * Construct a ProxyData with uninitialized data members. */ ProxyData() { } /** * Return the name of a package (including the trailing dot) * given the name of a class. * Returns an empty string if no package. We use this in preference to * using Class.getPackage() to avoid problems with ClassLoaders * that don't set the package. */ private static String getPackage(Class k) { String name = k.getName(); int idx = name.lastIndexOf('.'); return name.substring(0, idx + 1); } /** * Verifies that the arguments are legal, and sets up remaining data * This should only be called when a class must be generated, as * it is expensive. * * @param pt the ProxyType to convert to ProxyData * @return the flattened, verified ProxyData structure for use in * class generation * @throws IllegalArgumentException if `interfaces' contains * non-interfaces or incompatible combinations, and verify is true * @throws NullPointerException if interfaces is null or contains null */ static ProxyData getProxyData(ProxyType pt) { Map method_set = (Map) ProxySignature.coreMethods.clone(); boolean in_package = false; // true if we encounter non-public interface ProxyData data = new ProxyData(); data.interfaces = pt.interfaces; // if interfaces is too large, we croak later on when the constant // pool overflows int i = data.interfaces.length; while (--i >= 0) { Class inter = data.interfaces[i]; if (! inter.isInterface()) throw new IllegalArgumentException("not an interface: " + inter); try { if (Class.forName(inter.getName(), false, pt.loader) != inter) throw new IllegalArgumentException("not accessible in " + "classloader: " + inter); } catch (ClassNotFoundException e) { throw new IllegalArgumentException("not accessible in " + "classloader: " + inter); } if (! Modifier.isPublic(inter.getModifiers())) if (in_package) { String p = getPackage(inter); if (! data.pack.equals(p)) throw new IllegalArgumentException("non-public interfaces " + "from different " + "packages"); } else { in_package = true; data.pack = getPackage(inter); } for (int j = i-1; j >= 0; j--) if (data.interfaces[j] == inter) throw new IllegalArgumentException("duplicate interface: " + inter); Method[] methods = inter.getMethods(); int j = methods.length; while (--j >= 0) { ProxySignature sig = new ProxySignature(methods[j]); ProxySignature old = (ProxySignature) method_set.put(sig, sig); if (old != null) sig.checkCompatibility(old); } } i = method_set.size(); data.methods = new Method[i]; data.exceptions = new Class[i][]; Iterator itr = method_set.values().iterator(); while (--i >= 0) { ProxySignature sig = (ProxySignature) itr.next(); data.methods[i] = sig.method; data.exceptions[i] = (Class[]) sig.exceptions .toArray(new Class[sig.exceptions.size()]); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -