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 Hierarchy
Abstract classes:
MailServer
is an abstract classIncomingServer
is an abstract class : this helped NOT specifingDISCRIMINATOR VALUE
OutgoingServer
is an abstract class : this helped NOT specifingDISCRIMINATOR VALUE
Concrete classes:
IMAPServer
extends IncomingServer withDISCRIMINATOR VALUE : IMAP
POP3Server
extends IncomingServer withDISCRIMINATOR VALUE : POP3
SMTPServer
extends IncomingServer withDISCRIMINATOR 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.
Code Snippet
I was able to save the instances using the following simple code snippet:
Let me know if this solves the problem. :)
EDIT: added the mapping from MailAccount to MailServer.
My approach would be this:
And, please, show us more code. It's hard to help without know :)