Java ORM: Multiple (interface) inheritance - java

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.

Related

Hibernate use same mapping for multiple tables

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.

hibernate simple inheritance - OR - xml property import/include

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

org.hibernate.InstantiationException: How to tell Hibernate which class to use for object instantiation

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.

Hibernate, Set keys, CompositeUserType and SQL Procedures

I am having some trouble with returning a non-empty Set into an object using Hibernate and a custom CompositeUserType key.
I have a set of tables and views (simplified here):
create table lang (lang_id,lang_cd);
create table article (art_id,...);
create table article_lang (art_id, lang_id,title,...);
create view article_lang_vw (select * from article join article_lang on art_id);
create table authors(user_id,...);
create table article_authors(art_id,lang_id,user_id);
And database functions:
create or replace procedure addarticle(title,art_id,lang_id) ...
create or replace procedure updatearticle(title,art_id,lang_id)..
create or replace procedure delarticle(art_id,lang_id)..
create or replace procedure addarticleauthor(user_id,art_id,lang_id)...
create or replace procedure delarticleauthor(user_id,art_id,lang_id)...
So to accomplish this mapping using those functions I had to implement CompositeUserType so now I have Java classes like this:
class ProcedureGenerator implements PostInsertIdentityGenerator ...
class Language { int lang_id }
class ArticleLangPKType implements CompositeUserType { //implemented methods }
class ArticleLangPK { int art_id; Language l; }
class Article { ArticleLangPK id; String title; Set<Author> authors; }
class Author { int user_id; String name; }
I want to have a List or Set of Authors. But cannot figure out how to map this part in the *.hbm.xml files. It currently looks something like this:
<class name="Author" mutable="false">
<id name="user_id"/>
<property name="name"/>
</class>
<class name="Article">
<id name="id" type="ArticleLangPKType">
<column name="art_id"/>
<column name="lang_id"/>
<generator class="ProcedureGenerator"/>
</id>
<property name="title"/>
<set name="authors" table="article_authors">
<key> <!-- <key type="ArticleLangPKType"> -->
<column name="art_id"/>
<column name="lang_id"/>
</key>
<many-to-many class="Author" table="article_authors" unique="true"/>
<!-- addauthor, delauthor sql here some how -->
</set>
<sql-insert callable="true">{call addarticle(?,?,?)}</sql-insert>
<sql-update callable="true">{call updatearticle(?,?,?)}</sql-update>
<sql-delete callable="true">{call adddelete(?,?)}</sql-delete>
</class>
But when I run this session.load(Article.class, pk) on an article I know has authors I get a Set size of zero. Otherwise I have no problems inserting, updating, deleting using Hibernate, but now I am stumped. This seems to me to indicate a problem with my ArticleLangPKType.
Any ideas what to do to complete this? Why is my Set always size 0? How would I save the author using the Article's Set and the SQL procedures as provided? Is Hibernate right for me? Do I need a break to see this clearly?
Thanks in advance!
Nevermind I did need a long break. My ArticleLangPK did not override hashCode and Equals correctly. Now just to figure out how to call those other two stored procedures correctly.

Changing the inheritance strategy in branches of the class hierarchy via JPA annotations

Today I faced an interesting issue. I've been having an inheritance hierarchy with Hibernate JPA, with SINGLE_TABLE strategy. Later, I added a superclass to the hierarchy, which defined TABLE_PER_CLASS strategy. The result was that the whole hierarchy stared behaving as TABLE_PER_CLASS. This, of course, seems fair, if we read the #Inheriatance javadoc:
Defines the inheritance strategy to be used for an entity class hierarchy. It is specified on the entity class that is the root of the entity class hierarchy.
Hibernate docs, however, say that:
It is possible to use different mapping strategies for different branches of the same inheritance hierarchy
And continues on the exemptions from this statement. This is done via XML configuration.
So, finally, my question is - is there a way (a hibernate property, perhaps) to enable the aforementioned xml behaviour via annotations, and using EntityManager.
Well, if you read the "Inheritance" chapter of Hibernate documentation a little further :-) you'll see that the example given for mixing table-per-hierarchy and table-per-subclass strategies is in reality nothing more than table-per-hierarchy with secondary tables thrown in:
<class name="Payment" table="PAYMENT">
<id name="id" type="long" column="PAYMENT_ID">
<generator class="native"/>
</id>
<discriminator column="PAYMENT_TYPE" type="string"/>
<property name="amount" column="AMOUNT"/>
...
<subclass name="CreditCardPayment" discriminator-value="CREDIT">
<join table="CREDIT_PAYMENT">
<property name="creditCardType" column="CCTYPE"/>
...
</join>
</subclass>
<subclass name="CashPayment" discriminator-value="CASH">
...
</subclass>
</class>
You can do the same using #SecondaryTable annotation:
#Entity
#Inheritance(strategy=InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name="PAYMENT_TYPE")
#DiscriminatorValue("PAYMENT")
public class Payment { ... }
#Entity
#DiscriminatorValue("CREDIT")
#SecondaryTable(name="CREDIT_PAYMENT", pkJoinColumns={
#PrimaryKeyJoinColumn(name="payment_id", referencedColumnName="id")
)
public class CreditCardPayment extends Payment { ... }
#Entity
#DiscriminatorValue("CASH")
public class CashPayment extends Payment { ... }

Categories

Resources