8

I have a generic class that is also a mapped super class that has a private field that holds a pointer to another object of the same type:

@MappedSuperclass
public abstract class MyClass<T extends MyIfc<T>>
    implements MyIfc<T>
    {

        @OneToOne()
        @JoinColumn(name = "previous", nullable = true)
        private T previous;

             ...
             }

My problem is that Eclipse is showing an error in the file at the OneToOne "Target Entity "T" for previous is not an Entity." All of the implementations of MyIfc are, in fact, Entities. I should also add that each concrete implementation that inherit from MyClass uses a different value for T (because T is itself) so I can't use the "targetEntity" attribute.

I guess if there is no answer then I'll have to move this JPA annotation to all the concrete subclasses of MyClass. It just seems like JPA/Hibernate should be smart enough to know it'll all work out at run-time. Makes me wonder if I should just ignore this error somehow.

Pascal Thivent
  • 562,542
  • 136
  • 1,062
  • 1,124
Dave
  • 21,524
  • 28
  • 141
  • 221

3 Answers3

8

My problem is that Eclipse is showing an error in the file at the OneToOne "Target Entity "T" for previous is not an Entity."

Yes, and even if T was extending an Entity, I am not aware of any JPA provider supporting this (that's just not part of the JPA spec anyway). For more feedback have a look at JPA Generic entities classes Mappedsuperclass are not possible! (very similar thread about EclipseLink):

No you will be unable to make the Entities generic. The provider will be unable to map the relationship to the specific type defined by the generic definition as this type is assigned when the Entity is created in code not where the Entity is defined. Remember when designating Generics the Collection (in this case) is limited only to those types. The Provider can not possibly be this restrictive on a per Entity instance basis. In some cases changing the type may result in entirely different tables being mapped for a single Entity instance and that is definitely not supported.

Pascal Thivent
  • 562,542
  • 136
  • 1,062
  • 1,124
  • Thanks for confirming that this is impossible. Yet another reason why implementation inheritance never works out the way you want. I'm going to remove all references to generic types off the abstract superclass and duplicate them in all the concrete implementations. I wonder if I would have been better off using XML mapping files instead of annotations? – Dave May 11 '10 at 13:16
  • @HDave I don't *think* that this would change anything, I'd expect your JPA provider to complain at runtime. – Pascal Thivent May 11 '10 at 13:21
  • Even if it didn't I suppose compile-type type-safe entity relationships are worth the peace of mind. It just stinks that I have to spend today copying this snippet of code to 17 concrete entity implementations! – Dave May 11 '10 at 15:13
  • 2
    Oracle lovely screwed everything up and the link for the topic you posted (forums.sun.com/thread.jspa?threadID=5268944) returns a 404. Could not found the original post anywhere (google points back to here and to other places using the broken link). The oracle built-in search did not give any results. Can you (or somebody else) give me a new link for that? – Victor Stafusa - BozoNaCadeia Jun 03 '11 at 15:51
2

Since JDO supports persistence of interface fields (which is a similar concept to what you have here), and since DataNucleus JPA is built on top of the JDO capabilities, then it likely would allow you to persist such a field (I have an example using JDO that does something very similar, but without seeing the remains of your classes and persistence code its impossible to be definitive). Give it a try and see what happens.

Obviously that is beyond the JPA spec, hence if portability is a concern for you then have a think first

DataNucleus
  • 15,497
  • 3
  • 32
  • 37
  • In fact I've also tried it with JPA and that also works. So no, it is not impossible, as implied on the other response. It is beyond the JPA spec certainly, but very possible. You just need to use DataNucleus – DataNucleus May 11 '10 at 14:08
1

You can add a @OneToOne(targetEntity=SuperClassOfT.class) to your fields to make this work.

Check out How to implement polymorphic JPA entities with generic relations

Community
  • 1
  • 1
logan
  • 3,416
  • 1
  • 33
  • 45
  • This simple trick only works when the hierarchy starting from SuperClassOfT is mapped with a single-table strategy. To take the example in your link, as long as all Event subclasses are mapped into the event table, you can tell Hibernate to use Event as target and this will imply to use the event table to store/lookup all the target instances. But if, for instance, you want to map UserEvent and ApplicationEvent on different tables, I don't think the workaround you propose will work. – zakmck Aug 24 '12 at 09:47
  • I guess the joined-table strategy could work too, pretty much the same way single-table does, but I'm not sure. – zakmck Aug 24 '12 at 10:40
  • @zakmck -- that's an excellent point! I'm not sure how hibernate handles joins on superclasses when using a table-per-class strategy. That said, the generic information only relates the to java classes, the other restriction you are talking about would still exist without using generics, and instead relying on explicit casts. – logan Sep 01 '12 at 17:23