61

Lets say I have the following POJO:

public class MyThing {
 private int myNumber;
 private String myData;
//assume getter/setter methods
}

Is it now possible to extend this POJO as a JPA entity?

@Entity
@Table(name = "my_thing")
public class MyThingEntity extends MyThing implements Serializable {
 @Column(name = "my_number")
 //?????????
 @Column(name = "my_data")
 //????????
}

I want to keep the POJO separate from the JPA entity. The POJO lives in a different project and is often used without a persistence layer, my project wants to persist it in a database and do so without the overhead of mapping from a POJO to an entity and back.

I understand that JPA entities are POJOs, but in order to use it I would have to include a library that implements javax.persistence and the other projects using the same base object have no use for a persistence layer.

Is this possible? Is this a good idea?

Freiheit
  • 8,408
  • 6
  • 59
  • 101

2 Answers2

80

JPA specification states

Entities may extend non-entity classes as well as entity classes, and non-entity classes may extend entity classes.

@javax.persistence.MappedSuperclass annotation allows you to define this kind of mapping

@MappedSuperclass
public class MyThing implements Serializable {
    private int myNumber;
    private String myData;

    // getter's and setter's
}

And

@Entity
@Table(name="MY_THING")
public class MyThingEntity extends MyThing {


}

As said by JPA specification

The MappedSuperclass annotation designates a class whose mapping information is applied to the entities that inherit from it.

And

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.

If you need to override some property defined by MyThing, use @AttributeOverride (when you want to override a single property) or @AttributeOverrides (when you want to override more than one property)

@Entity
@Table(name="MY_THING")
@AttributeOverride(name="myData", column=@Column(name="MY_DATA"))
public class MyThingEntity extends MyThing {


}

And

@Entity
@Table(name="MY_OTHER_THING")
@AttributeOverrides({
    @AttributeOverride(name="myData1", column=@Column(name="MY_DATA_1")),
    @AttributeOverride(name="myData2", column=@Column(name="MY_DATA_2"))
})
public class MyOtherThingEntity extends MyThing {

}

If you do not want to change your base class, you can use xml to define it as a @MappedSuperClass

Be aware: by default, the persistence provider will look in the META-INF directory for a file named orm.xml

<?xml version="1.0" encoding="UTF-8"?>

<entity-mappings xmlns="http://java.sun.com/xml/ns/persistence/orm" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm http://java.sun.com/xml/ns/persistence/orm_1_0.xsd" version="1.0">
    <mapped-superclass class="MyThing">

    </mapped-superclass>
</entity-mappings>

Nothing else. If you want to override a property, use @AttributeOverride as shown above

Martin
  • 2,754
  • 1
  • 15
  • 35
Arthur Ronald
  • 33,349
  • 20
  • 110
  • 136
  • 4
    i suspect the idea is not to change the MyThing class – Maxime ARNSTAMM Mar 25 '10 at 15:54
  • 2
    Maxime is correct, I do not want to touch the base POJO at all. It might still work, `@MappedSuperclass MyThingMapper extends MyThing .... MyThingEntity extends MyThingWrapper` – Freiheit Mar 25 '10 at 17:34
  • @Freiheit Added to original answer – Arthur Ronald Mar 25 '10 at 18:04
  • Accepted. Now I'm off to implement a proof of concept and make the pitch to my team! Thank you Arthur! – Freiheit Mar 25 '10 at 18:37
  • @Freiheit Just an advice. Take a look at Appress Pro EJB 3 - PACKAGING AND DEPLOYMENT – Arthur Ronald Mar 25 '10 at 19:18
  • 1
    What if you want to make `myNumber` the primary key of `MyThingEntity`? – Manolo Santos Jan 27 '12 at 13:42
  • 1
    @Manolo Santos Just place Id annotation above it. However, do not forget: you should define one, and only one, primary key per class hierarchy. – Arthur Ronald Jan 27 '12 at 18:14
  • Is there a way to add the primary key without modifying the base entity, similar to how `@AttributeOverride` is used for the columns? – blacktide May 09 '16 at 11:37
  • The only thing I missed from this answer is a link to the official documentation – Niccolò Jun 28 '16 at 10:35
  • Some notes after trying this: 1) ``META-INF`` is located in ``src/main/resources/META-INF``. 2) ``@AttributeOverride`` isn't required if you are fine with the attribute names being the column names. – Lucas Sep 01 '16 at 15:15
  • @Casey did you find a solution to add primary key? –  Nov 19 '16 at 19:20
  • @Sidali Hallak You can't. It's a matter of consistency – Arthur Ronald Dec 04 '16 at 17:01
  • Can we inherit a non-entity class without annotate MappedSuperclass? – Sam YC Jul 12 '18 at 08:35
  • In this example an `attributeOverride` is used for myData1 and myData2. However, these fields do not exist in the parent class `MyThing`. From what I can see in the javadoc that would not be valid – IcedDante Jul 16 '18 at 14:47
  • Here is official document : https://docs.oracle.com/javaee/6/tutorial/doc/bnbqn.html#:~:text=Entities%20support%20class%20inheritance%2C%20polymorphic,be%20both%20abstract%20and%20concrete. – Niravdas May 08 '21 at 08:30
6

It is possible:

  • you can map it with XML - make an orm.xml (conforming to the orm schema), and map the columns of your POJO, without even extending it. It will be JPA-enabled in one environment, and a POJO in the other one
  • override just the getter methods and annotate them - (I'm not sure if this will work)

That said, I don't think it is necessary to do this. Just annotate your POJO, and add the compile-time dependency to your projects. Then each project will decide whether it will use them as JPA entities or not.

Bozho
  • 588,226
  • 146
  • 1,060
  • 1,140
  • Note that you must find a way to notice when the POJO is changed so you can change your mapping file. – Aaron Digulla Mar 25 '10 at 14:44
  • Lets assume for now that the team running the project that has the POJO will under no circumstances allow me to submit a patch with the JPA annotations and a javax.persistence import. Is there such a thing as a "dummy" javax.persistence library so the import works, but theres no need to drag EclipseLink JARs around if persistence isn't wanted? – Freiheit Mar 25 '10 at 14:50
  • 1
    The annotations alone won't cause a runtime problem even if the jar containing them isn't present. It would still be needed at compile time. I'm not sure where else this is available, but Maven has a javax.persistence-persistence-api-1.0.jar in the repository (http://mvnrepository.com/artifact/javax.persistence/persistence-api/1.0). – ColinD Mar 25 '10 at 15:55
  • 1
    @ColinD - That's actually very interesting. The reason we can't "pollute" the POJO with the annotations is that its used by several other projects and having to drag around a Maven or Eclipselink JAR to provide javax.persistence classes is not acceptable. So from what you say, we can build with those JARs present then distribute without them in projects that don't need JPA. – Freiheit Mar 25 '10 at 17:54
  • 1
    Yes, as long as just the annotations are used (the enums are ok too, as long as they're only used within the annotations), JPA does not need to be present at runtime. – ColinD Mar 25 '10 at 19:49