home.


Tagged: jpa


Java: Testing a REST service with a clean database (using sqlite)

You can test REST responses like so with Jersey’s client api.

    YourResponseObject result = service
       .path("somepath")
       .type(MediaType.APPLICATION_JSON)
       .put(YourResponseObject.class, yourInputObject);

    assertTrue(result.isSuccessful());

But your responses may depend on the state of your database.

And since you’re not running your tests from a WAR, or what have you, you have no direct access to populate its seed or delete it.

The best way to do this is to create a rest method to clear the database to use during development, and remove in production.

The method to delete the database would look like:

    EntityTransaction trans = mEntityManager.getTransaction();
    trans.begin();
    Query q = mEntityManager.createQuery("delete from UserEntity");
    q.executeUpdate();
    trans.commit();
    closeEntityConnection();

It may be possible access the JPA database if the tests are run in a WAR, but I haven’t tried that. Any experience would be welcomed in the comments.

java REST java-testing jersey sqlite jpa

JPA: Mapping to an existing database

In your persistence.xml you can specify an XML mapping file. Anything in this will overrule whatever is in your annotations.

Let’s say the a column name is changed in a UAT database, but not in production. You can create a mapping file that remaps the annotation for the UAT database, by specifying this in your persistence.xml under the persistence-unit tag:

META-INF/db_mapping.xml

In that file you can set remap the column like so:

<?xml version="1.0" encoding="UTF-8" ?>
<entity-mappings xmlns="http://java.sun.com/xml/ns/persistence/orm"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm    http://java.sun.com/xml/ns/persistence/orm_2_0.xsd"
    version="2.0">
    <entity class="org.denevell.tomcat.entities.write.AnotherThing">
       <table name="anotherthing" />
       <attributes>
         <basic name="text">
           <column name="sometext" nullable="false" />
         </basic>
       </attributes>
    </entity>
</entity-mappings>

After the car-crash of schema declarations, the entity specifies which class to map, to what table, and then the attributes within. The basic tag tells us the name of the property or field in your Java class. Then the column tags tell you want to map it to.

jpa jpa-databasemapping

JPA: Testing

You can test your JPA code by setting aside another folder structure, test/ for example, with a META-INF/ directory with a new persistence.xml file there pointing to a different database.

Here’s new new persistence.xml:

 <?xml version="1.0" encoding="UTF-8" ?>
 <persistence xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
     version="2.0"
     xmlns="http://java.sun.com/xml/ns/persistence">
   <persistence-unit name="example" transaction-type="RESOURCE_LOCAL">
     <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
     <class>org.denevell.tomcat.entities.write.AnotherThing</class>
     <properties>
       <property name="javax.persistence.jdbc.driver" value="org.sqlite.JDBC" />
       <property name="javax.persistence.jdbc.url" value="jdbc:sqlite:/home/YOURUSERNAME/test.db" />
       <property name="eclipselink.logging.level" value="ALL" />
       <property name="eclipselink.ddl-generation" value="drop-and-create-tables" />
     </properties>
   </persistence-unit>
</persistence>

The only different to the previous ones is that we’re putting our database in a new location - one where the runner of the junit test has write access. And we’re doing drop-and-create-tables in the table creation.

The next thing you need is the junit4 file that calls the persistence provider to test adding of the entity:

public class JPAStarterTest {
  @Test
  public void addAnotherThing() {
    // Arrange
    AnotherThing at = new AnotherThing();
    at.setText("hii");          
    // Act
    tx.begin();
    em.persist(at);
    tx.commit();            
    // Assert
    assertNotNull("Id should not be null", at.getId());
    List<AnotherThing> list = em.createNamedQuery("listAll", AnotherThing.class).getResultList();
    assertEquals("Table has one entity", 1, list.size()); 
    assertEquals("Table has correcttext", "hii", list.get(0).getText());
  }

  @BeforeClass
  public static void beforeClass() {
    emf = Persistence.createEntityManagerFactory("exampletest");
    em = emf.createEntityManager();
  }

  @AfterClass
  public static void afterClass() {
    em.close();
    emf.close();
  }

  @Before
  public void before() {
    tx = em.getTransaction();
  }
  private static EntityManagerFactory emf;
  private static EntityManager em;
  private EntityTransaction tx; 
}

Now when you run this, ensure your new persistence.xml is in the META-INF/ directory of the classes.

jpa java-testing jpa-testing junit

JPA: Named queries

On your entity class if you put this below the @Entity annotation,

@NamedQuery(name="listAll",query="select tings from AnotherThing tings")

Then that will get all the AnotherThings from all the AnotherThings objects in the system.
You can call this via:

TypedQuery<AnotherThing> q = em.createNamedQuery("listAll", AnotherThing.class);
List<AnotherThing> results = q.getResultList();
for (AnotherThing thing : results) {
}

If, in the NamedQuery, you put parameters like ‘:username’, then your code will look like:

em.createNamedQuery("nameOfQuery")
    .setParameter("username", "Luke Vibert")
    .getResultList();
jpa jpa-namedqueries

Tomcat 7: JPA using EclipseLink and Sqlite

Download EclipseLink, the reference implementation for JPA, from http://www.eclipse.org/eclipselink/downloads/ and the sqlite jdbc library, from https://bitbucket.org/xerial/sqlite-jdbc/downloads.

Copy, eclipselink.jar, javax_persistence_2.x.x.jar and the sqlite jdbc jar file into your tomcat lib directory, /usr/share/tomcat7/lib in my case.

Now restart tomcat.

Create persistence.xml in src/META-INF/persistence.xml.

  <?xml version="1.0" encoding="UTF-8" ?>
  <persistence xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
      version="2.0"
      xmlns="http://java.sun.com/xml/ns/persistence">
    <persistence-unit name="example" transaction-type="RESOURCE_LOCAL">
      <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
      <class>org.denevell.tomcat.entities.write.AnotherThing</class>
      <properties>
        <property name="javax.persistence.jdbc.driver" value="org.sqlite.JDBC" />
        <property name="javax.persistence.jdbc.url" value="jdbc:sqlite:/var/lib/tomcat7/dbs/test.db" />
        <property name="eclipselink.logging.level" value="ALL" />
        <property name="eclipselink.ddl-generation" value="create-tables" />
      </properties>
    </persistence-unit>
 </persistence>

The persistence-unit name will be how we will grab a hold of our persistence entity manager factory. The transaction-type say we’re using a local database. If it said JTA it would mean we’d have support for transactions over multiple datasources (Tomcat doesn’t support this out of the box).

We next tell it about the provider, EclipseLink, in our case. Then the class that will be persisted. Then we set properties to tell it about our driver, our jdbc url, the logging level and how we will generate the database.

We could set eclipselink.ddl-generation to ‘drop-and-create-tables’ if we want to destroy the database everytime. In a later tutorial we’ll detail how to work with an existing database without automatically doing anything, since the eclipselink.ddl-generation is only really useful during development.

Here’s what our ‘AnotherThing’ entity looks like:

package org.denevell.tomcat.entities.write; // Referenced in persistence.xml

@Entity
public class AnotherThing {
  @Id @GeneratedValue
  private int id;
  private String text;
  public AnotherThing() {
  }
  public int getId() {
      return id;
  }
  public void setId(int id) {
      this.id = id;
  }
  public String getText() {
      return text;
  }
  public void setText(String text) {
      this.text = text;
  }
}

Note @Entity defines our class as just that, the @Id annotation says this is the primary key of the entity, and @GeneratedValue say the persistence provider generates its value.

We can now talk to our JPA instance:

// Setup the entity manager
EntityManagerFactory factory =   Persistence.createEntityManagerFactory("example");
EntityManager em = factory.createEntityManager();
// Create it
AnotherThing t = new AnotherThing();
t.setText("Heya");      
// Add it
EntityTransaction trans = em.getTransaction();
trans.begin();
em.persist(t);
trans.commit();
// Fetch them
TypedQuery<AnotherThing> q = em.createQuery("select ting from AnotherThing ting", AnotherThing.class);
List<AnotherThing> results = q.getResultList();
for (AnotherThing thing : results) {
  writer.println(thing.getId() + ": " + thing.getText());
}
// Close the entity manager
em.close();
factory.close();

Note we’re using our name of the persistence-unit above to get the entity manager factory. Then we get the entity manager (we should only have one of these). Then we create a new object as normal.

We then start an entity transaction (we could use this to rollback if we wanted). Then we persist the object, committing the transaction.

Finally we use the JPQL syntax to get all the ‘AnotherThing’ objects in the database. Then we close the entity manager, and the entity manager factory.

I did get some error about AnotherThing not being recognised. Unfortunatley I think this is a bug in Tomcat for the most part. Stopping and then starting Tomcat should resolve the problem.

java jpql jpa tomcat sql sqlite

Page 1 of 1