I'm trying to create CGLib Proxy for java.net.SocketImpl class using code like:
Enhancer e = new Enhancer();
e.setSuperclass(SocketImpl.class);
e.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object socketImplInstance, Method method, Object[] arguments, MethodProxy methodProxy) throws Throwable {
System.out.println("Got call to " + method.getName());
return methodProxy.invokeSuper(socketImplInstance, arguments);
}
});
SocketImpl socketImpl = (SocketImpl)e.create();
Method m = SocketImpl.class.getDeclaredMethod("getSocket");
m.setAccessible(true);
System.out.println("getSocket: " + m.invoke(socketImpl));
m = SocketImpl.class.getDeclaredMethod("getLocalPort");
m.setAccessible(true);
System.out.println("getLocalPort: " + m.invoke(socketImpl));
As a result of this code I get an output:
getSocket: null
Got call to getLocalPort
getLocalPort: 0
We have no "Got call to getSocket", so SocketImpl#getSocket() has not been intercepted. This method differs from SocketImpl#getLocalPort() only by access level - SocketImpl#getLocalPort() is protected, while SocketImpl#getSocket() is package-private. I have the same behavior with other package-private method SocketImpl#getServerSocket().
I tried to reproduce this error with user class (which is abstract according to SocketImpl), but everything works as expected, if we have:
package userpackage;
public abstract class Abstract {
void testMethod() {}
}
package somethingother;
Enhancer e = new Enhancer();
e.setSuperclass(Abstract.class);
e.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object abstractInstance, Method method, Object[] arguments, MethodProxy methodProxy) throws Throwable {
System.out.println("Got call to " + method.getName());
return methodProxy.invokeSuper(abstractInstance, arguments);
}
});
Abstract abstrct = (Abstract)e.create();
Method m = Abstract.class.getDeclaredMethod("testMethod");
m.setAccessible(true);
System.out.println("testMethod: " + m.invoke(abstrct));
We get output:
Got call to testMethod
testMethod: null
Which is totally fine, this package-private method has been intercepted.
Please, can you help me to understand what's going on on this examples and why do we have different behavior. I have only one guess that it can be related to SecurityManager, but in that case, can you point me the specific case why it doesn't work?
I used CGLib 3.1 and 3.2.0 for tests.
Cglib is intercepting methods by creating a subclass that overrides all methods of its superclass. For overriding package-private methods, the subclass must be defined in the same package.
This is not possible for SocketImpl for two reasons. 1. Only the bootstrap class loader is allowed to define packages in the internal name spaces. 2. In order to override a method, the runtime package also needs to be equal. It is not possible to inject a class into the bootstrap class loader, though.
With cglib, this is not possible. You can however look into Byte Buddy which allows for the creation of bootstrap class proxies via instrumentation.