Hello,
We have a JBoss/Seam project using hibernate for ORM. The data model is a bit complicated and we make use of Java5 enum in it. In order to keep a strong relational relationship, enums are also persisted as tables in the database by annoting the enum with @Entity @Table and so on ...
All goes almost perfect : model creation, persist objects, find them, remove them ... but we encounters a "org.hibernate.InstantiationException: No default constructor for entity:". The problem is that Seam invoke a refresh() when the context is restored.
It's quite strange because Hibernate can persist perfectly the entities and also "find" them ... but during refresh method invocation, Hibernate try to instanciate the enum and - of course - doesn't found a "default constructor".
Is it a way to by pass the problem ?
Is that a normal behavior (or shall i open an issue on JIRA, if i didn't miss any already open) ?
We use the Hibernate Annotations / EntityManager 3.2.1.GA bundled in Seam 2.0.0 Beta1.
Here is an example of the problem :
Code:
package fr.ifis.core.data.entity.problem;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import org.hibernate.validator.NotNull;
@Entity
@Table(name="A")
public class A {
@Id
@GeneratedValue
@Column(name = "ID")
private int id;
@NotNull
@Column(name = "FOO")
private int foo;
@NotNull
@ManyToOne(optional = false)
@JoinColumn(name = "DISCRIMINATOR_ID")
/*I tried with the @Enumerated, but it doesn't change anything, and i prefer to let the foreign key over the ID column.*/
private B discriminator;
public B getDiscriminator() {
return discriminator;
}
public void setDiscriminator(B discriminator) {
this.discriminator = discriminator;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getFoo() {
return foo;
}
public void setFoo(int foo) {
this.foo = foo;
}
}
Code:
package fr.ifis.core.data.entity.problem;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table(name="DISCRIMINATOR")
public enum B {
STRATEGY,
PROJECT,
PROCUREMENT;
@Id
@Column(name = "ID", unique = true, nullable = false, insertable = true, updatable = false)
private final int id;
private B() {
this.id = ordinal();
}
}
Code:
package fr.ifis.action;
import javax.ejb.Local;
@Local
public interface ALocal {
public void initDiscriminator();
public void check();
}
Code:
package fr.ifis.action;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.jboss.seam.annotations.Logger;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.log.Log;
import fr.ifis.core.data.entity.problem.A;
import fr.ifis.core.data.entity.problem.B;
@Stateless
@Name("aBean")
public class ABean implements ALocal {
@Logger private Log log;
@PersistenceContext
private EntityManager em;
public void check() {
int id = -1;
A a1 = new A();
a1.setDiscriminator(B.PROJECT);
a1.setFoo(1);
em.persist(a1);
log.info("a1 persisted");
id = a1.getId();
//a1 = null;
A a2 = em.find(A.class, id);
a2.setFoo(5);
em.merge(a2);
log.info("a2 merged");
id = a2.getId();
a2 = null;
//Comment this 3 lines in order to make it work.
em.refresh(a1);
log.info("a1 refreshed : foo = " + a1.getFoo());
a1 = null;
A a3 = em.find(A.class, id);
log.info("post merging : foo = " + a3.getFoo());
a3.setDiscriminator(B.PROCUREMENT);
em.merge(a3);
log.info("a3 merged");
id = a3.getId();
a3 = null;
A a4 = em.find(A.class, id);
log.info("post merging : discriminator = " + a4.getDiscriminator());
em.remove(a4);
log.info("a4 removed");
a4 = null;
}
public void initDiscriminator() {
for (B discriminator : B.values()) {
em.persist(discriminator);
log.info("B discriminator persisted");
}
}
}
Best Regards,
Pierre Fourès.