Hibernate:“InstantiationException:无法实例化抽象类或接口”

时间:2011-09-21 15:28:51

标签: hibernate abstract-class

我有以下课程hierachy:

public class MailAccount{
 IncomingMailServer incomingServer;
 OutgoingMailServer outgoingServer;
}

public class MailServer{
 HostAddress hostAddress;
 Port port;
}

public class IncomingMailServer extends MailServer{
 // ...
}

public class OutgoingMailServer extends MailServer{
 // ...
}

public class ImapServer extends IncomingMailServer{
 // ...
}

public class Pop3Server extends IncomingMailServer{
 // ...
}

public class SmtpServer extends OutgoingMailServer{
 // ...
}

我的(简化)映射文件如下所示:

<?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="com.mail.account">
    <class name="MailAccount" table="MAILACCOUNTS" dynamic-update="true">

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

        <component name="incomingServer">
            <component name="hostAddress">
                <property name="address" column="IS_HOST_ADDRESS"></property>
            </component>

            <component name="port">
                <property name="portNumber" column="IS_PORT_NUMBER"></property>
            </component>
        </component>

        <component name="outgoingServer">
            <component name="hostAddress">
                <property name="address" column="OS_HOST_ADDRESS"></property>
            </component>

            <component name="port">
                <property name="portNumber" column="OS_PORT_NUMBER"></property>
            </component>
        </component>

    </class>
</hibernate-mapping>

问题:当我拨打session.save(mailAccountInstance);时,Hibernate会抛出此异常:

org.hibernate.InstantiationException: Cannot instantiate abstract class or interface: IncomingMailServer

因此,我将以下行添加到incomingServer组件:

<discriminator column="SERVER_TYPE" type="string"/>
<subclass name="ImapServer" extends="IncomingMailServer" discriminator-value="IMAP_SERVER" />           
<subclass name="Pop3Server" extends="IncomingMailServer" discriminator-value="POP3_SERVER" />

到传出服务器:

<discriminator column="SERVER_TYPE" type="string"/>
<subclass name="SmtpServer" extends="OutgoingMailServer" discriminator-value="SMTP_SERVER" />

但是现在,Hibernate给了我这个错误信息:

org.xml.sax.SAXParseException: The content of element type "component" must match "(meta*,tuplizer*,parent?,(property|many-to-one|one-to-one|component|dynamic-component|any|map|set|list|bag|array|primitive-array)*)".

显然,Hibernate不喜欢组件中的这些标签。

我该如何解决这个问题?

Ps:我已经尝试将IncomingServer和OutgoingServer各自移动到他们自己的表中并通过一对一映射它们。这有效但导致数据库不一致,因为我注意到MailAccount和IncomingServer / OutgoingServer必须始终具有相同的主键ID。如果没有,一切都不同步,主键的自动增量值不再匹配(在Mailaccount和服务器之间)。

2 个答案:

答案 0 :(得分:4)

这个映射对我有用:

Hibernate Mapping

                                                          

<class name="MailServer" abstract="true" table="SERVER">
    <id name="id" column="id">
        <generator class="native" />
    </id>
    <discriminator column="SERVER_TYPE" type="string"/>
    <subclass name="IncomingMailServer" abstract="true">
        <property name="address" column="IS_HOST_ADDRESS"></property>
        <property name="portNumber" column="IS_PORT_NUMBER"></property>
    </subclass>           
    <subclass name="OutgoingMailServer" abstract="true">
           <property name="address" column="OS_HOST_ADDRESS"></property>
           <property name="portNumber" column="OS_PORT_NUMBER"></property>
    </subclass>           
</class>

<subclass name="IMAPServer" extends="com.mail.account.IncomingMailServer" 
          discriminator-value="IMAP_SERVER"/>
<subclass name="POP3Server" extends="com.mail.account.IncomingMailServer" 
          discriminator-value="POP3_SERVER"/>
<subclass name="SMTPServer" extends="com.mail.account.OutgoingMailServer" 
          discriminator-value="SMTP_SERVER" />

类层次结构

抽象类:

  • MailServer是一个抽象类
  • IncomingServer是一个抽象类:这有助于不指定DISCRIMINATOR VALUE
  • OutgoingServer是一个抽象类:这有助于不指定DISCRIMINATOR VALUE

具体课程:

  • IMAPServer使用DISCRIMINATOR VALUE : IMAP
  • 扩展IncomingServer
  • POP3Server使用DISCRIMINATOR VALUE : POP3
  • 扩展IncomingServer
  • SMTPServer使用DISCRIMINATOR VALUE : SMTP
  • 扩展IncomingServer

所有具体服务器都映射到同一个表“SERVER”,但是如果需要,可以使用连接表将它们映射到各个表。

enter image description here

代码段

我能够使用以下简单的代码片段保存实例:

    Session session = HibernateUtil.getSessionFactory().getCurrentSession();
    Transaction txn =session.beginTransaction();
    IMAPServer imap=new IMAPServer();
    imap.setAddress("SMTP_01");
    imap.setPortNumber("SMTP_PORT_0001");
    session.save(imap);
    SMTPServer smtp=new SMTPServer();
    smtp.setAddress("STMP_01");
    smtp.setPortNumber("STMP_PORT_0001");
    session.save(smtp);

    MailAccount account=new MailAccount();
    account.setIncomingServer(imap);
    account.setOutgoingServer(smtp);

    session.save(account);
    txn.commit();

如果这解决了问题,请告诉我。 :)

编辑:将邮件从MailAccount添加到MailServer。

<class name="MailAccount" table="MAILACCOUNT" dynamic-update="true">
    <id name="id" column="id">
        <generator class="native" />
    </id>
    <many-to-one name="incomingServer" column="incoming" unique="true"/>
    <many-to-one name="outgoingServer" column="outgoing" unique="true"/>
</class>

答案 1 :(得分:0)

我的方法是:

  • 使用鉴别器和all创建一个实体(使用它自己的映射)MailServer。将它标记为抽象只是为了确定。
  • 使用自己的鉴别器创建MailServer的层次结构(每个一个hbm)。
  • 将MailAccount与2个一对一关系映射到MailServer。一个传入,一个传出。

而且,请告诉我们更多代码。如果不知道就很难提供帮助:)