Get the real object from CDI Proxy

六眼飞鱼酱① 提交于 2020-01-05 03:31:11

问题


I looked for a clean CDI solution and not a WELD dependent one but so far nothing...

I need to test if every element of a list of objects that I get with @Inject @Any MyInterface beans is a proxy, and when true I need to get the real object to do introspection and get all the properties of the object.

My WELD implementation:

MyInterface interf = obj;
if (isProxy(interf )) {
        interf = (Config) ((TargetInstanceProxy)interf ).getTargetInstance();
}

where isProxy is so defined (CDI solution?):

public boolean isProxy(Object obj) {
    try{
        return Class.forName("org.jboss.weld.bean.proxy.ProxyObject").isInstance(obj);
    } catch (Exception e) {
        LOGGER.error("Unable to check if object is proxy", e);
    }
    return false;
}

Any suggestions /Indications. In the official documentation I found no mention of introspection (here)

And then I would like to get all the properties of the bean with something like this:

Arrays.stream(interf.getClass().getDeclaredFields()).forEach(
                        field -> extractStuff(...)
                );

We use Wildfly and WELD but don't want to bind us to an implementation of CDI. Thanks in advance!

EDIT: The question is, more precisely: Do you know a clean CDI solution that WELD is already implementing with TargetInstanceProxy? Not if I need to go back to school or if I understand what I'm writing.. Thanks for taking time to help!


回答1:


CDI is intentionally hiding (or rather not exposing) the internals as they should be unimportant to end user when programming against interface.Furthermore messing with this can cause weird errors as you should always be invoking methods via proxy, not the actual instance.

So the short answer is - no, there is no pure CDI way to do this. (At least not an intended one.)

However, seeing that you are using Weld already, there are other ways. Weld comes with pretty much any EE server excepting TomEE, so depending on Weld API should be pretty safe. Now why am I saying this - in Weld 3.x (WildFly 12+), the API was extended to contain WeldConstruct and WeldClientProxy which are interfaces implemented by either Weld sublasses (interceptors/decorators) and/or client proxies - see javadocs of those classes for more information.

So if you must do this, then you could add a dependency on Weld API as such:

<dependency>
  <groupId>org.jboss.weld</groupId>
  <artifactId>weld-api</artifactId>
  <version>x.y.z</version>
</dependency>

And then, in your code, you can check if injected object is a proxy by doing:

@Inject
Foo foo;

public void doSomething() {
  if (foo instanceof WeldClientProxy) {
    // foo is a proxy
  } else {
    // not a proxy
  }
}

If you want to obtain actual instances, WeldClientProxy allows you to obtain Metadata from which you can the retrieve the underlying contextual instance. That's the closest I can get you to what you are after.




回答2:


One common option is to:

  1. get the Bean of the instance you want to unwrap
  2. get its scope (bean.getScope())
  3. from the bean manager (injectable) get the Context associated to the scope
  4. do a context.get(bean) to get the unwrapped instance if available in CDI context (there are some cases you can't get it at all).



回答3:


I would not recommend exposing the internal instance from a cdi bean, you will mess with scoping and potentially create weird behavior.

But a generic way of doing it would be to return this from your cdi bean.

E.g.

interface Unwrapable<T> { T unwrap(); }

@ApplicationScoped
class Foo implements Unwrapable<Foo> {

    public Foo unwrap() { return this; } // Will return the internal instance not the proxy

}


来源:https://stackoverflow.com/questions/51981660/get-the-real-object-from-cdi-proxy

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!