Field.get(obj)返回注入的CDI托管bean上的所有空值,而手动调用getter返回正确的值

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

获取beanObject:

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

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

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方法有这个实现:

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来获取值,请执行以下操作:

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

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

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

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

通常我会使用getter,但是我在这里要做的是对我正在开发的应用程序产生全局影响,这意味着返回并修改所有受影响的类以提供getter是最后一个度量解决方案。 此外,这个应用程序将不断修改和扩展,我不想冒其他开发者不提供获取者的机会,这会导致严重的问题。

谢谢!


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

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

}

如你所见,没有具体的领域。 你也应该注意到自动生成的类签名,同时也检查类本身。

毕竟,你会以错误的方式去做这件事。 您应该使用java.beans.Introspector API来内省bean,并调用bean实例上的getters / setter。

这是一个开球的例子:

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和猜测/猜测正确的方法名称。


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


我怀疑这些bean是由CDI和/或JSF实现代理的。

由于代理实现是特定于服务器的,因此没有可靠的方法来解决此问题。 代理生成运行时或应用程序部署时间,并且至少对于某些实现(例如焊接)代理而言,它们没有对bean本身的引用,但确实需要引用它获取bean并调用相应方法所需的内部类。

我能想到的唯一办法就是放松你的房产的安全性,并希望房产被复制到可靠的代理中。

所有这些都违背了JavaEE的精神并打破了面向对象的所有规则,所以我强烈建议不要这样做。

链接地址: http://www.djcxy.com/p/50217.html

上一篇: Field.get(obj) returns all nulls on injected CDI managed beans, while manually invoking getters return correct values

下一篇: When using @EJB, does each managed bean get its own @EJB instance?