次のHibernate呼び出しを行うと、ClassCastException(Stacktraceを参照)が発生しますが、その理由を理解するのに問題があります。Hibernateはここで何をしようとしていますか?オブジェクトの1つを別のクラスタイプにキャストしようとしていますか?はいの場合、なぜ、どのクラスに?
session.save(fooAccount);
スタックトレース:
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)
編集:オブジェクトを格納するマッピングとコードは次のとおりです。
マッピングファイル(短縮バージョン。無関係なものは省略):
<?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()
だから、私にとっては、 ?を介してパスワードのハッシュ値を取得することに問題があるようです。でもわからない。