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

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

获取beanObject:

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

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

 List fields = new ArrayList(); 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 getAllFields(List 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是最后一个度量解决方案。 此应用程序也将不断修改和扩展,我不想让其他开发人员不提供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实例上调用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 JavaBeans规范 ,因此您不需要使用原始reflectionAPI并计算/猜测正确的方法名称。


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

我怀疑bean正在通过CDI和/或JSF实现代理。

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

关于我能想到这样做的唯一方法是放宽对您的属性的安全性,并希望该属性可靠地复制到代理中。

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