Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Copyright (c) 2015, RoboVM AB. All Rights Reserved.
*
* Redistribution and use is subject to the RoboVM Software License terms
* available at (http://robovm.com)
*
* This notice and attribution to RoboVM AB may not be removed.
*/
package org.robovm.rt;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Proxy;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
/**
* {@code ClassProxy} defines methods for creating dynamic proxy classes. Unlike
* {@link Proxy} the proxies created by {@link ClassProxy} extend from a
* specified superclass. Proxy classes created by {@link ClassProxy} delegates
* non-final superclass method and interface method invocations to an
* {@link InvocationHandler}. Unlike {@link Proxy} the {@link Method} passed to
* {@link InvocationHandler#invoke(Object, Method, Object[])} represents the
* method on the generated class. Use {@link #getProxiedMethod(Method)} to get
* the overridden superclass method or interface method. Use
* {@link #invokeSuper(Method, Object, Object...)} to forward the call to the
* superclass method implementation.
*/
public class ClassProxy {
private static final Object[] EMPTY_ARGS = new Object[0];
private static final Class[] EMPTY_INTERFACES = new Class[0];
private static class CacheKey {
private final Class superclass;
private final Class[] interfaces;
private final InvocationHandler handler;
public CacheKey(Class superclass, Class[] interfaces, InvocationHandler handler) {
this.superclass = superclass;
this.interfaces = interfaces;
this.handler = handler;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((handler == null) ? 0 : handler.hashCode());
result = prime * result + Arrays.hashCode(interfaces);
result = prime * result + ((superclass == null) ? 0 : superclass.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
CacheKey other = (CacheKey) obj;
if (handler == null) {
if (other.handler != null) {
return false;
}
} else if (handler != other.handler) {
return false;
}
if (!Arrays.equals(interfaces, other.interfaces)) {
return false;
}
if (superclass == null) {
if (other.superclass != null) {
return false;
}
} else if (!superclass.equals(other.superclass)) {
return false;
}
return true;
}
}
// maps class loaders to created classes
private static final HashMap>> loaderCache = new HashMap<>();
// to find previously created types
private static final HashSet> proxyCache = new HashSet<>();
private static int nextClassNameIndex = 0;
/**
* Returns a proxy {@code Class} extending from the specified superclass and
* implementing the specified interfaces. The order of the interfaces is
* relevant. Invocations of this method with the same interfaces but
* different order result in different generated classes. The interfaces
* must be visible from the supplied class loader; no duplicates are
* permitted. All non-public interfaces must be defined in the same package.
*
* @param loader the class loader that will define the proxy {@link Class}.
* @param handler the {@link InvocationHandler} which will be called for any
* invocation on the generated proxy {@link Class}.
* @param interfaces an array of {@code Class} objects, each one identifying
* an interface that will be implemented by the returned proxy
* class.
* @return a proxy {@link Class} that implements all of the interfaces
* referred to in the contents of {@code interfaces}.
* @throws IllegalArgumentException if the superclass cannot be extended or
* if any of the interface restrictions are violated.
* @throws NullPointerException if either {@code superclass},
* {@code interfaces} or any of its elements are {@code null}.
*/
public static Class getProxyClass(ClassLoader loader, InvocationHandler handler, Class superclass,
Class... interfaces) throws IllegalArgumentException {
if (superclass == null) {
throw new NullPointerException("superclass == null");
}
if (superclass.isPrimitive()) {
throw new IllegalArgumentException("Cannot create proxy with primitive class " + superclass.getName()
+ " as superclass");
}
if (superclass.isArray()) {
throw new IllegalArgumentException("Cannot create proxy with array class " + superclass.getName()
+ " as superclass");
}
if (superclass.isInterface()) {
throw new IllegalArgumentException("Cannot create proxy with interface class " + superclass.getName()
+ " as superclass");
}
if (Modifier.isFinal(superclass.getModifiers())) {
throw new IllegalArgumentException("Superclass " + superclass.getName() + " is final");
}
if (loader != superclass.getClassLoader()) {
try {
if (superclass != Class.forName(superclass.getName(), false, loader)) {
throw new IllegalArgumentException("Superclass " + superclass.getName() +
" is not visible from class loader");
}
} catch (ClassNotFoundException ex) {
throw new IllegalArgumentException("Superclass " + superclass.getName() +
" is not visible from class loader");
}
}
if (handler == null) {
throw new NullPointerException("handler == null");
}
if (interfaces == null) {
interfaces = EMPTY_INTERFACES;
}
String commonPackageName = null;
if (!Modifier.isPublic(superclass.getModifiers()) || interfaces.length == 0) {
commonPackageName = getPackageName(superclass);
}
for (int i = 0, length = interfaces.length; i < length; i++) {
Class next = interfaces[i];
if (next == null) {
throw new NullPointerException("interfaces[" + i + "] == null");
}
String name = next.getName();
if (!next.isInterface()) {
throw new IllegalArgumentException(name + " is not an interface");
}
if (loader != next.getClassLoader()) {
try {
if (next != Class.forName(name, false, loader)) {
throw new IllegalArgumentException(name +
" is not visible from class loader");
}
} catch (ClassNotFoundException ex) {
throw new IllegalArgumentException(name + " is not visible from class loader");
}
}
for (int j = i + 1; j < length; j++) {
if (next == interfaces[j]) {
throw new IllegalArgumentException(name + " appears more than once");
}
}
if (!Modifier.isPublic(next.getModifiers())) {
int last = name.lastIndexOf('.');
String p = last == -1 ? "" : name.substring(0, last);
if (commonPackageName == null) {
commonPackageName = p;
} else if (!commonPackageName.equals(p)) {
throw new IllegalArgumentException("non-public interfaces must be " +
"in the same package");
}
}
}
// search cache for matching proxy class using the class loader
synchronized (loaderCache) {
Map> cache = loaderCache.get(loader);
if (cache == null) {
cache = new HashMap>();
loaderCache.put(loader, cache);
}
CacheKey cacheKey = new CacheKey(superclass, interfaces, handler);
@SuppressWarnings("unchecked") Class newClass = (Class) cache.get(cacheKey);
if (newClass == null) {
String className = superclass.getName() + "$$ClassProxy" + nextClassNameIndex++;
if (loader == null) {
loader = ClassLoader.getSystemClassLoader();
}
newClass = generateProxy(className.replace('.', '/'), superclass, interfaces, loader, handler);
cache.put(cacheKey, newClass);
synchronized (proxyCache) {
proxyCache.add(newClass);
}
}
return newClass;
}
}
private static String getPackageName(Class cls) {
String name = cls.getName();
int last = name.lastIndexOf('.');
String p = last == -1 ? "" : name.substring(0, last);
return p;
}
/**
* Returns whether or not the specified class is a proxy {@link Class}
* created by
* {@link #getProxyClass(ClassLoader, InvocationHandler, Class, Class...)}.
*
* @param cl the class.
* @return {@code true} if the class is a proxy class, {@code false}
* otherwise.
* @throws NullPointerException if the class is {@code null}.
*/
public static boolean isProxyClass(Class cl) {
if (cl == null) {
throw new NullPointerException("cl == null");
}
synchronized (proxyCache) {
return proxyCache.contains(cl);
}
}
/**
* Returns the {@link InvocationHandler} associated with the specified proxy
* {@link Class}.
*/
public static InvocationHandler getInvocationHandler(Class cls)
throws IllegalArgumentException {
if (isProxyClass(cls)) {
return getInvocationHandler0(cls);
}
throw new IllegalArgumentException("not a proxy class");
}
/**
* Given a proxy {@link Method} returns the proxied {@link Method}.
*/
public static Method getProxiedMethod(Method method) {
if (!isProxyClass(method.getDeclaringClass())) {
throw new IllegalArgumentException("Not a proxy class method: " + method);
}
return getProxiedMethod0(method);
}
/**
* Invokes the super method of the specified proxy {@link Method} on the
* specified receiver object.
*
* @param method the proxy method.
* @param receiver the receiver. Must not be {@code null}.
* @param args method arguments.
* @return the result of the invocation. Primitives are boxed. Returns
* {@code null} if method has no return type ({@code void}).
*/
public static Object invokeSuper(Method method, Object receiver, Object... args)
throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
if (receiver == null) {
throw new NullPointerException("receiver == null");
}
if (!isProxyClass(method.getDeclaringClass())) {
throw new IllegalArgumentException("Not a proxy class method: " + method);
}
if (method.getDeclaringClass() != receiver.getClass()) {
StringBuilder sb = new StringBuilder();
sb.append("expected receiver of type ")
.append(method.getDeclaringClass().getName())
.append(", but got ")
.append(receiver.getClass().getName());
throw new IllegalArgumentException(sb.toString());
}
if (args == null) {
args = EMPTY_ARGS;
}
Class[] pTypes = method.getParameterTypes();
if (args.length != pTypes.length) {
throw new IllegalArgumentException("wrong number of arguments; "
+ "expected " + pTypes.length + ", got " + args.length);
}
return invokeSuper0(method, pTypes, receiver, args);
}
native private static InvocationHandler getInvocationHandler0(Class cls);
native private static Method getProxiedMethod0(Method method);
native private static Object invokeSuper0(Method method, Class[] parameterTypes, Object receiver, Object... args);
native private static Class generateProxy(String name, Class superclass, Class[] interfaces,
ClassLoader loader, InvocationHandler handler);
}