0

次の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()だから、私にとっては、 ?を介してパスワードのハッシュ値を取得することに問題があるようです。でもわからない。

4

1 に答える 1

3

マッピングでパスワードのサブクラスのサブクラスを使用する背後にある考え方は何ですか?

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

ここで何が起こるかというと、永続化で特定の実装をシリアル化する必要があるということです。この場合、オブジェクトは親クラス(SecurePassword)を実装しているため、MediumSecurePasswordにキャストすることはできません。

マッピングで親クラスを使用することをお勧めします。これにより、実装でSecurePasswordとMediumSecurePasswordの両方を使用できるようになります。

        <component name="password" class="com.foo.web.model.authentication.Password">
            <property name="hash" column="PASSWORD" />
        </component>
于 2012-04-06T13:38:19.337 に答える