Java ORM: multiple (interface) inheritance

I would like to map a domain model to a relational database using one of the Java ORM frameworks. Unfortunately, none of them seem to have adequate support for classes that implement multiple interfaces. Let's 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 the Quote can refer to any Quotable (Stock, StockIndex and others), while Trade can only refer to Tradable objects. I tried OpenJPA and (simple) Hibernate with no luck, although the latest interface support looked promising.

Is there any infrastructure that can handle my script? Or are there good reasons why this should not be mapped to a database? If so, how should my model be changed?

My initial Hibernate mapping looked something like this (I don't show any OpenJPA stuff since 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 Hibernate documentation example and results in a table enclosed in a table with an identifier and a column discriminator column, table stock_index with an identifier and index name and a table with an identifier and stock name. So far so good ...

But what should I do with the Tradeable interface? I would need to set up a separate hierarchy and a Stock map in both hierarchies. I tried this, but had to define different entity names for Stock (and it was necessary to include this patch ), but it also did not work due to foreign key violations. I tried a couple of other obscure things that didn't work either.

In any case, matching stocks twice would not be a good solution, because the application would have to remember adding stock instances twice - once for each interface. I would prefer a control mechanism in this automatic way.

Ideally, Hibernate allows you to extend several interfaces, that is, something like (note the extends attribute for 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 could be displayed? Now I’ve found out about <any> , which looks like it might work for me, but I still have to understand all its consequences.

What about other frameworks? I heard that EclipseLink also has some interface support, but it is poorly documented.

+6
source share
1 answer

I don’t think you will find an ORM capable of handling the hierarchy of interfaces perfectly. Therefore, I will not talk about ORM here, but I will show you how to implement my example using Qi4j.

Qi4j is a composite-oriented programming implementation using a standard Java platform and a platform for developing domain-oriented applications, including developed concepts from AOP, DI and DDD. See http://qi4j.org

In Qi4j, the state of a domain is modeled using entities and values. In the following code example, I assume that everything is an entity, but your mileage may vary.

Since objects are declared using only interfaces, your use case should fit well.

 interface Quotable { ... } interface Tradable { ... } interface StockIndex extends Quotable { ... } interface Stock extends Quotable, Tradable { ... } interface Quote { Association<Quotable> quotable(); } interface Trade { Association<Tradable> tradable(); } 

Then you can save the abstracts in the EntityStore and use the request APIs to easily get them (and in a completely polymorphic way).

Please note that Qi4j EntityStores are not only SQL based, but also support NoSQL databases. See Available Extensions here: http://qi4j.org/latest/extensions.html

See the Qi4j documentation if you have additional questions.

+3
source

Source: https://habr.com/ru/post/912191/


All Articles