tags:

views:

347

answers:

2

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?

+3  A: 

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
Note that you must find a way to notice when the POJO is changed so you can change your mapping file.
Aaron Digulla
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
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
@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
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
+1  A: 

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 @AttibuteOverride (when you want to override a single property) or @AttibuteOverrides (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 {


}

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

Arthur Ronald F D Garcia
i suspect the idea is not to change the MyThing class
Maxime ARNSTAMM
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
@Freiheit Added to original answer
Arthur Ronald F D Garcia
Accepted. Now I'm off to implement a proof of concept and make the pitch to my team! Thank you Arthur!
Freiheit
@Freiheit Just an advice. Take a look at Appress Pro EJB 3 - PACKAGING AND DEPLOYMENT
Arthur Ronald F D Garcia