hibernate : "InstantiationException: Cannot instantiate abstract class or interface"

标签 hibernate abstract-class

我有以下类层次结构:

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

因此,我将以下几行添加到传入服务器组件中:

<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 和服务器之间)。

最佳答案

这个映射对我有用:

hibernate 映射

<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>

关于 hibernate : "InstantiationException: Cannot instantiate abstract class or interface",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7502455/

相关文章:

java - 如何使用带有 groovy 闭包的构造函数参数实例化 Java 抽象类

java - 从.sql加载模式以在Spring Boot中创建orm映射

java - hibernate 注释 - 使用 @MappedSuperclass 继承 - 值未设置为基类字段 - 奇怪的错误

java - 如何在 Spring Boot 和 Hibernate 中统计特定 id 的记录

c#-4.0 - 使用 Entity Framework 根据数据库行中的单元格映射到子类 POCO 对象

c++ - 前向声明的替代方案 : two classes using each other

java - 抽象类 NumberFormat - 对 getInstance() 非常困惑

java - Hibernate with SQLite 无法在数据库创建后第二次运行应用程序

java - 使用 Hibernate 保存对象

c# - 使用泛型类型 BaseUser 时出错需要 1 个参数