I was wondering if it's possible in JPA to define a generic entity like in my case PropertyBase<T> and derive concrete entity classes like ShortProperty and StringProperty and use them with the SINGLE_TABLE inheritance mode? If I try to commit newly created ElementModel instances (see ElementModelTest) over the EntityManager I always get an NumberFormatException that "value" can't be properly converted to a Short. Strangely enough if I define all classes below as inner static classes of my test case class "ElementModelTest" this seems to work. Any ideas what I need to change to make this work?
I'm using EclipseLink eclipselink-2.6.0.v20131019-ef98e5d.
public abstract class PersistableObject implements Serializable {
private static final long serialVersionUID = 1L;
private String id = UUID.randomUUID().toString();
private Long version;
public PersistableObject() {
this(serialVersionUID);
}
public PersistableObject(final Long paramVersion) {
version = paramVersion;
}
public String getId() {
return id;
}
public void setId(final String paramId) {
id = paramId;
}
public Long getVersion() {
return version;
}
public void setVersion(final Long paramVersion) {
version = paramVersion;
}
public String toString() {
return this.getClass().getName() + "[id=" + id + "]";
}
}
public abstract class PropertyBase<T> extends PersistableObject {
private static final long serialVersionUID = 1L;
private String name;
private T value;
public PropertyBase() {
this(serialVersionUID);
}
public PropertyBase(final Long paramVersion) {
this(paramVersion, null);
}
public PropertyBase(final Long paramVersion, final String paramName) {
this(paramVersion, paramName, null);
}
public PropertyBase(final Long paramVersion, final String paramName, final T paramValue) {
super(paramVersion);
name = paramName;
value = paramValue;
}
public String getName() {
return name;
}
public void setName(final String paramName) {
name = paramName;
}
public T getValue() {
return value;
}
public void setValue(final T paramValue) {
value = paramValue;
}
}
public class ShortProperty extends PropertyBase<Short> {
private static final long serialVersionUID = 1L;
public ShortProperty() {
this(null, null);
}
public ShortProperty(final String paramName) {
this(paramName, null);
}
public ShortProperty(final String paramName, final Short paramValue) {
super(serialVersionUID, paramName, paramValue);
}
}
public class StringProperty extends PropertyBase<String> {
private static final long serialVersionUID = 1L;
protected StringProperty() {
this(null, null);
}
public StringProperty(final String paramName) {
this(paramName, null);
}
public StringProperty(final String paramName, final String paramValue) {
super(serialVersionUID, paramName, paramValue);
}
}
public class ElementModel extends PersistableObject {
private static final long serialVersionUID = 1L;
private StringProperty name = new StringProperty("name");
private ShortProperty number = new ShortProperty("number");
public ElementModel() {
this(serialVersionUID);
}
public ElementModel(final Long paramVersion) {
super(paramVersion);
}
public String getName() {
return name.getValue();
}
public void setName(final String paramName) {
name.setValue(paramName);
}
public Short getNumber() {
return number.getValue();
}
public void setNumber(final Short paramNumber) {
number.setValue(paramNumber);
}
}
<?xml version="1.0" encoding="UTF-8" ?>
<entity-mappings version="2.1">
<mapped-superclass class="PersistableObject">
<attributes>
<id name="id">
<column name="id" />
</id>
<version name="version" access="PROPERTY">
<column name="version" />
</version>
</attributes>
</mapped-superclass>
<entity class="PropertyBase">
<table name="PropertyBase" />
<inheritance />
<discriminator-column name="type"/>
<attributes>
<basic name="name">
<column name="name" />
</basic>
<basic name="value">
<column name="value" />
</basic>
</attributes>
</entity>
<entity class="StringProperty">
<discriminator-value>StringProperty</discriminator-value>
</entity>
<entity class="ShortProperty">
<discriminator-value>ShortProperty</discriminator-value>
</entity>
<entity class="ElementModel">
<table name="ElementModel" />
<inheritance />
<discriminator-column name="type"/>
<attributes>
<one-to-one name="name">
<join-column name="name" referenced-column-name="id" />
<cascade>
<cascade-all />
</cascade>
</one-to-one>
<one-to-one name="number">
<join-column name="number" referenced-column-name="id" />
<cascade>
<cascade-all />
</cascade>
</one-to-one>
</attributes>
</entity>
</entity-mappings>
public class ElementModelTest extends ModelTest<ElementModel> {
public ElementModelTest() {
super(ElementModel.class);
}
@Test
@SuppressWarnings("unchecked")
public void testSQLPersistence() {
final String PERSISTENCE_UNIT_NAME = getClass().getPackage().getName();
new File("res/db/test/" + PERSISTENCE_UNIT_NAME + ".sqlite").delete();
EntityManagerFactory factory = Persistence.createEntityManagerFactory(PERSISTENCE_UNIT_NAME);
EntityManager em = factory.createEntityManager();
Query q = em.createQuery("select m from ElementModel m");
List<ElementModel> modelList = q.getResultList();
int originalSize = modelList.size();
for (ElementModel model : modelList) {
System.out.println("name: " + model.getName());
}
System.out.println("size before insert: " + modelList.size());
em.getTransaction().begin();
for (int i = 0; i < 10; ++i) {
ElementModel device = new ElementModel();
device.setName("ElementModel: " + i);
device.setNumber((short) i);
em.persist(device);
}
em.getTransaction().commit();
modelList = q.getResultList();
System.out.println("size after insert: " + modelList.size());
assertTrue(modelList.size() == (originalSize + 10));
em.close();
}
}