📄 proxy.java
字号:
* @return the generated proxy class * @throws IllegalArgumentException if the constraints for getProxyClass * were violated, except for problems with null * @throws NullPointerException if `interfaces' is null or contains * a null entry, or if handler is null * @see Configuration#HAVE_NATIVE_GET_PROXY_CLASS * @see #getProxyClass(ClassLoader, Class[]) * @see #getProxyData0(ClassLoader, Class[]) * @see #generateProxyClass0(ProxyData) */ private static native Class getProxyClass0(ClassLoader loader, Class[] interfaces); /** * Optional native method to replace (and speed up) the pure Java * implementation of getProxyData. Only needed if * Configuration.HAVE_NATIVE_GET_PROXY_DATA is true. The native code * may safely assume that a new ProxyData object must be created which * does not duplicate any existing ones. * * @param loader the class loader to define the proxy class in; null * implies the bootstrap class loader * @param interfaces the interfaces the class will extend * @return all data that is required to make this proxy class * @throws IllegalArgumentException if the constraints for getProxyClass * were violated, except for problems with null * @throws NullPointerException if `interfaces' is null or contains * a null entry, or if handler is null * @see Configuration.HAVE_NATIVE_GET_PROXY_DATA * @see #getProxyClass(ClassLoader, Class[]) * @see #getProxyClass0(ClassLoader, Class[]) * @see ProxyType#getProxyData() */ private static native ProxyData getProxyData0(ClassLoader loader, Class[] interfaces); /** * Optional native method to replace (and speed up) the pure Java * implementation of generateProxyClass. Only needed if * Configuration.HAVE_NATIVE_GENERATE_PROXY_CLASS is true. The native * code may safely assume that a new Class must be created, and that * the ProxyData object does not describe any existing class. * * @param loader the class loader to define the proxy class in; null * implies the bootstrap class loader * @param data the struct of information to convert to a Class. This * has already been verified for all problems except exceeding * VM limitations * @return the newly generated class * @throws IllegalArgumentException if VM limitations are exceeded * @see #getProxyClass(ClassLoader, Class[]) * @see #getProxyClass0(ClassLoader, Class[]) * @see ProxyData#generateProxyClass(ClassLoader) */ private static native Class generateProxyClass0(ClassLoader loader, ProxyData data); /** * 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) { if (loader == null) loader = ClassLoader.getSystemClassLoader(); this.loader = loader; this.interfaces = interfaces; } /** * Calculates the hash code. * * @return a combination of the classloader and interfaces hashcodes. */ public int hashCode() { //loader is always not null int hash = loader.hashCode(); for (int i = 0; i < interfaces.length; i++) hash = hash * 31 + interfaces[i].hashCode(); return hash; } // A more comprehensive comparison of two arrays, // ignore array element order, and // ignore redundant elements private static boolean sameTypes(Class arr1[], Class arr2[]) { if (arr1.length == 1 && arr2.length == 1) { return arr1[0] == arr2[0]; } // total occurrance of elements of arr1 in arr2 int total_occ_of_arr1_in_arr2 = 0; each_type: for (int i = arr1.length; --i >= 0; ) { Class t = arr1[i]; for (int j = i; --j >= 0; ) { if (t == arr1[j]) { //found duplicate type continue each_type; } } // count c(a unique element of arr1)'s // occurrences in arr2 int occ_in_arr2 = 0; for (int j = arr2.length; --j >= 0; ) { if (t == arr2[j]) { ++occ_in_arr2; } } if (occ_in_arr2 == 0) { // t does not occur in arr2 return false; } total_occ_of_arr1_in_arr2 += occ_in_arr2; } // now, each element of arr2 must have been visited return total_occ_of_arr1_in_arr2 == arr2.length; } /** * Calculates equality. * * @param the 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; return sameTypes(interfaces, pt.interfaces); } } // 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 the 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> */ private static final class ProxyData { /** * The package this class is in. Possibly null, meaning the unnamed * package. */ Package 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 = 0; /** * The id of this proxy class */ final int id = count++; /** * Construct a ProxyData with uninitialized data members. */ ProxyData() { } /** * 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) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -