2012-04-06 2 views
0

Когда я делаю следующий вызов Hibernate, я получаю исключение ClassCastException (см. Stacktrace), но у меня есть проблемы, чтобы понять, почему. Что Hibernate пытается сделать здесь? Является ли это попыткой применить один из моих объектов к другому типу класса? Если да, то почему и к какому классу?Почему Hibernate бросает ClassCastException при вызове session.save (object)?

session.save(fooAccount); 

StackTrace:

com.foo.web.model.exception.FailedDatabaseOperationException: java.lang.ClassCastException: com.foo.web.model.authentication.SecurePassword 
    at com.foo.web.controller.db.HibernateController.savefooAccount(HibernateController.java:883) 
    at com.foo.web.model.account.fooAccount.save(fooAccount.java:459) 
    at com.foo.web.controller.AccountController.createfooAccount(AccountController.java:258) 
    at com.foo.web.view.start.RegisterController.register(RegisterController.java:233) 
    at com.foo.web.view.start.RegisterController.onClick$btn_register(RegisterController.java:196) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) 
    at java.lang.reflect.Method.invoke(Method.java:597) 
    at org.zkoss.zk.ui.event.GenericEventListener.onEvent(GenericEventListener.java:81) 
    at org.zkoss.zk.ui.impl.EventProcessor.process0(EventProcessor.java:192) 
    at org.zkoss.zk.ui.impl.EventProcessor.process(EventProcessor.java:138) 
    at org.zkoss.zk.ui.impl.EventProcessingThreadImpl.process0(EventProcessingThreadImpl.java:517) 
    at org.zkoss.zk.ui.impl.EventProcessingThreadImpl.sendEvent(EventProcessingThreadImpl.java:121) 
    at org.zkoss.zk.ui.event.Events.sendEvent(Events.java:319) 
    at org.zkoss.zk.ui.event.Events.sendEvent(Events.java:329) 
    at org.zkoss.zk.ui.AbstractComponent$ForwardListener.onEvent(AbstractComponent.java:3034) 
    at org.zkoss.zk.ui.impl.EventProcessor.process0(EventProcessor.java:192) 
    at org.zkoss.zk.ui.impl.EventProcessor.process(EventProcessor.java:138) 
    at org.zkoss.zk.ui.impl.EventProcessingThreadImpl.process0(EventProcessingThreadImpl.java:517) 
    at org.zkoss.zk.ui.impl.EventProcessingThreadImpl.run(EventProcessingThreadImpl.java:444) 
Caused by: java.lang.ClassCastException: com.foo.web.model.authentication.SecurePassword 
    at org.hibernate.type.ComponentType.toLoggableString(ComponentType.java:410) 
    at org.hibernate.type.ComponentType.toLoggableString(ComponentType.java:414) 
    at org.hibernate.pretty.Printer.toString(Printer.java:76) 
    at org.hibernate.pretty.Printer.toString(Printer.java:113) 
    at org.hibernate.event.def.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:120) 
    at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:50) 
    at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1216) 
    at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:383) 
    at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:133) 
    at com.foo.web.controller.db.HibernateController.savefooAccount(HibernateController.java:879) 

Edit: Вот отображения, а также код, который хранит объект:

Mapping файл (сокращенный вариант . Исключительные вещи опущены):

<?xml version="1.0"?> 
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" 
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> 
<!-- Generated 26.04.2011 14:49:15 by Hibernate Tools 3.3.0.GA --> 
<hibernate-mapping> 
    <class name="com.foo.web.model.account.fooAccount" table="fooACCOUNT"> 

     <id name="id" type="long" access="field"> 
      <column name="foo_ACCOUNT_ID" /> 
      <generator class="native" /> 
     </id> 

     <many-to-one name="defaultMailAccount" lazy="false" column="DEFAULT_MAIL_ACCOUNT_ID" /> 

     <bag name="mailAccounts" table="MAILACCOUNTS" lazy="false" inverse="true"> 
      <key column="foo_ACCOUNT_ID"></key> 
      <one-to-many class="com.foo.web.model.mail.account.MailAccount" /> 
     </bag> 

     <component name="user" class="com.foo.web.model.account.fooUser"> 
      <component name="activationCode"> 
       <property name="activationCode" column="ACTIVATION_CODE"></property> 
      </component> 

      <component name="password" class="com.foo.web.model.authentication.MediumSecurePassword"> 
       <property name="hash" column="PASSWORD" /> 
      </component> 

      <component name="resetCode"> 
       <property name="resetCode" column="RESET_CODE" /> 
      </component> 
      <one-to-one name="fooAccount" class="com.foo.web.model.account.fooAccount"></one-to-one> 
      <component name="username"> 
       <property name="username" column="USERNAME" unique="true" /> 
      </component> 

      <property name="userStatus"> 
       <column name="USERSTATUS" /> 
       <type name="org.hibernate.type.EnumType"> 
        <param name="type">12</param> 
        <param name="enumClass">com.foo.web.model.account.UserStatus</param> 
       </type> 
      </property> 
      <property name="userType"> 
       <column name="USERTYPE" /> 
       <type name="org.hibernate.type.EnumType"> 
        <param name="type">12</param> 
        <param name="enumClass">com.foo.web.model.account.UserType</param> 
       </type> 
      </property> 
     </component> 

    </class> 
</hibernate-mapping> 

SecurePassword.java (сокращенный)

/** 
* Represents a password. 
*/ 
public class SecurePassword extends Password { 

    /** 
    * Default constructor 
    */ 
    public SecurePassword() { 
     super(); 
    } 

    /** 
    * Constructor method. Will throw IllegalPasswordException if password is 
    * not safe. 
    */ 
    public SecurePassword(String password) throws IllegalPasswordException { 
     setPassword(password); 
    } 

    /** 
    * Checks if the given character is a number 
    * 
    * @param c 
    *   The character to check 
    * @return Returns true if the given character is a number 
    */ 
    public boolean isNumber(char c) { 
     // ... 
    } 

    /** 
    * Checks is a given password is valid. 
    */ 
    public boolean passwordValid(Password password) 
     throws IllegalPasswordException { 
     return passwordValid(password.toString()); 
    } 

    /** 
    * Checks is a given password is valid. 
    */ 
    public boolean passwordValid(String password) 
     throws IllegalPasswordException { 

     // ... 
    } 

    /** 
    * Sets a new password. 
    */ 
    @Override 
    public void setPassword(String password) throws IllegalPasswordException { 

     if (passwordValid(password)) { 
      this.password = password; 
     } 
    } 

} 

Password.java (сокращенный)

/** 
* Represents a simple password without much restriction 
*/ 
public class Password { 
    Crypter crypter  = new Crypter(); 
    String hash  = null; 
    String password = null; 

    public Password() { 
     super(); 
    } 

    public Password(String password) throws IllegalPasswordException { 
     setPassword(password); 
    } 

    @Override 
    public boolean equals(Object password) { 

     if (this == password) { 
      return true; 
     } 

     if (password instanceof Password) { 
      Password p = (Password) password; 
      return getHash().equals(p.getHash()); 
     } 

     if (password instanceof String) { 
      String password_str = getPassword(); 
      if (password_str != null) { 
       return password_str.equals(password); 
      } 
     } 

     return false; 
    } 

    /** 
    * Returns the hashed version of this password 
    * 
    * @return The hashed version of this password 
    */ 
    public String getHash() { 
     if (hash == null) { 
      try { 
       hash = crypter.hash(getPassword()); 
      } catch (FailedCryptOperationException e) { 
       handleException(e, false, null, null); 
      } 
     } 
     return hash; 
    } 

    public String getPassword() { 
     return password; 
    } 

    /* 
    * Handles the given exception 
    */ 
    private void handleException(Exception e, boolean notifyUser, 
     String customTitle, String customErrorMessage) { 

     SystemController.handleException(e, notifyUser, customTitle, 
      customErrorMessage); 
    } 

    public void setHash(String hash) { 
     this.hash = hash; 
    } 

    @SuppressWarnings("unused") 
    public void setPassword(String password) throws IllegalPasswordException { 
     hash = null; 
     this.password = password; 
    } 

    @Override 
    public String toString() { 

     return getPassword(); 
    } 
} 

MediumSecurePassword.java

public class MediumSecurePassword extends SecurePassword { 

    public final int MAX_LENGTH    = 64; 
    public final int MIN_LENGTH    = 6; 
    StringUtil   stringUtil    = new StringUtil(); 


    public MediumSecurePassword() { 
     super(); 
    } 

    /** 
    * Constructor method. Will throw IllegalPasswordException if password is 
    * not safe. Medium Safe passwords are at least 6 characters long. 
    */ 
    public MediumSecurePassword(String password) throws IllegalPasswordException { 
     setPassword(password); 
    } 

    /** 
    * Checks if the given character is a number 
    */ 
    public boolean isNumber(char c) { 
     // ... 
    } 

    /** 
    * Checks is a given password is valid. Valid means that it's secure (at 
    * least 8 characters, at least 1 number, at least 1 special character). 
    */ 
    public boolean passwordValid(Password password) 
     throws IllegalPasswordException { 
     return passwordValid(password.toString()); 
    } 

    /** 
    * Checks is a given password is valid. Valid means that it's "medium secure" (min. 
    * length of 6). 
    */ 
    public boolean passwordValid(String password) 
     throws IllegalPasswordException { 

     // ... 
    } 

    /** 
    * Sets a new password. Will throw IllegalPasswordException if password is 
    * not safe. Safe passwords are at least 8 characters long, consist of 
    * numbers, letters and special characters. 
    */ 
    @Override 
    public void setPassword(String password) throws IllegalPasswordException { 

     if (passwordValid(password)) { 
      this.password = password; 
     } 
    } 
} 

Примечание: Если удалить эти 3 строки из моего файла отображения все проходит гладко:

<component name="password" class="com.foo.web.model.authentication.MediumSecurePassword"> 
<property name="hash" column="PASSWORD" /> 
</component> 

Так, для меня, кажется, есть проблема с получением хэш-значением, что пароль с помощью passwordInstance.getHash() ? Не уверен, хотя.

+1

Что связь между _assumably_ 'Account' лицами и' SecurePassword '? Каковы сопоставления? – nobeh

+0

опубликуйте [SSCCE] (http://sscce.org/), или мы не сможем понять это либо –

+0

@nobeh Я добавил файл сопоставления и исходный код – Timo

ответ

3

В чем заключается идея использования подкласса подкласса пароля в сопоставлении?

Что здесь происходит то, что вам требуется конкретные реализации сериализовать на упорствовать. В вашем случае ваш объект реализует родительский класс (SecurePassword), поэтому его нельзя отнести к MediumSecurePassword.

посоветую использовать родительский класс в отображении, таким образом, вы сможете использовать как SecurePassword и MediumSecurePassword в вашей реализации:

 <component name="password" class="com.foo.web.model.authentication.Password"> 
      <property name="hash" column="PASSWORD" /> 
     </component> 
+0

О, боже мой. Вы абсолютно правы. Я был таким глупым. Спасибо за подсказку. Изменение класса вызвало трюк. – Timo

Смежные вопросы