Monday, February 15, 2010

Persisting Qi4j Transient Composites using JPA

I've been trying to use Qi4j in a "lightweight mode", while still retaining the JPA (Java Persistence API) programming model. I haven't been successful yet.

Qi4j is a framework for domain driven development aka composite-oriented programming in Java. If that's still not enough buzzwords for you, Qi4j allows you to implement Data-Context-Interaction (DCI) architecture the same way Spring Web MVC allows you to implement MVC.

Fast forward to the current results, what I get is this error:
Testcase: createOne(user.UserTest):        Caused an ERROR
Object: org.qi4j.runtime.composite.TransientInstance@8fa0f0 is not a known entity type.
java.lang.IllegalArgumentException: Object: org.qi4j.runtime.composite.TransientInstance@8fa0f0 is not a known entity type.
        at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.registerNewObjectForPersist(
        at org.eclipse.persistence.internal.jpa.EntityManagerImpl.persist(
        at user.UserTest.createOne(
In short, I was trying to persist a Qi4j Transient Composite object using JPA. Transient Composites are the simplest composite objects in Qi4j, I thought it may work.

But it won't, because JPA expects an entity class (the closest to that would be the a UserMixin class), not a TransientInstance class (which is Qi4j implementation detail).

Here's the test code:

// test/user/
package user;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import org.junit.Test;
import org.qi4j.bootstrap.AssemblyException;
import org.qi4j.bootstrap.ModuleAssembly;
import org.qi4j.test.AbstractQi4jTest;
import static org.junit.Assert.*;

public class UserTest extends AbstractQi4jTest {

    EntityManager em;

    public void assemble(ModuleAssembly module) throws AssemblyException {

    public void setUp() throws Exception {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("PragmaticDciPU");
        em = emf.createEntityManager();

    public void tearDown() throws Exception {
        if (em != null) {

    public void createOne() {
        UserEntity user = transientBuilderFactory.newTransient(UserEntity.class);
        UserEntity user2 = em.find(UserEntity.class, user.getId());
        assertEquals(user.getFirstName(), user2.getFirstName());
Here's the UserEntity composite interface:
// main/user/
package user;

import org.qi4j.api.composite.TransientComposite;

public interface UserEntity
  extends User, TransientComposite { }
Here's the User mixin interface:
// main/user/
package user;

import org.qi4j.api.mixin.Mixins;
import user.internal.UserMixin;

public interface User {

    public Long getId();
    void setId(Long id);
    String getFirstName();
    void setFirstName(String firstName);
    String getLastName();
    void setLastName(String lastName);
And finally, the User mixin implementation:

// main/user/internal/
package user.internal;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import user.User;

public class UserMixin implements User, Serializable {

    private Long id;

    private String firstName;

    private String lastName;

    public String getFirstName() {
        return firstName;

    public void setFirstName(String firstName) {
        this.firstName = firstName;

    public Long getId() {
        return id;

    public void setId(Long id) { = id;

    public String getLastName() {
        return lastName;

    public void setLastName(String lastName) {
        this.lastName = lastName;

If you're curious about the persistence unit, here is it:
<!-- WEB-INF/persistence.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0" xmlns="" xmlns:xsi="" xsi:schemaLocation="">
  <persistence-unit name="PragmaticDciPU" transaction-type="RESOURCE_LOCAL">
      <property name="eclipselink.ddl-generation" value="create-tables"/>
      <property name="javax.persistence.jdbc.driver" value="org.apache.derby.jdbc.ClientDriver"/>
      <property name="javax.persistence.jdbc.url" value="jdbc:derby://localhost/pragmaticdci"/>
      <property name="javax.persistence.jdbc.user" value="app"/>
      <property name="javax.persistence.jdbc.password" value="app"/>