3

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!

BuZZ-dEE
  • 6,075
  • 12
  • 66
  • 96
Paolof76
  • 889
  • 1
  • 9
  • 23
  • One think then came to my mind: Why can't you refacture your legacy code and rewrite it to a proper way? And why do you need such tests? Normally, there is no need for this. – Roland Aug 23 '18 at 10:01
  • Because they don't want :( Is it always so easy for you folks to do whatever you want with company's code? – Paolof76 Aug 23 '18 at 10:37
  • And I got a down vote for what exactly? If people don't get satisfied with an up, they down vote here? – Paolof76 Aug 23 '18 at 10:39

2 Answers2

9

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.

Siliarus
  • 6,393
  • 1
  • 14
  • 30
  • Thanks, yeah I see your point... they don't want to use weld directly but thanks +1 for giving me good reasons. PS You say it is unimportant to get the internal class that is wrapped in a proxy. But maybe it is not.... why then Weld developers are taking time to give this possibility? CDI lack of reflection tools is disarming, something like Introspector.getBeanInfo... – Paolof76 Aug 23 '18 at 10:45
  • Well, we have seen cases where mostly integrators (meaning WildFly, Payara, ...) or some other EE technologies integrating witu us (RestEasy) have actual need to get hold of contextual instances - hence this API came to life to avoid them hacking into truly internal Weld classes. With end users, we have seen very little cases where it wouldn't be 'cleaner' to avoid doing this. That being said, there are always some cases for sure :) – Siliarus Aug 23 '18 at 10:54
  • 1
    Oh and I just recalled, there was a CDI requirement for what you want loooong ago but was never realized, see https://issues.jboss.org/browse/CDI-10 – Siliarus Aug 23 '18 at 10:55
  • Hey @Siliarus it's reopened, maybe they will implement it in 2.1 :) Another reason to live for some time with an implementation (weld)! – Paolof76 Aug 23 '18 at 11:50
3

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).
BuZZ-dEE
  • 6,075
  • 12
  • 66
  • 96
Romain Manni-Bucau
  • 3,354
  • 1
  • 16
  • 13