org.hibernate.InstantiationException:如何告诉Hibernate用于对象实例化的类

时间:2011-04-29 18:20:46

标签: java hibernate persistence subclass

我目前正在尝试用Hibernate替换我自己的数据库控制器实现,并且我在创建适当的映射文件时遇到以下问题。

(我对Hibernate很新,所以请温柔:-) - 我已经阅读了整个Hibernate Reference文档,但我还没有任何实际经验。)

(整个事情应代表电子邮件帐户与其服务器设置之间的关系)。

我有一个名为MailAccount的类,它有2个属性(参见下面的代码):

public class MailAccount{
    long id;
    IncomingMailServer  incomingServer;
    OutgoingMailServer  outgoingServer;

    public MailAccount(){
        super();
    }

    // Getter and setter omitted
}

服务器类层次结构如下所示:

MailServer.java

public abstract class MailServer {
    String password;
    String host;
    String username;
    String port;

    // Getter and setter omitted
}

IncomingMailServer.java

public abstract class IncomingMailServer extends MailServer {
}

OutgoingMailServer.java

public abstract class OutgoingMailServer extends MailServer {
}

Pop3Server.java

public class Pop3Server extends IncomingMailServer{
    public Pop3Server(){
        super();
    }
}

ImapServer.java

public class ImapServer extends IncomingMailServer{
    public ImapServer(){
        super();
    }
}

SmtpServer.java

public class SmtpServer extends OutgoingMailServer{
    public SmtpServer(){
        super();
    }
}

MailAccount.java中的incomingServer和outgoingServer属性当然只包含Pop3Server,ImapServer(对于incomingServer)或SmtpServer(对于outgoingServer)的实例。

现在,我尝试为MailAccount创建映射文件:

<?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">
<hibernate-mapping package="test.account">
    <class name="MailAccount" table="MAILACCOUNTS" dynamic-update="true">

        <id name="id" column="MAIL_ACCOUNT_ID">
            <generator class="native" />
        </id>

        <component name="incomingServer" class="test.server.incoming.IncomingMailServer">
            <property name="password" column="INCOMING_SERVER_PASSWORD" />
            <property name="host" column="INCOMING_SERVER_PASSWORD" />
            <property name="username" column="INCOMING_SERVER_PASSWORD" />
            <property name="port" column="INCOMING_SERVER_PASSWORD" />
        </component>

        <component name="outgoingServer" class="test.server.outgoing.OutgoingMailServer">
            <property name="password" column="OUTGOING_SERVER_PASSWORD" />
            <property name="host" column="OUTGOING_SERVER_PASSWORD" />
            <property name="username" column="OUTGOING_SERVER_PASSWORD" />
            <property name="port" column="OUTGOING_SERVER_PASSWORD" />
        </component>
    </class>
</hibernate-mapping>

注意:由于我在MailAccount和IncomingMailServer以及MailAccount和OutgoingMailServer之间建立了1:1的关系,我希望1表中的所有内容都能防止不必要的连接。

问题:每当我告诉Hibernate保存一个MailAccount实例时,就像这样:

session = getSession();
transaction = session.beginTransaction();
session.save(mailAccount);
transaction.commit();

..我收到以下异常:

  

org.hibernate.InstantiationException:   无法实例化抽象类或   接口:   test.server.incoming.IncomingMailServer

这完全有道理,因为抽象类无法实例化。

然而,这里是我的问题:我如何告诉Hibernate创建一个正确类的实例(Pop3Server,SmtpServer,ImapServer)而不是抽象的实例?

示例:如果属性incomingServer拥有Pop3Server的实例,那么Hiberante应该将其存储到我的数据库中,当我加载相应的MailAccount时,我希望Hibernate重新创建Pop3Server的实例。 / p>

1 个答案:

答案 0 :(得分:4)

问题出现是因为组件不是独立的实体,而是“a class whose instances are stored as an intrinsic part of an owning entity and share the identity of the entity”。在JPA术语中,它被认为是Embeddable类。这些类通常用于从多个表列中创建一个类对象,这些表通常必须作为单个属性存储在实体中(您几乎可以将其视为分组)。

虽然这种方法有很多好处,但也存在一些限制。其中一个限制是组件或嵌入式不能是抽象类。原因是hibernate没有办法将特定的具体子类与您尝试存储或读取的值相关联。可以这样想一想:您是否能够通过查看列数据来判断要创建的实例?它通常不是那么直接,特别是对于持久性引擎。

为了获得您想要的功能,您需要考虑将MailServer数据存储为具有自己的主键字段的单独实体。这样做允许您使用各种继承方法管理子类的数据,例如包括DiscriminatorColumn或单独的表(取决于您的配置)。

以下是一些可以帮助您设置这些映射和使用实体继承的链接:

希望这有帮助。

http://www.vaannila.com/hibernate/hibernate-example/hibernate-example.html

如果你使用Hibernate使用这种方法(我个人更喜欢基于JPA的Annotation配置),你可以将MailServer配置为一个抽象实体,它将定义类和DiscriminatorColumn之间的公共列映射(如果使用相同的表继承)。子类将根据此定义构建,根据需要添加自定义属性。