3

I want to have a superclass that is common to all document types:

@Entity
public abstract class Doc implements Serializable
{

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    protected long docId;

    public long getDocId()
    {
        return docId;
    }

    public void setDocId(long docId)
    {
        this.docId = docId;
    }

}

And I want to have child classes for each doc type:

@Entity
@Table(name = "DocTypeA")
public class DocTypeA extends Doc implements Serializable
{
    // other child fields
}

But it gives an error and says that DocTypeA needs a primary key. How can I isolate the primary key and put it in the super class? Because all the subclasses will have that same id field.

I am using EclipseLink.

And my other question is: Why do I need to put @Entity in the abstract class? Being an abstract class it cannot be instantiated, so what is the point of marking it as an Entity? Is it really necessary? I will not persist the superclass. I need it only for isolating the code common in all subclasses.

The stack trace is a long one, relevant part is pasted below:

Exception Description: Entity class [class repository.DocTypeA] has no primary key specified. It should define either an @Id, @EmbeddedId or an @IdClass. If you have defined PK using any of these annotations then make sure that you do not have mixed access-type (both fields and properties annotated) in your entity class hierarchy.
MWiesner
  • 8,868
  • 11
  • 36
  • 70
  • What's the exact and complete error stack trace? What would you like your database schema to look like? – JB Nizet Apr 08 '16 at 21:22
  • Are you sure that the Doc class is indeed annotated with `@Entity` when you get that exception? – JB Nizet Apr 08 '16 at 21:38
  • 1
    Read http://stackoverflow.com/questions/9667703/jpa-implementing-model-hiearchy-mappedsuperclass-vs-inheritence – JB Nizet Apr 08 '16 at 21:45

1 Answers1

6

According to the official JavaDoc the annotation @MappedSuperclass:

Designates a class whose mapping information is applied to the entities that inherit from it. A mapped superclass has no separate table defined for it.

which is what you are looking for. Thus abstract classes can easily be used for common attributes of entities, which in most cases a primary key or DB-generated object identifier is. Annotated fields of that abstract class will then only be mapped for concrete subclasses:

A class designated with the MappedSuperclass annotation can be mapped in the same way as an entity except that the mappings will apply only to its subclasses since no table exists for the mapped superclass itself. When applied to the subclasses the inherited mappings will apply in the context of the subclass tables.

Exchange the @Entity annotation in the abstract class Doc like so:

@MappedSuperclass
public abstract class Doc implements Serializable
{
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    protected long docId;
    //...
}

and you should be good to go.

Hope it helps.

MWiesner
  • 8,868
  • 11
  • 36
  • 70