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

前端 未结 7 1116
旧时难觅i
旧时难觅i 2020-12-09 02:05

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

Is this possible?

相关标签:
7条回答
  • 2020-12-09 02:38

    Simple and robust:

    AopUtils.getTargetClass(object).getName(); 
    

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

    0 讨论(0)
  • 2020-12-09 02:43

    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.)

    0 讨论(0)
  • 2020-12-09 02:45

    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.

    0 讨论(0)
  • 2020-12-09 02:50

    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}]}
    
    0 讨论(0)
  • 2020-12-09 02:52

    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());
    }
    
    0 讨论(0)
  • 2020-12-09 02:59

    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!

    0 讨论(0)
提交回复
热议问题