Final goal:
Have a few java objects sharing the same base class persisted into a database while each one having its own self-contained table with all own/inherited objects, and a simple auto-generated by the database id.
Very simple requirement. Impossible (?) with Hibernate!
What I have so far (using MySQL, Hibernate XML mapping):
map.hbm.xml
<?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 default-access="field"
default-lazy="false">
<class name="xyz.url.hibernate.EntityBase" abstract="true">
<id name="m_id" column="id">
<generator class="identity" />
</id>
<version name="m_version" column="version" type="long" />
<union-subclass name="xyz.url.hibernate.User" table="my_entity">
<property name="name" column="name" type="string" />
</union-subclass>
</class>
</hibernate-mapping>
EntityBase.java
public abstract class EntityBase {
private final long m_id;
private final long m_version;
public EntityBase() {
this.m_id = 0;
this.m_version = 0;
}
public long get_id() {
return this.m_id;
}
public long get_version() {
return this.m_version;
}
}
User.java
public class User extends EntityBase {
public String name;
}
The above does not work unless you change the generator class to increment.
Currently this is the given error:
org.hibernate.MappingException: Cannot use identity column key generation with <union-subclass> mapping for: xyz.url.hibernate.User
Well, why does Hibernate ASSUMES I want a unique ID in a program-wide scope (I've read about some JPA requirement)... what a crap!
Anyway, I insist of having a simple table (per object) that aggregates all the object's (User in this case) properties, and deny using discriminators (again what a crap..) which just complicate the final SQL queries and hit performance.
The only solutions I see here:
Manually map all properties in a one block inside the XML.
Map all properties while "importing" some <propert> items from an external file, thus achieve inheritance (reusage of properties). Possible? How to do?!?
Explore annotations further which as far as I've seen they don't support that simple inheritance requirement.
Dump Hibernate and go with another ORM solution.
Please don't link to the docs - I gave up on that one after reading them a few times!
An example of property import (from external file) would be great.
Thanks and god bless!
First of all you need to decide whether your inheritance relationship should be mapped to the database (to allow polymorphic queries such as from EntityBase, polymorphic realtionships, etc) or not.
As far as I understand in your case it shouldn't be mapped, therefore it doesn't make sense to use inheritance mapping options such as <union-subclass> at all. Now you have the following options:
2. Hibernate doesn't have special support for reuse of XML mappings, but its documentation suggests to use XML entities in this case, see, for example, 10.1.6. Table per concrete class using implicit polymorphism.
3. Annotations certainly support this requirement in form of #MappedSuperclass annotation.
This annotation can be used to mark a class that is not mapped to the database itself, but any mapping annotations defined on its properties take effect for its mapped subclasses, so that you don't need to repeat them.
You can also use XML Entity Reference, see:
https://n1njahacks.wordpress.com/2014/09/19/hibernate-xml-mapping-fragment-re-use/
http://xml.silmaril.ie/includes.html
Related
I have a small hibernate application as above:
BankAccount class is as follows:
package in.co.way2learn;
import java.util.Set;
public class BankAccount {
private int accountNumber;
private String accountHoldersName;
private int balance;
private Address address;
private Set<String> emails;
//setters and getters
}
Address class is as below:
package in.co.way2learn;
public class Address {
private String addressLine1;
private String addressLine2;
private String city;
private String country;
private int pinCode;
//setters and getters
}
BankAccount.hbm.xml file is as below:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated Jul 2, 2014 3:59:34 PM by Hibernate Tools 3.4.0.CR1 -->
<hibernate-mapping package="in.co.way2learn">
<class name="BankAccount">
<id name="accountNumber" type="integer">
<generator class="assigned"/>
</id>
<property name="accountHoldersName" type="string"/>
<property name="balance" type="integer"/>
<component name="address" class="Address" lazy="true">
<property name="addressLine1"/>
<property name="addressLine2"/>
<property name="city"/>
<property name="country"/>
<property name="pinCode"/>
</component>
<set name="emails" order-by="email asc" table="bankaccount_emails">
<key column="SNo"/>
<element column="email" type="string"/>
</set>
</class>
</hibernate-mapping>
hibernate.cfg.xml file is as below:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="hibernate.connection.driver_class">
org.gjt.mm.mysql.Driver
</property>
<property name="hibernate.connection.password">root</property>
<property name="hibernate.connection.url">
jdbc:mysql://localhost:3306/way2learnDB
</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.dialect">
org.hibernate.dialect.MySQLInnoDBDialect
</property>
<property name="hibernate.show_sql">true</property>
<property name="hibernate.format_sql">true</property>
<property name="hibernate.hbm2ddl.auto">update</property>
<mapping resource="in/co/way2learn/BankAccount.hbm.xml"/>
</session-factory>
</hibernate-configuration>
Now my question is in BankAccount.hbm.xml file in the component tag I am using using lazy="true", when ever I am firing select query on BankAccount class using session.get(BankAccount.class, 1235); It is loading address details also from database, the code I used to fire select query is below:
Session session=sessionFactory.openSession();
Transaction transaction=session.beginTransaction();
BankAccount bankAccount=(BankAccount)session.get(BankAccount.class, 1235);
transaction.commit();
session.close();
The query fired is
Hibernate:
select
bankaccoun0_.accountNumber as accountN1_0_0_,
bankaccoun0_.accountHoldersName as accountH2_0_0_,
bankaccoun0_.balance as balance3_0_0_,
bankaccoun0_.addressLine1 as addressL4_0_0_,
bankaccoun0_.addressLine2 as addressL5_0_0_,
bankaccoun0_.city as city6_0_0_,
bankaccoun0_.country as country7_0_0_,
bankaccoun0_.pinCode as pinCode8_0_0_
from
BankAccount bankaccoun0_
where
bankaccoun0_.accountNumber=?
But I am expecting address details will be loaded lazily from database when ever I used bankAccount.getAddress() method only?
Now can any one please explain why hibernate is loading address details eagerly, and how to load then lazily?
Take an example from below code:-
class B {
private C cee;
public C getCee() {
return cee;
}
public void setCee(C cee) {
this.cee = cee;
}
}
class C {
// Not important really
}
Right after loading B, you may call getCee() to obtain C. But look, getCee() is a method of your class and Hibernate has no control over it. Hibernate does not know when someone is going to call getCee(). That means Hibernate must put an appropriate value into "cee" property at the moment it loads B from database.
If proxy is enabled for C, Hibernate can put a C-proxy object which is not loaded yet, but will be loaded when someone uses it. This gives lazy loading for one-to-one.
But now imagine your B object may or may not have associated C (constrained="false"). What should getCee() return when specific B does not have C? Null. But remember, Hibernate must set correct value of "cee" at the moment it set B (because it does no know when someone will call getCee()). Proxy does not help here because proxy itself in already non-null object.
If your B->C mapping is mandatory (constrained=true), Hibernate will use proxy for C resulting in lazy initialization. But if you allow B without C, Hibernate just HAS TO check presence of C at the moment it loads B. But a SELECT to check presence is just inefficient because the same SELECT may not just check presence, but load entire object. So lazy loading goes away.
Workaround1 : - Just add annotation or entry in hdm file for #JoinColumn for reference private Address address;.
Workaround2 :- add optional=false in OneToOne relationship
Other solutions for this problem:
The simplest one is to fake one-to-many relationship. This will work because lazy loading of collection is much easier then lazy loading of single nullable property but generally this solution is very inconvenient if you use complex JPQL/HQL queries.
The other one is to use build time bytecode instrumentation. For more details please read Hibernate documentation: 19.1.7. Using lazy property fetching. Remember that in this case you have to add #LazyToOne(LazyToOneOption.NO_PROXY) annotation to one-to-one relationship to make it lazy. Setting fetch to LAZY is not enough.
The last solution is to use runtime bytecode instrumentation but it will work only for those who use Hibernate as JPA provider in full-blown Java EE environment (in such case setting "hibernate.ejb.use_class_enhancer" to true should do the trick: Entity Manager Configuration) or use Hibernate with Spring configured to do runtime weaving (this might be hard to achieve on some older application servers). In this case #LazyToOne(LazyToOneOption.NO_PROXY) annotation is also required.
This will work for you.
Hibernate does not create proxies for components, that's why lazy loading does not work for them.
Solutions:
Use bytecode instrumentation to enable lazy loading of non-entity fields. It has its own pitfalls and is not widely adopted.
Use two different classes for BankAccount, one containing the Address component (as it is now), and one without it, and map them to the same table. Then, use the one without address in contexts in which you don't need addresses.
Use fake one-to-one association between BankAccount and Address by making Address component an entity and mapping it to the same table. The drawback here is that you must not insert the Address instances (because you'll end up trying to insert a separate row in the table), but rather you have to read and update it after you insert the corresponding BankAccount entity instance.
Change the db schema and move the component to its own separate table. Then simply promote the component to an entity and map it to the new table.
I have 2 identical DB instances containing FOO_TABLE with the same schema. So, currently I have one class definition per DB instance:
<class name="FooTable" table="FOO_TABLE" entity-name="FooTableInstance1">
<property name="..." column="..." />
<property name="..." column="..." />
....
</class>
<class name="FooTable" table="FOO_TABLE" entity-name="FooTableInstance2">
<property name="..." column="..." />
<property name="..." column="..." />
....
</class>
The problem is that I don't want to copy-paste the properties, as the tables have the same schema. Is it possible to inherit the 2 classes from a base class which contains all the mappings and in the 2 children classes specify different entity-name?
An alternative (and perhaps the correct one if I understand your question correctly) is to use a #MappedSuperclass to define the common mappings. Whether you use this or the suggestion posted previously depends on the data model: for example are these two entities related so that you would like to be able to query across both of them?
e.g. select f from Foo returns all Foo1 and Foo2.
This cannot be done when Foo is a MappedSuperclass.
See here for further details:
http://en.wikibooks.org/wiki/Java_Persistence/Inheritance#Mapped_Superclasses
JPA: Implementing Model Hierarchy - #MappedSuperclass vs. #Inheritance
Yes, it is possible. Take a look at the relevant documentation: http://docs.jboss.org/hibernate/core/3.3/reference/en/html/inheritance.html
More specifically, check 9.1.5. Table per concrete class. Make the parent class abstract and things should work fine.
According to the documentation you need 3 Java classes:
Foo (abstract, containing all fields you want in both tables)
FooChild1 (concrete, subclass of Foo, containing no new fields)
FooChild2 (concrete, subclass of Foo, containing no new fields)
You will need two tables. One mapping to FooChild1, and another to FooChild2.
TL;DR How can I enforce the Hibernate schema creation to create a foreign key constraint in a table-per-concrete-class setup from AbstractProperty.ownerId to Owner.ownerId for the structure displayed below, without adding a Owner property to the AbstractProperty?
I'm working on a project where I have the following class structure:
The Owner has a one-to-one mapping to an AbstractProperty, which is extended by the ConcreteProperty class (and others like AnotherProperty, but that's not really relevant for the rest of this question).
The AbstractProperty really has only one property, the abstractPropertyId. Therefor, we want to use the table-per-concrete-class structure, ending up with the tables Owner, ConcreteProperty, and tables for the other AbstractProperty extending classes (AnotherProperty).
To this end, I created the following mapping for Owner:
<?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.example">
<class name="Owner">
<id name="ownerId">
<generator class="identity"/>
</id>
<property name="ownerProperty"/>
<one-to-one name="abstractProperty"/>
</class>
</hibernate-mapping>
And for the AbstractProperty:
<?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.example">
<class name="AbstractProperty" abstract="true">
<id name="ownerId">
<generator class="foreign">
<param name="property">ownerId</param>
</generator>
</id>
<union-subclass name="ConcreteProperty">
<property name="concreteProperty"/>
</union-subclass>
<union-subclass name="AnotherProperty">
<property name="anotherProperty"/>
</union-subclass>
</class>
</hibernate-mapping>
This works.
However, and here is my question, using this mapping and having Hibernate create the schema for me (<property name="hbm2ddl.auto">create</property>), it does not create a foreign key constraint from the ConcreteProperty.ownerId database field to the Owner.ownerId field. It does when I create the inverse constrained one-to-one field from the AbstractProperty to Owner using this mapping for AbstractProperty (where the owner field is of type Owner in the AbstractProperty java class):
<?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.example">
<class name="AbstractProperty" abstract="true">
<id name="ownerId">
<generator class="foreign">
<param name="property">ownerId</param>
</generator>
</id>
<one-to-one name="owner" constrained="true"/>
<union-subclass name="ConcreteProperty">
<property name="concreteProperty"/>
</union-subclass>
<union-subclass name="AnotherProperty">
<property name="anotherProperty"/>
</union-subclass>
</class>
</hibernate-mapping>
How can I enforce the creation of a foreign key from AbstractProperty.ownerId to Owner.ownerId without this Owner field in my AbstractProperty?
Simple answer: Never let Hibernate create the schema for real applications.
Hibernate is an object relational mapper and one should treat it as this.
That Hibernate additionally creates schemas is at most kind for the first time. But in environments after the first release you don't want to have Hibernate control over the schema. After all you have to handle SQL to have migrations scripts (manually or tool support). After the first release you will have data in the database. To ensure data migration on the production system with less problems you should consider schema and data migration the same way in the production environment as you do in your development environment.
Exceptions of that can be any application that has rarely changing data that may be reconstructable fast on data loss.
We use standard JPA (no hibernate-specific hacks) and had the same problem, and we did not find a nice solution.
Assumptions:
AbstractProperty is a class in a package that is reusable/shared in different applications, and that you don't want a reference to an application specific Owner Class.
ConcreteProperty & AnotherProperty is application specific.
In this case, the solution would be to put references in ConcreteProperty to the Owner (with foreign keys), eventually both with AnotherProperty extending the same ApplicationProperty, and making the abstractPropertyId private, so that on setting the Owner, it is set automatically.
Wouldn't it work automatically if you define the Owner attribute on Abstract Property as "transient"?
Variables may be marked transient to indicate that they are not part of the persistent state of an object.
And if you implement your own manual serialization you could check for the Modifier on a field and just ignore it --> cyclic serialization problem avoided.
The only other way I see is to push the Owner attribute to each of the concrete Property classes and change your mapping to
<class name="AbstractProperty" abstract="true">
<id name="ownerId">
<generator class="foreign">
<param name="property">ownerId</param>
</generator>
</id>
<union-subclass name="ConcreteProperty">
<property name="concreteProperty"/>
<one-to-one name="owner" constrained="true"/>
</union-subclass>
<union-subclass name="AnotherProperty">
<property name="anotherProperty"/>
<one-to-one name="owner" constrained="true"/>
</union-subclass>
</class>
which creates the following sql:
create table AnotherProperty (
ownerId integer not null,
anotherProperty varchar(255),
primary key (ownerId)
)
create table ConcreteProperty (
ownerId integer not null,
concreteProperty varchar(255),
primary key (ownerId)
)
create table Owner (
ownerId integer generated by default as identity,
ownerProperty varchar(255),
primary key (ownerId)
)
alter table AnotherProperty
add constraint FK_ceq89n6x2i1ax18bb4gqpq4m5
foreign key (ownerId)
references Owner
alter table ConcreteProperty
add constraint FK_i41buhvtxxtpsim2cc0ur1gxr
foreign key (ownerId)
references Owner
First : Hibernate/JPA is capable of handling a lot of scenarios - if there really was a lot of folks trying the same approach as you, I would think that it would have been addressed by now - it's no spring chicken. ** that's a clue ;-) **
Second : Having a table called 'Owner' with a 'ownerProperty' is another clue. The names infer a built in relationship.
Third : Simply by stating that you don't want an owner property within the AbstractProperty table, this sets the stage for a logical fallacy commonly referred to as a catch-22 (http://en.wikipedia.org/wiki/False_dilemma).
My point -> This seems to be more of a modeling/design issue than a technical/framework issue.
My suggestion would be to take a step back from the problem, and re-evaluate it. For example, if you were just writing straight queries with spring-jdbc, how would you expect to interact with the data for SELECT, UPDATE, and DELETE operations? ... if you work through those, your solution/needs would likely present themselves more clearly. To be even more pointed, what would you expect the behavior to be on a cascading-delete? If I issue a DELETE statement on a single Owner record, would you like for the database to automatically delete the records from the child tables? recursively? Once you have that isolated, you can figure out how to tell Hibernate what to do - don't allow team members to put the cart before the horse by prematurely restricting the solution.
For example, (case 1 ) if you're really dealing with a 'property' of an owner, it would be reasonably foreseeable that you would need to store multiple properties about an owner (aka: OneToMany).
Alternatively, (case 2 ) if you're dealing with a 'type' of owner ( as in a discriminator field ), then your 'AbstractProperty' table should be extending Owner ... in which case you may be able to reduce your solution down to 3 tables ( Owner with a discriminator, Concrete1 w/ ownerId, Concrete2 w/ ownerId ).
Proposed Solution 1 : In either of those cases, it would still make sense for the 'AbstractProperty' table to have a reference to it's parent/Owner. And if it did, I think Cascading DELETES may work the way that you would prefer.
Proposed Solution 2 : If however, in a cascading delete scenario of an Owner record, you would prefer that the row(s) in AbstractProperty stick around as reference-data, then it could be argued that you should put an additional table between Owner and AbstractProperty to protect your reference data ... as a mapping table that has a unique composite key.
Focus on the business needs and user-stories, and that should hopefully guide your choice of available solutions.
I'd like to map a domain model to a relational database using one of the ORM frameworks for Java. Unfortunately, none of them seem to have adequate support for classes implementing multiple interfaces. Say I want to map something like:
public interface Quotable {
}
public interface Tradable {
}
// StockIndex only implements Quotable as it cannot be trade directly
public class StockIndex implements Quotable {
}
// Stock implements both interfaces as there are market quotes and can be traded
public class Stock implements Quotable, Tradable {
}
public class Quote {
private Quotable quotable;
}
public class Trade {
private Tradable tradable;
}
So what I'm trying to achieve is that a Quote can reference any Quotable (Stock, StockIndex and others) while a Trade can only reference Tradable entities. I've tried OpenJPA and (plain) Hibernate with no luck even though the latter's support for interfaces looked promising.
Is there any framework that can handle my scenario? Or are there any good reasons why this shouldn't be mapped to a database? If so, how should my model be modified?
My initial Hibernate mapping looked something like this (I'm not showing any OpenJPA stuff as it doesn't support interface inheritance or at least I couldn't figure out how):
<hibernate-mapping package="com.foo">
<class name="Quotable" table="quotable" >
<id type="java.lang.Long" column="id">
<generator class="sequence" />
</id>
<discriminator column="type" type="string" />
<subclass name="StockIndex">
<join table="stock_index" >
<key column="id"/>
<property name="name" column="name" access="field" />
</join>
</subclass>
<subclass name="Stock">
<join table="stock" >
<key column="id"/>
<property name="name" column="name" access="field" />
</join>
</subclass>
</class>
</hibernate-mapping>
This is pretty much identical to the example in the Hibernate documentation and results in a table quotable with an id and a string discriminator column, a table stock_index with an id and the index' name and a table stock with an id and the stock's name. So far so good...
But what shall I do with the Tradeable interface? I would have to setup a separate hierarchy and map Stock in both hierarchies. I did try this but had to define different entity names for Stock (and needed to include this patch) but this also didn't work due to foreign key violations. I tried a couple of other obscure things that didn't work either.
Anyway, mapping Stock twice wouldn't be a good solution as the application would have to remember adding Stock instances twice - once for each interface. I'd rather have the framework handle this automaticaly.
Ideally Hibernate would allow extending multiple interfaces, i.e. something like (note the extends attribute on the subclass element):
<subclass name="Stock" extends="Quotable, Tradable" >
<join table="stock" >
<key column="id"/>
<property name="name" column="name" access="field" />
</join>
</subclass>
Any other ideas how my example can be mapped? I've now learned about the <any> element which looks like it might work for me but I have yet to understand all its implications.
How about other frameworks? I've heard EclipseLink also has some support for interfaces but it's not well documented.
I don't think you will find any ORM able to handle interfaces hierarchy nicely.
So I won't talk about ORMs here but I'm going to show you how to implement your example using Qi4j.
Qi4j is an implementation of Composite Oriented Programming, using the standard Java platform and a framework for domain centric application development, including evolved concepts from AOP, DI and DDD. See http://qi4j.org
In Qi4j, domain state is modeled using Entities and Values. In the following code sample I assume that everything is an Entity but your mileage may vary.
As Entities are declared using only interfaces, your use case should fit in nicely.
interface Quotable { ... }
interface Tradable { ... }
interface StockIndex extends Quotable { ... }
interface Stock extends Quotable, Tradable { ... }
interface Quote {
Association<Quotable> quotable();
}
interface Trade {
Association<Tradable> tradable();
}
You can then store theses in an EntityStore and use the Query API to retrieve them easily (and in a fully polymorphic way).
Note that Qi4j EntityStores are not only SQL based but support NoSQL databases too. See the available extensions here: http://qi4j.org/latest/extensions.html
See the Qi4j documentation if you have more questions.
I am currently trying to replace my own database controller implementation with Hibernate and I have the following problem creating an appropriate mapping file.
(I am very new to Hibernate, so please be gentle :-) - I've read through the whole Hibernate Reference documentation but I don't have any practical experience yet).
(The whole thing should represent the relationship between email accounts and their server settings).
I have a class called MailAccount which has 2 properties (see code below):
public class MailAccount{
long id;
IncomingMailServer incomingServer;
OutgoingMailServer outgoingServer;
public MailAccount(){
super();
}
// Getter and setter omitted
}
The server class hierachy looks like this:
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();
}
}
The properties incomingServer and outgoingServer in MailAccount.java of course only hold instances of either Pop3Server, ImapServer (for incomingServer) or SmtpServer (for outgoingServer).
Now, I tried to create the mapping file for 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>
Note: Since I got a 1:1 relation between MailAccount and IncomingMailServer as well as MailAccount and OutgoingMailServer, I want everything in 1 table in order to prevent unnecessary joins.
The problem: Whenever I tell Hibernate to save an instance of MailAccount, like this:
session = getSession();
transaction = session.beginTransaction();
session.save(mailAccount);
transaction.commit();
.. I get the following exception:
org.hibernate.InstantiationException:
Cannot instantiate abstract class or
interface:
test.server.incoming.IncomingMailServer
This totally makes sense since abstract classes cannot be instantiated.
However, here comes my question: How can I tell Hibernate to create an instance of the right class (Pop3Server, SmtpServer, ImapServer) instead of the abstract ones?
Example: If the property incomingServer holds an instance of Pop3Server, then Hiberante should store that into my database and when I load the according MailAccount back, I want Hibernate to recreate an instance of Pop3Server.
The problem is occurring because a component is not a stand-alone entity, but "a class whose instances are stored as an intrinsic part of an owning entity and share the identity of the entity". In JPA terms it is considered an Embeddable class. These classes are usually used to create a class object out of a number of table columns that would normally have to be stored as individual attributes in an entity (you can almost look at it as grouping).
While there are a number of benefits to this approach, there are some restrictions. One of these restrictions are that the component or embeddable cannot be an abstract class. The reason being that there isn't any way for hibernate to associate a particular concrete subclass with the value you are trying to store or read. Think of it this way: would you be able to tell what instance to create by only looking at the column data? It's usually not that straight forward, especially for the persistence engine.
In order to get the functionality you desire, you will want to look into storing MailServer data as a separate entity with its own primary key field. Doing so allows you to manage the data with subclasses using various inheritance methods such as including a DiscriminatorColumn or separate tables (depending on your configuration).
Here are some links that should help you with setting up these mappings and using entity inheritance:
One-to-One mapping example
(useful if not reusing MailServer
data.
Inheritance overview
Useful Hibernate examples (not
latest spec, but gives you good
overview)
Hope this helps.
http://www.vaannila.com/hibernate/hibernate-example/hibernate-example.html
If you were to use this approach using Hibernate (I personally prefer JPA-based Annotation configurations), you could configure MailServer as an abstract entity that would define the common column mappings between the classes and a DiscriminatorColumn (if using same table inheritance). The subclasses would be built off of this definition, adding custom attributes as needed.