Saturday, July 24, 2010

Unit Testing your JPA entities

If you want to avoid exceptions like this at runtime after adding properties to your JPA entities, it might be worthwhile to invest some time in writing unit tests for them.
Caused by: org.hibernate.MappingException: Could not determine type for: be.ecs.validation.entities.City, at table: Person, for columns: [org.hibernate.mapping.Column(city)]
at org.hibernate.mapping.SimpleValue.getType(SimpleValue.java:291)
at org.hibernate.tuple.PropertyFactory.buildStandardProperty(PropertyFactory.java:143)
at org.hibernate.tuple.component.ComponentMetamodel.(ComponentMetamodel.java:68)
at org.hibernate.mapping.Component.buildType(Component.java:183)
at org.hibernate.mapping.Component.getType(Component.java:176)
at org.hibernate.mapping.SimpleValue.isValid(SimpleValue.java:275)
at org.hibernate.mapping.Property.isValid(Property.java:217)
at org.hibernate.mapping.PersistentClass.validate(PersistentClass.java:464)
at org.hibernate.mapping.RootClass.validate(RootClass.java:236)
at org.hibernate.cfg.Configuration.validate(Configuration.java:1193)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1378)
at org.hibernate.cfg.AnnotationConfiguration.buildSessionFactory(AnnotationConfiguration.java:954)
at org.hibernate.ejb.Ejb3Configuration.buildEntityManagerFactory(Ejb3Configuration.java:891)
... 43 more

The Spring TestContext Framework provides generic, annotation-driven unit and integration testing support. More information can be found on http://static.springsource.org/spring/docs/3.0.3.RELEASE/spring-framework-reference/html/testing.html

The following needs to be done
  1. Create a persistence.xml specific to your unit tests
  2. Create a Spring application context to bootstrap the entitymanager
  3. Create the unit test that
  • constructs an entity
  • persists it
  • retrieves it
    1. Create a persistence.xml specific to your unit tests
    We'll create a dedicated persistence.xml file in our package (src/test/java/META-INF/persistence.xml). In this example, we're using an in-memory HSQL database.

    <persistence>
    <persistence-unit name="pu" transaction-type="RESOURCE_LOCAL">
    <provider>org.hibernate.ejb.HibernatePersistence</provider>
    <class>be.ecs.validation.entities.Person</class>
    <class>be.ecs.validation.entities.City</class>
    <class>be.ecs.validation.entities.Country</class>
    <properties>
    <property name="hibernate.connection.url" value="jdbc:hsqldb:mem:unit-testing-jpa"/>
    <property name="hibernate.connection.driver_class" value="org.hsqldb.jdbcDriver"/>
    <property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect"/>
    <property name="hibernate.hbm2ddl.auto" value="create-drop"/>
    <property name="hibernate.connection.username" value="sa"/>
    <property name="hibernate.connection.password" value="x"/>
    <property name="hibernate.archive.autodetection" value="class, hbm"/>
    </properties>
    </persistence-unit>
    </persistence>



    2. Create a Spring application context

    xxx

    <beans>

    <bean id="entityManagerFactory"
    class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean">
    <property name="persistenceUnitName" value="pu" />
    </bean>

    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
    <property name="entityManagerFactory" ref="entityManagerFactory" />
    </bean>
    </beans>


    3. Create the unit test

    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(locations={"/applicationContext.xml"})
    public class PersonPersistenceTest {

    @PersistenceContext
    private EntityManager entityManager;

    public EntityManager getEntityManager() {
    return entityManager;
    }

    @Test
    public void createAndPersistPerson() {
    Person person = new Person();
    getEntityManager().persist(person);
    Person retrievedPerson = getEntityManager().find(Person.class, person.getId());
    Assert.assertNotNull(retrievedPerson);
    }

    }

    Seam returns HTTP Status 404 but the page exist

    Did it ever occur to you that you saw this message while are sure that particular page does exist at the given location ? :

    Always keep an eye on the Seam console output, as in this case it provides the following info :

    Jul 24, 2010 3:14:46 PM com.sun.facelets.impl.DefaultFaceletFactory createFacelet
    WARNING: /conversations/template/template.xhtml not found at jndi:/localhost/seamdemo.ui/conversations/template/template.xhtml
    The root cause for the 404 is the fact that his particular page referred to a template that couldn't be located :

    <ui:composition xmlns="http://www.w3.org/1999/xhtml"
    s="http://jboss.com/products/seam/taglib"
    ui="http://java.sun.com/jsf/facelets"
    f="http://java.sun.com/jsf/core"
    h="http://java.sun.com/jsf/html"
    rich="http://richfaces.org/rich"
    template="template/template.xhtml">
    <ui:define name="body">
    ....
    </ui:define>
    </ui:composition>

    As you can see, the template (defined in a relative way) couldn't be located from the page consuming it (located in a different folder).