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

Java get(obj)返回注入的CDI托管bean上的所有空值,同时手动调用getter返回正确的值,java,jsf,reflection,cdi,managed-bean,Java,Jsf,Reflection,Cdi,Managed Bean,我试图通过反射从JSF页面的支持bean访问一些字段的值。问题是,当我使用getter时,我得到了正确的值,但是当我使用必需字段的get(obj)方法时,我总是得到一个返回的null值 获取beanObject: ELContext elcontext = FacesContext.getCurrentInstance().getELContext(); Object beanObject = FacesContext.getCurrentInstance().getApplication().

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

获取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

}
List fields=new ArrayList();
获取所有字段(字段,beanClass);
用于(字段:字段){
字段。setAccessible(true);
System.out.println(field.getName()+”:“+field.get(beanObject));//看看它是否有效
}
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;
}
公共静态列表getAllFields(列表字段,类类型){
for(字段:type.getDeclaredFields()){
字段。添加(字段);
}
if(type.getSuperclass()!=null){
fields=getAllFields(字段,类型.getSuperclass());
}
返回字段;
}
要使用getter获取值,请执行以下操作:

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

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

    return (ClassX)getter.invoke(beanObject, (Object[])null);
}
private ClassX getValue(对象beanObject,类beanClass)引发异常{
方法getter=beanClass.getDeclaredMethod(“myMethod”,(类[])null);
return(ClassX)getter.invoke(beanObject,(Object[])null);
}
我可以进一步提到的是,我试图访问的字段被注入了@Inject注释,但我不认为这是问题所在,因为其他未注入的实例字段也会受到同样的影响

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


谢谢大家!

我怀疑bean正在被CDI和/或JSF实现代理

由于代理实现是特定于服务器的,因此没有可靠的方法来解决这个问题。代理是在运行时或应用程序部署时生成的,至少对于某些实现(例如weld),代理没有对bean本身的引用,但有对获取bean和调用相应方法所需的内部类的引用

我能想到的唯一方法是放松你的财产的安全性,并希望将财产复制到代理中


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

这确实是预期的行为。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);
    }

}
如你所见,这里没有混凝土场地。您还应该在检查类本身时注意到自动生成的类签名

毕竟,你走错了路。您应该使用来内省bean并在bean实例上调用getter/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类似,所以您不需要摆弄原始反射API和计算/猜测正确的方法名称



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

Java最被滥用的API反射很多时候只是特定于框架的。如果不是真的需要,请避免使用它。如果是通过注入,您如何获得beanObject?它可能被代理,因此您可能无法获得字段的任何值。我以获取beanObject的方式进行编辑,我认为您使用代理是正确的。有没有办法克服这个问题?