How do I get the underlying type of a proxy object in java?
Asked Answered
S

9

40

I'd like to access the classname of the underlying class which is an instance of java.lang.reflect.Proxy.

Is this possible?

Sb answered 27/7, 2010 at 13:50 Comment(0)
K
34

You can get the InvocationHandler with which the proxy was created, by calling Proxy.getInvocationHandler(proxy)

Note that in the case of java.lang.reflect.Proxy there is no underlying class per se. The proxy is defined by:

  • interface(s)
  • invocation handler

And the wrapped class is usually passed to the concrete invocation handler.

Kinard answered 27/7, 2010 at 13:59 Comment(2)
Thanks. What does the invocation handler get me? I've got a proxy but i want the classname of the object that is implementing the interface the proxy is built from. I'm thinking it's not possible ...Sb
There is no object other than the proxy object. The invocation handler is responsible for dispatching the callKinard
C
28

I found a good solution on this site (now archived):

@SuppressWarnings({"unchecked"})
protected <T> T getTargetObject(Object proxy, Class<T> targetClass) throws Exception {
  if (AopUtils.isJdkDynamicProxy(proxy)) {
    return (T) ((Advised)proxy).getTargetSource().getTarget();
  } else {
    return (T) proxy; // expected to be cglib proxy then, which is simply a specialized class
  }
}

Usage

@Override
protected void onSetUp() throws Exception {
  getTargetObject(fooBean, FooBeanImpl.class).setBarRepository(new MyStubBarRepository());
}
Cataplasia answered 17/7, 2013 at 9:24 Comment(4)
The argument "targetClass" is not used :)Hypotonic
Yes, it is only for type castingCataplasia
In that case, wouldn't it be better to actually use it for casting, rather than suppressing warnings, e.g. targetClass.cast(proxy)? This way you're actually guaranteed to get an object of that type, whereas in the other case due to type erasure the casting might not occur depending on the usage pattern.Packard
This worked perfectly in Java 11 and Spring Boot 2.1.1 as wellCruikshank
A
16

Well a Proxy instance won't be an instance of java.lang.reflect.Proxy per se. Rather, it will be an instance of a subclass of java.lang.reflect.Proxy.

Anyway, the way to get the actual proxy classes name is:

Proxy proxy = ...
System.err.println("Proxy class name is " + proxy.getClass().getCanonicalName());

However, you cannot get the name of the class that the Proxy is a proxy for, because:

  1. you proxy interfaces not classes, and
  2. a Proxy can be a proxy for multiple interfaces

However, from looking at the source code of the ProxyGenerator class, it seems that the interfaces are recorded in the generated proxy class as the interfaces of the class. So you should be able to get them at runtime via the proxy classes Class object; e.g.

Class<?>[] classes = proxy.getClass().getInterfaces();

(Note: I've not tried this ...)

Afebrile answered 27/7, 2010 at 14:11 Comment(1)
Perfect for searching original interface with only dynamic implementation (by framework). Like port of WS: Stream.of(port.getClass().getInterfaces()).filter(__ -> __.getAnnotation(WebService.class) != null).findAny()Carpel
P
8

Simple and robust:

AopUtils.getTargetClass(object).getName(); 

Will also work for CGLIB proxies and non-proxy objects.

Potage answered 19/3, 2019 at 18:43 Comment(0)
O
5

Here was the solution we used with my team (we need the name of the class behind the proxy) :

if (getTargetName(yourBean) ... ) {

}

With this little helper :

private String getTargetName(final Object target) {

    if (target == null) {
        return "";
    }

    if (targetClassIsProxied(target)) {

        Advised advised = (Advised) target;

        try {

            return advised.getTargetSource().getTarget().getClass().getCanonicalName();
        } catch (Exception e) {

            return "";
        }
    }

    return target.getClass().getCanonicalName();
}

private boolean targetClassIsProxied(final Object target) {

    return target.getClass().getCanonicalName().contains("$Proxy");
}

Hope it helps!

Oshiro answered 26/6, 2014 at 21:28 Comment(0)
C
4

You can use the following code for retrieve the info (ArrayUtils is from Apache commons lang) about invocation handler and the interfaces of the current proxy:

String.format("[ProxyInvocationHandler: %s, Interfaces: %s]", 
     Proxy.getInvocationHandler(proxy).getClass().getSimpleName(), 
     ArrayUtils.toString(proxy.getClass().getInterfaces()));

Example result:

[ProxyInvocationHandler: ExecuteProxyChain, Interfaces: {interface com.example.api.CustomerApi}]}
Comprehensible answered 27/2, 2015 at 10:25 Comment(0)
F
1

I found the perfect solution for me in org.springframework.aop.framework.AopProxyUtils:

AopProxyUtils.ultimateTargetClass(object).getCanonicalName()

Furiya answered 10/12, 2021 at 15:56 Comment(0)
W
0

First of all, java.lang.reflect.Proxy works only on interfaces. The framework creates a descendant class that implements the interface(s) but extends java.lang.reflect.Proxy rather than an application class that may be of interest to you. There is no inheritance of multiple classes in modern (2016) Java.

In my case, the debugger shows that the object of interest is in the obj field in the invocation handler of the proxy object.

    Object handler = Proxy.getInvocationHandler(somethingProxied);
    Class handlerClass = handler.getClass();
    Field objField = handlerClass.getDeclaredField("obj");
    objField.setAccessible(true);
    Object behindProxy = objField.get(handler);

You will have to catch() two exceptions: NoSuchFieldException and IllegalAccessException.

I found it useful to print the list of fields of declared fields from the catch() clause:

...
} catch (NoSuchFieldException nsfe) {
    nsfe.printStackTrace();

    Object handler = Proxy.getInvocationHandler(somethingProxied);
    Class handlerClass = handler.getClass();
    for (Field f : handlerClass.getDeclaredFields()) {
        f.setAccessible(true);
        String classAndValue = null;
        try {
            Object v = f.get(handler);
            classAndValue= "" + (v == null ? "" : v.getClass()) + " : " + v;
        } catch (IllegalAccessException iae) {
            iae.printStackTrace();
        }
        System.out.println(" field: " + f.getName() + " = " + classAndValue+ ";");
    }
...
}

Note that different frameworks use different proxies and even different techniques of proxying. The solution that worked for me may be not applicable in your case. (It definitely will not work for Javassist or Hibernate proxies.)

Wanyen answered 17/1, 2017 at 15:34 Comment(0)
N
0

Static Hibernate.getClass() might be useful in this scenario.

Get the true, underlying class of a proxied persistent class

    public static Class getClass(Object proxy) {
        if ( proxy instanceof HibernateProxy ) {
            return ( ( HibernateProxy ) proxy ).getHibernateLazyInitializer()
                    .getImplementation()
                    .getClass();
        }
        else {
            return proxy.getClass();
        }
    }
Necrotomy answered 22/6, 2021 at 16:41 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.