Java generates a proxy class for a given interface and provides the instance of the proxy class. But when we type cast the proxy object to our specific Object, how java handles this internally? Is this treated as special scenario?
For example I have class OriginalClass
and it implements OriginalInterface
, when I create proxy object by passing OriginalInterface
interface Java created proxy class ProxyClass
using methods in the provided interface and provides object of this class(i.e. ProxyClass
). If my understanding is correct then can you please answer following queries
ProxyClass
to my class OriginalClass
this works, but how Java is allowing this? Same in case of instace of?Thanks, Student
A proxy class is a class created at runtime that implements a specified list of interfaces, known as proxy interfaces. A proxy instance is an instance of a proxy class. Each proxy instance has an associated invocation handler object, which implements the interface InvocationHandler .
Spring AOP uses either JDK dynamic proxies or CGLIB to create the proxy for a given target object. (JDK dynamic proxies are preferred whenever you have a choice). If the target object to be proxied implements at least one interface then a JDK dynamic proxy will be used.
We create and use proxy objects when we want to add or modify some functionality of an already existing class. The proxy object is used instead of the original one. Usually, the proxy objects have the same methods as the original one and in Java proxy classes usually extend the original class.
Spring used two types of proxy strategy one is JDK dynamic proxy and other one is CGLIB proxy. JDK dynamic proxy is available with the JDK. It can be only proxy by interface so target class needs to implement interface.
Java isn't allowing casting from a proxy to a concrete class. JDK proxies (java.lang.reflect.Proxy
) are only proxies of an interface. The resulting proxy is of type ProxyX
(X being a number), and if you try to cast it to any class you will get ClassCastException
Therefore your 2nd and 3rd questions aren't relevant - the proxy isn't backed by a concrete class. To achieve this, you can use other proxying mechanisms - CGLIB or javassist. They use ynamic subclassing, and so all protected
(and above) fields and methods are accessible to the subclass (proxy).
From the API javadocs for java.lang.reflect.InvocationHandler:
InvocationHandler is the interface implemented by the invocation handler of a proxy instance.
The dynamic proxy implements the interface, but uses the handler (OriginalClass) to provide the base implementations of the methods.
To answer your questions:
Inside the implementation of the dynamic proxy (e.g. in the implementation of the invoke(...) method) you can access the members of the handler using reflection.
Here's some test code that I used to check my answer:
// package ...;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import junit.framework.Assert;
import org.junit.Test;
public class TestDynamicProxy
{
@Test
public void testCast() throws Exception {
Foo foo = (Foo) TestProxy.newInstance(new FooImpl());
foo.bar(null);
System.out.println("Class: " + foo.getClass());
System.out.println("Interfaces: " + foo.getClass().getInterfaces());
Assert.assertNotNull(foo);
Assert.assertTrue(foo instanceof Foo);
Assert.assertFalse(foo instanceof FooImpl);
}
}
interface Foo
{
Object bar(Object obj) throws Exception;
}
class FooImpl implements Foo
{
public Object bar(Object obj) throws Exception {
return null;
}
}
class TestProxy implements java.lang.reflect.InvocationHandler
{
private final Object obj;
public static Object newInstance(Object obj) {
return java.lang.reflect.Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), new TestProxy(obj));
}
private TestProxy(Object obj) {
this.obj = obj;
}
public Object invoke(Object proxy, Method m, Object[] args) throws Throwable {
Object result;
try {
result = m.invoke(obj, args);
}
catch (InvocationTargetException e) {
throw e.getTargetException();
}
catch (Exception e) {
throw new RuntimeException("unexpected invocation exception: " + e.getMessage());
}
return result;
}
}
This article has a lot of useful information and example code.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With