本人的一个系统,JDK7+Spring3.1+SpringSecurity3开发的,一切都没有问题,后来tomcat在1.8下跑起来加载这个应用,就抛出了这个异常来,很令人心烦。调查结果是说降为JDK1.7就好了。如果这样就好了,我也不用折腾了。就想用JDK8了。
org.springframework.beans.FatalBeanException: Failed to obtain BeanInfo for class [com.xxxx.domain.User]; nested exception is java.beans.IntrospectionException: type mismatch between read and write methods at org.springframework.beans.CachedIntrospectionResults.<init>(CachedIntrospectionResults.java:262) at org.springframework.beans.CachedIntrospectionResults.forClass(CachedIntrospectionResults.java:149) at org.springframework.beans.BeanWrapperImpl.getCachedIntrospectionResults(BeanWrapperImpl.java:324) at org.springframework.beans.BeanWrapperImpl.setPropertyValue(BeanWrapperImpl.java:1055) at org.springframework.beans.BeanWrapperImpl.setPropertyValue(BeanWrapperImpl.java:924) at org.springframework.beans.AbstractPropertyAccessor.setPropertyValues(AbstractPropertyAccessor.java:76) at org.springframework.validation.DataBinder.applyPropertyValues(DataBinder.java:692) at org.springframework.validation.DataBinder.doBind(DataBinder.java:588) ……
问题的起源调查清楚了,我直接以案例的形式来阐明问题的所在。
User类是用户类,是系统早期设计的时候就存在的。后来整合SpringSecurity,就给它实现了UserDetails接口,这个是有经验的人都知道的。
UserDetail接口有一个方法,是关于授权的,接口方法声明如下:
Collection<? extends GrantedAuthority> getAuthorities();
这个好办,给User加这样一个字段就行了。问题是,我把GrantedAuthority(也是接口)资源化了,即有一个类Authority实现了这个接口,并且可以持久化到数据库中,然后在线动态分配。由于GrantedAuthority接口里面只有一个返回值为字符串的无参方法getAuthority,因此Authority类我就不贴出来了。
管理User中的authorites的时候,我使用了List类型的成员变量,即:
private List<GrantedAuthority> authorities; @Override public List<GrantedAuthority> getAuthorities() { return authorities; } public void setAuthorities(List<GrantedAuthority> authorities) { this.authorities = authorities; }
因此getter/setter也都是List<GrantedAuthority>类型的。
由于User实现了UserDetails接口,而该接口中的对getter的声明返回类型为Collection<? extends GrantedAuthority>,因此特意将上述getter的返回类型改成了Collection<? extends GrantedAuthority>,即:
private List<GrantedAuthority> authorities; @Override public Collection<? extends GrantedAuthority> getAuthorities() { return authorities; } public void setAuthorities(List<GrantedAuthority> authorities) { this.authorities = authorities; }
编译没有问题,在JDK1.7下跑也没问题,后来就没再理会。后来升级到JDK1.8的时候,乱子就由此引发:
org.springframework.beans.FatalBeanException: Failed to obtain BeanInfo for class [com.xxxx.domain.User]; nested exception is java.beans.IntrospectionException: type mismatch between read and write methods
修改方式有两种:一种是,回复原先List<GrantedAuthority>返回值的getter声明,虽然与接口声明的不一样,但是属于实现兼容,因此编译还是没有问题,但跑起来没问题。
另一种是,authorities属性的声明、setter/getter都用UserDetails中声明的类型,即Collection<? extends GrantedAuthority>来声明,编译、运行也都没有问题。
所以,当你的项目存在这种类型的属性的时候,基本在JDK1.8+Spring3.1是跑不通的。之所以下这个结论,并且有这样的约束(Spring3.1),是因为最后抛出异常的位置是Spring3.1里面做BeanInfo检查的时候跑出来的,具体的流程我就不贴出来了。如果有兴趣,跟踪一下代码就会发现问题所在的。