Field.get(obj) 在注入的 CDI 托管 bean 上返回所有空值,而手动调用 getter 返回正确的值 [英] Field.get(obj) returns all nulls on injected CDI managed beans, while manually invoking getters return correct values

查看:17
本文介绍了Field.get(obj) 在注入的 CDI 托管 bean 上返回所有空值,而手动调用 getter 返回正确的值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图通过反射从 JSF 页面的支持 bean 访问某些字段的值.问题是,当我使用 getter 时,我得到了正确的值,但是当我使用必要字段的 get(obj) 方法时,我总是得到一个返回的空值.

I am trying to access the values of some fields from the backing bean of a JSF page via reflection. The problem is that when I use the getter I get the correct value but when I use the get(obj) method of the necessary fields I always get a null value returned.

获取 beanObject:

Getting the beanObject:

ELContext elcontext = FacesContext.getCurrentInstance().getELContext();
Object beanObject = FacesContext.getCurrentInstance().getApplication().getELResolver().getValue(elcontext, null, beanName);

要在不使用 getter 的情况下获取字段值,我执行以下操作:

To get the fields values without using the getter I do the following:

List<Field> fields = new ArrayList<Field>();
ParamsBuilder.getAllFields(fields, beanClass);

for(Field field: fields) {

    field.setAccessible(true);
    System.out.println(field.getName() + ": " + field.get(beanObject)); //just to see if it works

}

getAllFields 方法有这个实现:

The getAllFields method has this implementation:

public static List<Field> getAllFields(List<Field> fields, Class<?> type) {
    for (Field field: type.getDeclaredFields()) {
        fields.add(field);
    }

    if (type.getSuperclass() != null) {
        fields = getAllFields(fields, type.getSuperclass());
    }

    return fields;
}

要使用 getter 获取值,我执行以下操作:

To get the values by using the getter I do the following:

private ClassX getValue(Object beanObject, Class<?> beanClass) throws Exception {

    Method getter = beanClass.getDeclaredMethod("myMethod",(Class<?>[]) null);

    return (ClassX)getter.invoke(beanObject, (Object[])null);
}

我可以进一步提到的是,我尝试访问的字段注入了 @Inject 注释,但我认为这不是问题,因为其他未注入的实例字段也受到同样的影响.

What I can further mention is that the fields I am trying to access are injected with the @Inject annotation, but I don't believe this is the problem as other instance fields, not injected, suffer of the same affection.

通常我会使用 getter,但我在这里尝试做的事情会对我正在开发的应用程序产生全局影响,这意味着返回并修改所有受影响的类以提供 getter 是最后的解决方案.此外,此应用程序将不断修改和扩展,我不想冒险其他开发人员不提供 getter,这将导致严重问题.

Normally I would use the getter but what I am trying to do here has a global impact on the application I am developing, which means that going back and modifying all affected classes to provide getters is a last measure solution. Also this application will be constantly modified and extended and I don't want to take the chance of the other developers not providing the getters, which will result in serious problems.

谢谢!

推荐答案

这确实是预期的行为.CDI 托管 bean 实例本质上是一个自动生成类的可序列化代理实例,它扩展原始支持 bean 类并通过公共方法将所有公共方法进一步委托给实际实例(就像 EJB 的工作方式一样).自动生成的类大致如下所示:

That's indeed expected behavior. The CDI managed bean instance is in essence a serializable proxy instance of an autogenerated class which extends the original backing bean class and delegates in all public methods further to the actual instance via public methods (like as how EJBs work). The autogenerated class looks roughly like this:

public CDIManagedBeanProxy extends ActualManagedBean implements Serializable {

    public String getSomeProperty() {
        ActualManagedBean instance = CDI.resolveItSomehow();
        return instance.getSomeProperty();
    }

    public void setSomeProperty(String someProperty) {
        ActualManagedBean instance = CDI.resolveItSomehow();
        instance.setSomeProperty(someProperty);
    }

}

如您所见,没有具体的字段.您也应该在检查类本身时注意到自动生成的类签名.

As you see, there are no concrete fields. You should also have noticed the autogenerated class signature while inspecting the class itself too.

毕竟,你这样做是错误的.您应该使用 java.beans.Introspector API 用于内省 bean 并在 bean 实例上调用 getter/setter.

After all, you're going about this the wrong way. You should be using java.beans.Introspector API to introspect the bean and invoke getters/setters on bean instances.

这是一个启动示例:

Object beanInstance = getItSomehow();
BeanInfo beanInfo = Introspector.getBeanInfo(beanInstance.getClass());

for (PropertyDescriptor property : beanInfo.getPropertyDescriptors()) {
    String name = property.getName();
    Method getter = property.getReadMethod();
    Object value = getter.invoke(beanInstance);
    System.out.println(name + "=" + value);
}

这个 API 像 JSF 和 CDI 一样尊重 JavaBeans 规范,所以你不需要摆弄原始反射 API 和计算/猜测正确的方法名称.

This API respects like JSF and CDI the JavaBeans spec, so you don't need to fiddle around with raw reflection API and figuring/guessing the correct method names.

与具体问题无关,取决于具体的功能需求,您可能错误地认为这都是正确的解决方案,而您在问题中没有提及任何内容,有可能是比内省 bean 实例更好的方法来实现它.

Unrelated to the concrete problem, depending on the concrete functional requirement for which you possibly incorrectly thought that this all would be the right solution, which you didn't tell anything about in the question, there may be even more better ways to achieve it than introspecting the bean instances.

这篇关于Field.get(obj) 在注入的 CDI 托管 bean 上返回所有空值,而手动调用 getter 返回正确的值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆