从CDI代理获取真实对象

时间:2018-08-23 08:44:10

标签: java cdi jboss-weld

我寻找的是干净的CDI解决方案,而不是WELD依赖的解决方案,但到目前为止没有任何解决方法...

我需要测试使用@Inject @Any MyInterface bean获得的对象列表中的每个元素是否都是代理,并且当为true时,我需要获取真实的对象进行自省并获取该对象的所有属性。

我的WELD实施:

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

isProxy在何处定义(CDI解决方案?):

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;
}

任何建议/适应症。在官方文档中,我没有提到内省(here

然后我想用这样的东西来获取bean的所有属性:

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

我们使用Wildfly和WELD,但不想将我们绑定到CDI的实现。 预先感谢!

编辑: 问题更确切地说是:您是否知道一个干净的CDI解决方案,即WELD已已经使用 TargetInstanceProxy 实现了?如果我需要重返校园,或者我了解自己在写什么,就不用了。谢谢您抽出宝贵的时间来帮助您!

3 个答案:

答案 0 :(得分:7)

CDI故意隐藏(或不公开)内部结构,因为在针对接口进行编程时,它们对于最终用户而言并不重要。此外,由于应始终 调用方法,将其弄乱可能会导致奇怪的错误通过代理而不是实际实例。

所以简短的答案是-不,没有纯CDI方法可以做到这一点。 (至少不是预期的。)

但是,看到您已经在使用Weld,还有其他方法。除了TomEE,Weld几乎与任何其他EE服务器一起提供,因此依赖Weld API应该非常安全。 现在,为什么要这么说-在Weld 3.x(WildFly 12+)中,API扩展为包含WeldConstructWeldClientProxy,它们是由Weld子激光器(拦截器/装饰器)和/或客户端代理-有关更多信息,请参见这些类的javadocs。

因此,如果必须执行此操作,则可以这样添加对Weld API的依赖关系:

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

然后,在您的代码中,您可以执行以下操作来检查注入的对象是否是代理:

@Inject
Foo foo;

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

如果要获取实际的实例,可以从WeldClientProxy allows you to obtain Metadataretrieve the underlying contextual instance。那是我能带给您的最接近的信息。

答案 1 :(得分:2)

我不建议从cdi bean中公开内部实例,否则您将无法确定范围并可能产生奇怪的行为。

但是一般的做法是从cdi bean中return this

例如

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

@ApplicationScoped
class Foo implements Unwrapable<Foo> {

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

}

答案 2 :(得分:0)

一个常见的选择是1.获取要解开的实例的Bean,2.获取其作用域(bean.getScope()),3.从Bean管理器(可注入)获取与该作用域关联的Context ,4.如果在CDI上下文中可用,请执行context.get(bean)来获取未包装的实例(在某些情况下,您根本无法获得它)。