Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Replace CGLIB with custom code to generate "enhancers" and "fast-classes".

Some user visible changes from using cglib:
- intercepted method that has a return type of int but returns null from the interceptor will no longer be automatically converted to 0, instead a NullPointerException will be thrown.
- Scope implementation can no longer check for circular proxy instance using CircularDependencyProxy marker class, instead should use Scopes.isCircularProxy
- Depending on which custom class loading option is used, Guice enhanced class may no longer be mockable/spyable
- Generated class name is slightly longer.

Closes #1298

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=320433559
  • Loading branch information
mcculls authored and kevinb9n committed Jul 10, 2020
1 parent 19386e1 commit 8e8238b
Show file tree
Hide file tree
Showing 175 changed files with 1,903 additions and 460 deletions.
Expand Up @@ -8,6 +8,6 @@
* @since 4.0
*/
public static boolean isCircularProxy(Object object) {
return object instanceof CircularDependencyProxy;
return BytecodeGen.isCircularProxy(object);
}

@@ -0,0 +1,7 @@
/** Creates a new circular proxy for the given type. */
static <T> T newCircularProxy(Class<T> type, InvocationHandler handler) {
Object proxy = Proxy.newProxyInstance(type.getClassLoader(), new Class<?>[] {type}, handler);
circularProxyTypeCache.put(proxy.getClass(), Boolean.TRUE);
return type.cast(proxy);
}

This file was deleted.

@@ -0,0 +1,10 @@
/**
* Returns an invoker that constructs an enhanced instance. The invoker function accepts an array
* of invocation handlers plus an array of arguments for the original constructor.
*/
static BiFunction<Object, Object[], Object> enhancedConstructor(
Function<String, BiFunction<Object, Object[], Object>> enhancer, Constructor<?> constructor) {
checkArgument(canEnhance(constructor), "Constructor is not visible");
return enhancer.apply(signature(constructor));
}

@@ -0,0 +1,5 @@
/** Create a builder of enhancers for the given class. */
static EnhancerBuilder enhancerBuilder(Class<?> hostClass) {
return ENHANCER_BUILDERS.getUnchecked(hostClass);
}

@@ -0,0 +1,7 @@
/**
* Prepares the class declaring the given member for fast invocation using bytecode generation.
*/
private static Function<String, BiFunction<Object, Object[], Object>> fastClass(Executable member) {
return FAST_CLASSES.get(member.getDeclaringClass());
}

@@ -0,0 +1,13 @@
/**
* Returns a fast invoker for the given constructor. The invoker function ignores the first
* parameter and accepts an array of arguments for the constructor in the second parameter.
*
* <p>Returns {@code null} if the constructor cannot be "fast-invoked" due to visibility issues.
*/
static BiFunction<Object, Object[], Object> fastConstructor(Constructor<?> constructor) {
if (canFastInvoke(constructor)) {
return fastClass(constructor).apply(signature(constructor));
}
return null;
}

@@ -0,0 +1,13 @@
/**
* Returns a fast invoker for the given method. The invoker function accepts an instance, which
* will be {@code null} for static methods, and an array of arguments for the method.
*
* <p>Returns {@code null} if the method cannot be "fast-invoked" due to visibility issues.
*/
static BiFunction<Object, Object[], Object> fastMethod(Method method) {
if (canFastInvoke(method)) {
return fastClass(method).apply(signature(method));
}
return null;
}

This file was deleted.

This file was deleted.

This file was deleted.

@@ -0,0 +1,5 @@
/** Returns true if the given object is a circular proxy. */
public static boolean isCircularProxy(Object object) {
return object != null && circularProxyTypeCache.containsKey(object.getClass());
}

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

@@ -0,0 +1,10 @@
/**
* Returns an invoker that calls the original unenhanced method. The invoker function accepts an
* enhanced instance plus an array of arguments for the original method.
*/
static BiFunction<Object, Object[], Object> superMethod(
Function<String, BiFunction<Object, Object[], Object>> enhancer, Method method) {
// no need to check 'canEnhance', ProxyFactory will only pick methods from enhanceable list
return enhancer.apply(signature(method));
}

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

@@ -0,0 +1,15 @@
/**
* Generates an enhancer for the selected subset of methods.
*
* <p>The enhancer maps constructor and method signatures to invokers, where each invoker is
* represented as a {@link BiFunction} that accepts a context object and an argument array.
*
* <p>Constructor invokers take an array of {@link InvocationHandler}s as their context object.
* This is stored in the enhanced class before the original host class constructor is called,
* with arguments unpacked from the argument array. The enhanced instance is then returned.
*
* <p>Method invokers take an enhanced instance as their context object and call the original
* super-method with arguments unpacked from the argument array, ie. provides super-invocation.
*/
Function<String, BiFunction<Object, Object[], Object>> buildEnhancer(BitSet methodIndices);

@@ -0,0 +1,11 @@
/**
* Lists the methods in the host class that can be enhanced.
*
* <p>This always includes public and protected methods that are neither static nor final.
*
* <p>Package-private methods can only be enhanced if they're in the same package as the host
* and we can define types in the same class loader with Unsafe. The {@link #finalize} method
* can never be enhanced.
*/
Method[] getEnhanceableMethods();

This file was deleted.

This file was deleted.

This file was deleted.

Expand Up @@ -17,11 +17,6 @@
// TODO: if I create a proxy which implements all the interfaces of
// the implementation type, I'll be able to get away with one proxy
// instance (as opposed to one per caller).
ClassLoader classLoader = BytecodeGen.getClassLoader(expectedType);
return expectedType.cast(
Proxy.newProxyInstance(
classLoader,
new Class[] {expectedType, CircularDependencyProxy.class},
invocationHandler));
return BytecodeGen.newCircularProxy(expectedType, invocationHandler);
}

Expand Up @@ -5,16 +5,12 @@

/*if[AOP]*/
try {
net.sf.cglib.reflect.FastClass fc = BytecodeGen.newFastClassForMember(constructor);
if (fc != null) {
int index = fc.getIndex(constructor.getParameterTypes());
// We could just fall back to reflection in this case but I believe this should actually
// be impossible.
Preconditions.checkArgument(
index >= 0, "Could not find constructor %s in fast class", constructor);
return new FastClassProxy<T>(injectionPoint, constructor, fc, index);
BiFunction<Object, Object[], Object> fastConstructor =
BytecodeGen.fastConstructor(constructor);
if (fastConstructor != null) {
return new FastClassProxy<T>(injectionPoint, constructor, fastConstructor);
}
} catch (net.sf.cglib.core.CodeGenerationException e) {
} catch (Exception | LinkageError e) {
/* fall-through */
}
/*end[AOP]*/
Expand Down

0 comments on commit 8e8238b

Please sign in to comment.