I have a use case where I would like to implement both a self-join and single-table inheritance for the same entity.
I have a NODE table with three fields, ID, Name, and parent_node_id (which is null if the node row is a root node). Here is my example with just the self-join, which works without issue.
@ManyToOne
@JoinColumn(name="parent_node_id")
public Node parent;
//TODO need to ensure children and fields are pre-fetched (can't fetch from within bean)
@OneToMany(mappedBy="parent")
public List<Node> children = new ArrayList<DataNode>();
Now, I'd like to add a discriminator column and subclass this Node class to achieve single-table inheritance, making my Node class abstract. However, when I try it with this setup (using NodeA as an implementing class of Node), I run into the following error:
Exception in thread "main" java.lang.RuntimeException: getIntercept children on [node.Node] type[node.NodeA$$EntityBean$exchange] threw error.
at com.avaje.ebeaninternal.server.deploy.BeanProperty.getValueIntercept(BeanProperty.java:912)
at com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocMany.getValueIntercept(BeanPropertyAssocMany.java:189)
at com.avaje.ebeaninternal.server.deploy.BeanProperty.elGetValue(BeanProperty.java:937)
at com.avaje.ebeaninternal.server.query.CQuery.createNewDetailCollection(CQuery.java:632)
at com.avaje.ebeaninternal.server.query.CQuery.readBeanInternal(CQuery.java:596)
at com.avaje.ebeaninternal.server.query.CQuery.hasNextBean(CQuery.java:710)
at com.avaje.ebeaninternal.server.query.CQuery.readTheRows(CQuery.java:696)
at com.avaje.ebeaninternal.server.query.CQuery.readCollection(CQuery.java:663)
at com.avaje.ebeaninternal.server.query.CQueryEngine.findMany(CQueryEngine.java:203)
at com.avaje.ebeaninternal.server.query.DefaultOrmQueryEngine.findMany(DefaultOrmQueryEngine.java:96)
at com.avaje.ebeaninternal.server.core.OrmQueryRequest.findList(OrmQueryRequest.java:315)
at com.avaje.ebeaninternal.server.core.DefaultServer.findList(DefaultServer.java:1534)
at com.avaje.ebeaninternal.server.core.DefaultBeanLoader.loadMany(DefaultBeanLoader.java:162)
at com.avaje.ebeaninternal.server.core.DefaultServer.loadMany(DefaultServer.java:516)
at com.avaje.ebeaninternal.server.loadcontext.DLoadManyContext.loadMany(DLoadManyContext.java:158)
at com.avaje.ebean.common.AbstractBeanCollection.lazyLoadCollection(AbstractBeanCollection.java:147)
at com.avaje.ebean.common.BeanList.init(BeanList.java:116)
at com.avaje.ebean.common.BeanList.size(BeanList.java:408)
at com.mainstream.exchange.data.Test.main(Test.java:20)
Caused by: java.lang.RuntimeException: Not expecting this method to be called on [node.Node.children] as it is a NON ID property on an abstract class
at com.avaje.ebeaninternal.server.deploy.ReflectGetter$NonIdGetter.get(ReflectGetter.java:96)
at com.avaje.ebeaninternal.server.deploy.ReflectGetter$NonIdGetter.getIntercept(ReflectGetter.java:100)
at com.avaje.ebeaninternal.server.deploy.BeanProperty.getValueIntercept(BeanProperty.java:905)
... 18 more
Furthermore, when I try to setup the same inheritance structure using the Node class as concrete, I get a ClassCastException: node.NodeA cannot be cast to node.Node.
I haven't found much insight in looking at the source code, is my use case an impossibility in Ebean?