I have recently started playing around with the Play! Framework for Java, version 1.2.3 (the latest). While testing out the framework, I came across a strange problem when trying to persist a Map object inside a Hibernate entity called FooSystem. The Map object maps a long to a Hibernate entity I have called Foo, with the declaration Map<Long, Foo> fooMap;
My problem is as follows: The correct tables are created as I have annotated them. However, when the FooSystem object fs is persisted, the data in fs.fooMap is not!
Here is the code I am using for the entities. First is Foo:
package models.test;
import javax.persistence.Entity;
import javax.persistence.ManyToOne;
import play.db.jpa.Model;
@Entity
public class Foo extends Model
{
@ManyToOne
private FooSystem foosystem;
public Foo(FooSystem foosystem)
{
this.foosystem = foosystem;
}
}
And here is FooSystem:
package models.test;
import java.util.HashMap;
import java.util.Map;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import play.db.jpa.Model;
@Entity
public class FooSystem extends Model
{
@ManyToMany(cascade = {CascadeType.ALL, CascadeType.PERSIST})
@JoinTable(
name = "fooMap",
joinColumns = @JoinColumn(name = "foosystem"),
inverseJoinColumns = @JoinColumn(name = "foo")
)
private Map<Long, Foo> fooMap = new HashMap<Long, Foo>();
public FooSystem()
{
Foo f1 = new Foo(this);
Foo f2 = new Foo(this);
fooMap.put(f1.getId(), f1);
fooMap.put(f2.getId(), f2);
}
public Map<Long, Foo> getFooMap()
{
return fooMap;
}
}
Here is the Controller class I am using to test my set-up:
package controllers;
import javax.persistence.EntityManager;
import models.test.FooSystem;
import play.db.jpa.JPA;
import play.mvc.Controller;
public class TestController extends Controller
{
public static void index() {
EntityManager em = JPA.em();
FooSystem fs = new FooSystem();
em.persist(fs);
render();
}
}
The Play! framework automatically created a transaction for the HTTP request. Although data is inserted into the foo and foosystem tables, nothing is ever inserted into the foomap table, which is the desired result. What can I do about this? What am I missing?
I managed to solve this problem using the advice of Java Ka Baby. The issue was actually not in my
Modelclasses; the problem lay within theController. Specifically, I was saving the entities in the wrong order. Once I realized that using the@ElementCollectionannotation on theMap<Long, Foo>produced the same effects as the join table I was manually specifying, I tried I thought experiment where I re-thought how I was saving my entities.In the code I posted above, you can see in the
FooSystemconstructor that twoFooobjects,f1andf2, are put intofooMapbefore theFooobjects are persisted. I realized that iff1is not in the database when it is put into the map, how is JPA able to use its ID as a foreign key in the join table?If you can see where I’m going with this line of reasoning, you can see that the obvious answer is that JPA is not able to accomplish this amazing feat of using a foreign key to reference a nonexistent key. The bizarre thing is that the Play! console did not note any errors at all for the original code I posted, even though it was not correct at all. Either the framework swallowed every
Exceptionthrown during the process, or I’ve written code that should produce anException.So to fix the problem, I persisted the
Fooentities before any operations were performed on them. Only then did I put them intofooMap. Finally, oncefooMapwas populated, I persisted theFooSystementity.Here is the corrected
TestControllerclass:And, since I changed
FooSystem, here is the final code for that class: