开发者

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

I have the following 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{
 // ...
}

My (simplified) mapping file looks like this:

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

The problem: Hibernate throws this exception when I call session.save(mailAccountInstance);:

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

So, I added the following lines to the incomingServer component:

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

And to the outgoing server:

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

But now, Hibernate gives me this error message:

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)*)".

Obviously, Hibernate does not like these tags in components.

How could I work around this?

Ps: I already tried moving IncomingServer and OutgoingServer each to their own tables and map them via a one-to-one. That works but leads to inconsistencies in the database because I noticed that MailAccount and IncomingServer/OutgoingServer must always have the same primary key id. If not, everything gets out of sync and the autoincrement value for the primary keys don't match any more (between Mailaccount and Servers).


This mapping worked for me:

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

Class Hierarchy

Abstract classes:

  • MailServer is an abstract class
  • IncomingServer is an abstract class : this helped NOT specifing DISCRIMINATOR VALUE
  • OutgoingServer is an abstract class : this helped NOT specifing DISCRIMINATOR VALUE

Concrete classes:

  • IMAPServer extends IncomingServer with DISCRIMINATOR VALUE : IMAP
  • POP3Server extends IncomingServer with DISCRIMINATOR VALUE : POP3
  • SMTPServer extends IncomingServer with DISCRIMINATOR VALUE : SMTP

All the concrete servers are mapped to the same table "SERVER" however if need be they can be mapped to individual tables using join table.

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

Code Snippet

I was able to save the instances using the following simple code snippet:

    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();

Let me know if this solves the problem. :)

EDIT: added the mapping from MailAccount to 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>


My approach would be this:

  • Create a Entity (with it's own mapping) MailServer with discriminators and all. Mark it abstract just to be sure.
  • Create the hierarchy of MailServer (one hbm for each) with it's own discriminator.
  • Map MailAccount with 2 one-to-one relationships to MailServer. One incoming, one outgoing.

And, please, show us more code. It's hard to help without know :)

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜