随笔 - 53, 文章 - 0, 评论 - 3, 引用 - 0
数据加载中……

为对象属性同时定义get和is方法导致的hibernate异常。

今天遇到了一个奇怪的Hibernate问题。(我用得hibernate是2.1版。比较旧,不知道这个问题在hibernate 3 中是否存在。)
下面这个是捕捉到的异常堆栈。
java.lang.ClassCastException: java.lang.Boolean  
at net.sf.hibernate.type.StringType.set(StringType.java:26)
at net.sf.hibernate.type.NullableType.nullSafeSet(NullableType.java:48)  
at net.sf.hibernate.type.NullableType.nullSafeSet(NullableType.java:35)  
at net.sf.hibernate.persister.EntityPersister.dehydrate(EntityPersister.java:393)
at net.sf.hibernate.persister.EntityPersister.insert(EntityPersister.java:466)  
at net.sf.hibernate.persister.EntityPersister.insert(EntityPersister.java:442)  
at net.sf.hibernate.impl.ScheduledInsertion.execute(ScheduledInsertion.java:29)    
at net.sf.hibernate.impl.SessionImpl.executeAll(SessionImpl.java:2382)  
at net.sf.hibernate.impl.SessionImpl.execute(SessionImpl.java:2335) 
at net.sf.hibernate.impl.SessionImpl.flush(SessionImpl.java:2204)
奇怪之处在于程序在本机Tomcat上运行情况良好,一旦部署到Linux服务器上就挂了。

仔细分析之后,发现要存储的对象既定义了get方法又定义了is方法。内容示例如下
public class FakePO {
    String goodMan;
    public String getGoodMan() {
        return goodMan;
    }
    public void setGoodMan(String goodMan) {
        this.goodMan = goodMan;
    }
    public boolean isGoodMan(){
        return "Y".equalsIgnoreCase(goodMan);
    }
}
怀疑可能是这个衍生的辅助方法isGoodMan()导致的问题。通过追踪Hibernate 2的源代码,发现hibernate 2是按如下方式通过反射API访问PO的。

private static Method getterMethod(Class theClass, String propertyName) {      
        Method[] methods = theClass.getDeclaredMethods();
        for (int i=0; i<methods.length; i++) {
            // only carry on if the method has no parameters
            if ( methods[i].getParameterTypes().length==0 ) {
                String methodName = methods[i].getName();
               
                // try "get"
                if( methodName.startsWith("get") ) {
                    String testStdMethod = Introspector.decapitalize( methodName.substring(3) );
                    String testOldMethod = methodName.substring(3);
                    if( testStdMethod.equals(propertyName) || testOldMethod.equals(propertyName) ) return methods[i];
                   
                }
               
                // if not "get" then try "is"
                /*boolean isBoolean = methods[i].getReturnType().equals(Boolean.class) ||
                    methods[i].getReturnType().equals(boolean.class);*/
                if( methodName.startsWith("is") ) {
                    String testStdMethod = Introspector.decapitalize( methodName.substring(2) );
                    String testOldMethod = methodName.substring(2);
                    if( testStdMethod.equals(propertyName) || testOldMethod.equals(propertyName) ) return methods[i];
                }
            }
        }
        return null;
    }
仔细读以上代码可以发现,Hibernate就是简单的遍历类的public方法,看是否和属性名称匹配,并不检查方法的返回值是否和属性的类型匹配。所以在我们的例子中,既可能返回get方法,也可能返回is方法,取决于public方法列表的顺序,而这个顺序恰恰是没有任何保证的。这也解释了为什么这个问题只能在特定平台上发生。

posted on 2008-07-07 12:14 InPractice 阅读(561) 评论(0)  编辑  收藏


只有注册用户登录后才能发表评论。


网站导航: