2012-04-06 7 views
0

Wenn ich den folgenden Hibernate-Aufruf mache, bekomme ich eine ClassCastException (siehe Stacktrace), aber ich habe Probleme zu verstehen, warum. Was versucht Hibernate hier zu machen? Wird versucht, eines meiner Objekte in einen anderen Klassentyp umzuwandeln? Wenn ja, warum und zu welcher Klasse?Warum wirft Hibernate beim Aufruf von session.save (object) eine ClassCastException?

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: Hier sind die Zuordnungen sowie der Code, der das Objekt speichert:

Mapping-Datei (gekürzte Version Irrelevante Sachen weggelassen):

<?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 (verkürzt)

/** 
* 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 (verkürzt)

/** 
* 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; 
     } 
    } 
} 

Hinweis: Wenn ich diese 3 Zeilen von meiner Mapping-Datei reibungslos läuft alles entfernen:

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

Also, für mich scheint es das Kennwort der Hash-Wert über passwordInstance.getHash() ein Problem zu sein mit immer ? Nicht sicher, obwohl.

+1

Was die Beziehung zwischen _assumably_ 'Account' Einheit ist und' SecurePassword '? Was sind die Abbildungen? – nobeh

+0

post ein [SSCCE] (http://sscce.org/) oder wir werden es nicht verstehen –

+0

@nobeh Ich habe die Mapping-Datei und den Quellcode hinzugefügt – Timo

Antwort

3

Was ist die Idee hinter der Verwendung einer Unterklasse einer Unterklasse von Password im Mapping?

Was hier passiert, ist, dass Sie eine spezifische Implementierung erfordern auf die anhalten serialisiert werden. In Ihrem Fall implementiert Ihr Objekt die Elternklasse (SecurePassword), so dass es nicht in MediumSecurePassword umgewandelt werden kann.

Ich werde beraten die Eltern-Klasse in der Abbildung zu verwenden, auf diese Weise Sie beide SecurePassword und MediumSecurePassword in Ihrer Implementierung nutzen können:

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

Oh mein Gott. Du hast absolut recht. Ich war so dumm. Danke für deinen Hinweis Mann. Das Ändern des Klassennamens hat den Trick gemacht. – Timo

Verwandte Themen