Blog Archives

May 7th, 2010
5:30 pm
Spring and JPA – best practice

Posted under Spring
Tags , ,

This post is to explore best practice in this area.

The reason is that I am looking at a stack based on JSF/ICEfaces or PrimeFaces/Tomcat/JPA, as I have a project in mind to run in a hosted environment and Tomcat hosting is easier and cheaper than JBoss/Glassfish hosting.

Spring’s JPATemplate looks useful, but ties you to a Spring standard rather than an open (JPA) one which is vendor independent.

I am always wary when I read in a vendor’s documentation that “such and such an interface abstracts all the other interfaces used by other vendors/standards etc.”
Whilst of course abstraction is a good thing, you do end up tied to the abstraction interface and so need to be aware of the implications of this!

On face value (and I have not explored this at all yet as I am just starting to look at Spring) it seems a backwards step to encapsulate a platform/container independent standard (JPA) which has cross platform support with a platform/container specific one (Spring)?

This post (which I have yet to explore in detail) suggests that it is cleaner not to use Spring’s JPA support classes, which makes sense to me.

The True Way Of Developing Applications has been disturbed and that is damn good. For starters, please take a moment to read these articles in order:

Getting started with JPA and Spring
JPA Annotations Guide (broken link)
Advanced JPA with spring

  • What will happen if you do:
  • No more need for hibernate mapping files; everything will work from annotations, persistent classes are automagically discovered, and greenfield projects can have the database automatically generated. Controller interceptors can be substituted with Transaction annotations, which is much easier to understand and maintain. Spring will generate interceptors anyway but at least you do not have to be so aware of them.
  • No more need of JpaDaoSupport and JpaTemplate. They were a great commodity with JDBC and raw Hibernate, but with JPA it’s cleaner if you do not use the support classes.
  • Do not forget to make your test classes extend AbstractJpaTests so that Spring can inject your attributes.

 

 
I will continue to post links and discusssions here as I explore it in more detail.

No Comments »

January 5th, 2010
4:56 pm
@ManyToMany issues with Eclipselink 1.1.2

Posted under JPA
Tags , , , ,

I found a number of issues when configuring a many to many relationship, but eventually found a working solution.

1/  This example for a many to many uses referencedColumnName when it does not need to – it was a hangover from an example using multiple join columns. If you do this with Eclipselink 1.1.2 and Oracle (in my case XE 10g), the columns are created with data types of varchar2(255) instead of the default of number(19)  :-

      @ManyToMany
      @JoinTable(name="AppUserRole",
                 joinColumns =@JoinColumn(name="AppUserID",
                                          referencedColumnName="AppUserID"),
                 inverseJoinColumns=@JoinColumn(name="AppRoleID",
                                          referencedColumnName="AppRoleID”))

The referencedColumnName attribute is the cause of this issue. Leaving it out causes correct column types. It is only needed for multiple column joins (which break anyway see 2/), and so should not be used. This therefore works correctly and is the recommended format to use  :-

      @ManyToMany
      @JoinTable(name="AppUserRole",
                 joinColumns =@JoinColumn(name="AppUserID"),
                 inverseJoinColumns=@JoinColumn(name="AppRoleID"))

2/ Using a many to many as in 1/ but with multiple join columns causes eclipselink bug 300485. (Although listed as a one to many bug it also happens with many to many). This is not due to be fixed until eclipselink 2.1. The bug gives a query parameter not found error for an internally generated query used when eclipselink lazily loads a relationship collection.

3/ Leaving out the @JoinTable and only having the @ManyToMany annotation works ok, but gives an XML column name resolution error from eclipse for one of the join columns. This is purely an ‘invalid validation’ however, as the code runs fine against a database created from it.

4/ using the xml annotations in orm.xml along with just an @ManyToMany annotation in the code works fine, but you do get some validation errors from Eclipse as the validation does not appear to merge the annotations and xml correctly when validating :-

<entity>
  <attributes>
   <many-to-many name="appRoles">
    <join-table name="AppUserRole">
     <join-column name="AppUserID" column-definition="number(19)"/>
     <inverse-join-column name="AppRoleID" column-definition="number(19)"/>
    </join-table>
   </many-to-many>
  </attributes>
 </entity>

This would be the preferred route if anything database specific  was needed, such as the column-definition attributes for Oracle in the example.  The “@ManyToMany” annotation on the entity may be superfluous in this case but is a helpful label. A comment in the code that there are overrides in orm.xml would be helpful. The above fragment was tested but without the column-definition attributes on the columns – these are shown as examples of how to add database specific column definitions without having to pollute the code with them via annotations.

The intention here would be to use xml in conjunction with annotations, with annotations used for all the standard metadata. Different versions of orm.xml and persistence.xml could then be swapped in and out for different back end databases, keeping the code standard. The same approach has been advocated to permit using Oracle sequences here.

No Comments »

January 5th, 2010
9:05 am
JPQL Query Editing Tools

Posted under JPA
Tags ,

Not too many of these around…

The plan is to donate the Oracle Weblogic Workshop JPQL Query Editor but haven’t seen a release of that yet.

jpaquerytool looks like a possible – a stand alone query tool. You need to feed it your jars in order to give it your entity definitions, then off you go. It mentions Toplink Essentials but not Eclipselink, and it has to use proprietary apis to get the entity mapping metadata so may have issues but worth a look.

No Comments »

December 18th, 2009
5:25 pm
Eclipse error “Class is listed in persistence.xml but not mapped”

Posted under Eclipse
Tags , , ,

Sometimes eclipse lists the following error in the problem view :-

Class xxx is listed in the persistence.xml file but is not mapped

This appears to be a synchronisation problem within Eclipse, as deleting the classes from persistence.xml and then adding them back by browsing with Eclipse’s own persistence.xml editor eliminates the problem, even though the resulting file is identical. Validating the original file did not solve the problem.

Even with the error listed, projects still run and build successfully, so the problem is not serious.

I have also had other cases where Eclipse has whinged about a perfectly good persistence.xml, and have in general just lived with it as it is not serious.

This is an important issue to be aware of though to prevent much head scratching when such a problem is believed to be a real error and is not!

No Comments »

December 18th, 2009
12:30 pm
Tomcat with JPA Persistence jar signing issue

Posted under Tomcat
Tags , , ,

I hit this when deploying  an Eclipselink 1.1 web application to Tomcat 6.0.24, when trying to place all the persistence jars in <Tomcat Home>\lib

The app worked fine when including its own copy of the jars under WEB-INF\lib, but moving them to <Tomcat Home>\lib gave the following error :-

java.lang.SecurityException: class “javax.persistence.Persistence”‘s signer information does not match signer information of other classes in the same package

I checked all the other (non eclipselink) libraries present and could not see a clash. This post appears to shed some light, indicating that it is perhaps a mismatch of jar signing in the Eclipsink libraries.
However, it is strange that it works fine with the libraries deployed with the application rather than under Tomcat.

As Tomcat does not provide its own JPA support, I decided I was quite happy to deploy the libraries with the web app as that works fine, and to leave the issue unresolved.

No Comments »

December 18th, 2009
12:24 pm
Eclipse JPA Generate Tables From Entities “Unable to identify VM” error

Posted under Eclipse
Tags , , ,

This error was caused by importing Eclipse projects from another configuration. The projects had a different JRE library configured, which eclipse listed as “Unbound” as it was not present.

Simply adding the default JRE system library and removing the unbound definition solved the problem. To do this, right click the project, and select Build Path/Configure Build Path. Select the libraries tab on the right hand pane and add/remove from there.

Strangely, this problem did not stop projects running completely – eclipse still allowed a number of small test projects to run even with the “unbound” jre configured. The problem only appeared to manifest itself when trying to create the database schema from the entities via right clicking on the project and selecting JPA Tools/Generate Tables from Entities, wherupon the error occurred.

No Comments »

December 17th, 2009
4:15 pm
Using Eclipse/JSF/JPA with Tomcat 6

Posted under JPA
Tags , , , , , ,

I’ve found that this is useful for prototyping/mockups of apps that are targetted for GlassFish. It is possible to run JPA with Eclipselink outside an EJB container, so a JSF/JPA app can be run under Tomcat, resulting in less overhead and faster turnaround of changes. For a while I’ve had to use a PC which is RAM limited, and so developing/prototyping with Eclipse and Glassfish has been slow. Turning around deployments/changes around takes time, and I’ve found the synchronisation between Eclipse and Glassfish to be a bit fussy – sometimes Eclipse misunderstands the state of Glassfish, needing a Glassfish restart which again takes valuable time.

Note the following points on doing this:-

1/ My application stack looks similar to the ‘real’ one, but my Service layer/domain objects are just POJOs which are explicitly created or injected via faces_config.xml. This Oracle Example details the various IOC features of the JSF. managed bean facility.

2/ Persistence.xml needs setting up differently to run JPA outside the container. I have found it easiest to specify the database connection explicitly, rather than using a data source. In Eclipse, you can use the persistence.xml editor to populate the connection properties directly from the one Eclipse uses for its entity validation. Whilst you can do JNDI lookups of a data source stored in Tomcat, the naming context used is different, as it makes use of the Enterprise Naming Context (ENC), i.e. “java:comp/env”. This example details how to do it if you want to go that way. A sample persistence.xml follows (with entries commented out where they have been replaced for use with Tomcat) :- 

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="1.0" xmlns="http://java.sun.com/xml/ns/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_1_0.xsd">

 <!--<persistence-unit name="SentryPrototype" transaction-type="JTA">-->
 <persistence-unit name="SentryPrototype" transaction-type="RESOURCE_LOCAL">

   <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>

   <!--<jta-data-source>jdbc/JPATestPool</jta-data-source>-->

   <class>uk.co.salientsoft.jpatest.domain.UserInfo</class>
   <properties>
    <property name="eclipselink.logging.level" value="INFO" />

    <!-- <property name="eclipselink.target-server" value="SunAS9" />-->
    <property name="eclipselink.target-server" value="None" />

    <property name="eclipselink.session-name" value="SentryPrototypeSession" />
    <property name="eclipselink.target-database" value="Oracle" />   
    <property name="eclipselink.ddl-generation.output-mode" value="database" />

    <property name="eclipselink.jdbc.url" value="jdbc:oracle:thin:@localhost:1521:xe"/>
    <property name="eclipselink.jdbc.user" value="sentry"/>
    <property name="eclipselink.jdbc.password" value="sentry"/>
    <property name="eclipselink.jdbc.driver" value="oracle.jdbc.OracleDriver"/>

   </properties>
  </persistence-unit>
</persistence>

 

3/ Ref this eclipse tutorial :-
Tomcat does not have an EJB container so you must add EJB 3.0/JPA 1.0 capability for EclipseLink JPA by placing the specification persistence.jar into the container lib directory $TOMCAT_HOME/lib.
It is recommended to put persistence_1_0.xsd there as well.  It is not recommended that the WAR include its own version of persistence.jar. Your eclipse project should reference but not include this jar and xsd.

The eclipselink.jar should be placed off of the container lib directory $TOMCAT_HOME/lib.
Since Tomcat does not include an EJB container, you may put eclipselink.jar in the web applications’s lib directory or higher up in the classloader by putting it off of Tomcats’ lib directory, where all web applications can access it.
Do not split the eclipselink.jar from the javax.persistence jar – keep them together – preferably in $TOMCAT_HOME/lib

 4/ Tomcat has its own dependencies on the Expression Language (EL) web libraries. These should be removed from WEB_INF/lib when deploying to Tomcat as pointed out here. (If you do not do this, the application will crash with duplicate class loading exceptions.) This may be done in eclipse on the Java Server Faces facet page – open the project properties for the project, and select Java Server Faces under Project Facets. Untick the entry for Standardized EL Library v1.0.

Then save the changes and redeploy the application.

For more information, the eclipse tutorial referenced in 3/ goes into greater depth on the subject. You can also find a list of the available eclipse JPA tutorials here.

5/ When running xxxxxx

Comments Off on Using Eclipse/JSF/JPA with Tomcat 6

December 15th, 2009
11:09 am
Accessing JPA Entity Metadata

Posted under JPA
Tags , ,

It is often useful to access the entity definition metadata. A classic example would be to access the actual maximum defined length of a string column from the code. Such a definition should be centralised to avoid multiple definitions of a constant value, which would otherwise require multiple changes if the value were increased. There are several approaches to this, but unfortunately not an obvious ‘silver bullet’ which is straightforward and also performant.

1/ Access Database Metadata via JDBC

You can access the actual database definitions via a JDBC connection. This would have a performance penalty, but would make sense if the database is your master definition source, i.e. you are starting with a database defninition and then creating entities based on the database. You can get a JDBC connection from JPA via the code below, as described at the end of this post here :-

JPA 2.0

entityManager.getTransaction().begin();
java.sql.Connection connection = entityManager.unwrap(java.sql.Connection.class);
...
entityManager.getTransaction().commit();

 

JPA 1.0

entityManager.getTransaction().begin();
UnitOfWorkImpl unitOfWork = (UnitOfWorkImpl)((JpaEntityManager)entityManager.getDelegate()).getActiveSession();
unitOfWork.beginEarlyTransaction();
java.sql.Connection connection = unitOfWork.getAccessor().getConnection();
...
entityManager.getTransaction().commit();

 

  This post here  details how to get metadata from a connection. The sample code from the post follows :-

Get Column Size

import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;

public class Main {
  public static void main(String[] argsthrows Exception {
    Connection conn = getMySqlConnection();
    System.out.println("Got Connection.");
    Statement st = conn.createStatement();
    st.executeUpdate("drop table survey;");
    st.executeUpdate("create table survey (id int,name varchar(30));");
    st.executeUpdate("insert into survey (id,name ) values (1,'nameValue')");

    ResultSet rsColumns = null;
    DatabaseMetaData meta = conn.getMetaData();
    rsColumns = meta.getColumns(null, null, "survey"null);
    while (rsColumns.next()) {
      String columnName = rsColumns.getString("COLUMN_NAME");
      System.out.println("column name=" + columnName);
      String columnType = rsColumns.getString("TYPE_NAME");
      System.out.println("type:" + columnType);
      int size = rsColumns.getInt("COLUMN_SIZE");
      System.out.println("size:" + size);
      int nullable = rsColumns.getInt("NULLABLE");
      if (nullable == DatabaseMetaData.columnNullable) {
        System.out.println("nullable true");
      else {
        System.out.println("nullable false");
      }
      int position = rsColumns.getInt("ORDINAL_POSITION");
      System.out.println("position:" + position);
      
    }

    st.close();
    conn.close();
  }

  private static Connection getHSQLConnection() throws Exception {
    Class.forName("org.hsqldb.jdbcDriver");
    System.out.println("Driver Loaded.");
    String url = "jdbc:hsqldb:data/tutorial";
    return DriverManager.getConnection(url, "sa""");
  }

  public static Connection getMySqlConnection() throws Exception {
    String driver = "org.gjt.mm.mysql.Driver";
    String url = "jdbc:mysql://localhost/demo2s";
    String username = "oost";
    String password = "oost";

    Class.forName(driver);
    Connection conn = DriverManager.getConnection(url, username, password);
    return conn;
  }

  public static Connection getOracleConnection() throws Exception {
    String driver = "oracle.jdbc.driver.OracleDriver";
    String url = "jdbc:oracle:thin:@localhost:1521:caspian";
    String username = "mp";
    String password = "mp2";

    Class.forName(driver)// load Oracle driver
    Connection conn = DriverManager.getConnection(url, username, password);
    return conn;
  }
}

 

2/ Access JPA Annotations via Reflection

Alternatively, you could try using Reflection to read the JPA annotations via introspection.  This post here describes how to read annotations with Reflection, but note that this is not a JPA example – it is a ‘roll your own persistance provider’ example, but the introspection techniques should work the same way. The downside of this technique is that all that introspection just seems laborious and slow performing if all you want is the length of a few string columns.

 

3/ Use Constants in Inner Classes to roll your own master Metadata Definitions

Another way, which makes sense if the entity defninitions are the ‘master’ and you are creating the database tables from the entities, is just to define some inner classes in the entity class containing static constants for the metadata you need access to. You can then use these definitions as the master, and refer to them both in the annotations and the calling code. You can also use an inheritance hierachy to standardise the metadata you are using, and centralise common definitions. As you are rolling your own metadata, you do not have to stick to the jpa annotations, you are free to invent any other constants that you need to tell you something about your entities/columns. The example which follows demonstrates column metadata, but you could of course apply the same technique to entity (table) level metadata if required.

In this example, a number of entities have Code fields containing a coded string which might be 30 characters, and description fields which might be 255 characters. The definitions for “Code” and “Description” can be centralised in a common superclass. In each Entity, for all the fields for which you want to expose the metadata, you define a public  inner class named <FieldName>Meta just above the field and annotation declarations. You can then access the constants in the inner class statically from outside the entity. (If required, you could also provide a statically initialised field containing a reference to the <FieldName>Meta class, and create a getter for it, if you need getter access as well, e.g. for managed access via a framework such as JSF, although this involves non static access to a static value which eclipse/java will winge about). The following code samples illustrate the technique:-

Class ColumnMeta

package uk.co.salientsoft.jpa;

/* This base class defines the metadata used. */

public abstract class ColumnMeta {
 public static final String NAME = null;
 public static final int LENGTH = 255;
}

 

Class ColumnMetaCode

package uk.co.salientsoft.test.domain;
import uk.co.salientsoft.jpa.ColumnMeta;

public abstract class ColumnMetaCode extends ColumnMeta {
 public static final String NAME = "Code";
 public static final int LENGTH = 30;
}

 

Class ColumnMetaDescription

package uk.co.salientsoft.test.domain;
import uk.co.salientsoft.jpa.ColumnMeta;

public abstract class ColumnMetaDescription extends ColumnMeta {
 public static final String NAME = "Description";
 public static final int LENGTH = 255;
}

 

Entity Class AppRole

package uk.co.salientsoft.test.domain;

import java.io.Serializable;
import java.lang.String;
import javax.persistence.*;

@Entity
public class AppRole implements Serializable {

 private static final long serialVersionUID = 1L;

 @Id
 @GeneratedValue(generator="AppRoleID")
 private long AppRoleID;
 private long AppID;

 public class CodeMeta extends ColumnMetaCode {};
 @Column(length=CodeMeta.LENGTH)
 private String Code;
 
 public class DescriptionMeta extends ColumnMetaDescription {};
 @Column(length=DescriptionMeta.LENGTH)
 private String Description;

 public AppRole() {
  super();
 }  
 public long getAppRoleID() {
  return this.AppRoleID;
 }
 public void setAppRoleID(long AppRoleID) {
  this.AppRoleID = AppRoleID;
 }  
 public long getAppID() {
  return this.AppID;
 }
 public void setAppID(long AppID) {
  this.AppID = AppID;
 }  
 public String getCode() {
  return this.Code;
 }
 public void setCode(String Code) {
  this.Code = Code;
 }  
 public String getDescription() {
  return this.Description;
 }
 public void setDescription(String Description) {
  this.Description = Description;
 }
}

 

Example MetaData References

codeLength = AppRole.CodeMeta.LENGTH;
descLength = AppRole.DescriptionMeta.LENGTH;

Comments Off on Accessing JPA Entity Metadata

December 9th, 2009
6:45 pm
Creating database tables from Entities in Eclipse

Posted under JPA
Tags , , ,

This can be done a couple of different ways :-

  1. From the Project context menu, select JPA Tools/Create Tables from Entities. This will drop and create the whole schema based on the entity definitions.
  2. Alternatively, you can configure persistence.xml to drop and create the whole schema before each run as detailed in the example file here.

Comments Off on Creating database tables from Entities in Eclipse

December 9th, 2009
6:06 pm
Using Oracle Specific features in JPA with Eclipselink

Posted under JPA
Tags , , ,

To use Oracle specific features in JPA with Eclipselink, such as using sequences for ID generation as described in this example here, it is necessary to set the correct property in persistence.xml to ensure that JPA/Eclipselink knows that an Oracle database is in use. By default, it does not discover this automatically and resorts to using table based ID generation even if you turn sequences on as per the above example.

A sample persistence.xml with the correct properties follows :-

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="1.0"
 xmlns="http://java.sun.com/xml/ns/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_1_0.xsd">
 <persistence-unit name="JPATest" transaction-type="RESOURCE_LOCAL">
  <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
  <non-jta-data-source>jdbc/JPATestPool</non-jta-data-source>
  <mapping-file>META-INF/orm.xml</mapping-file>
  <class>uk.co.salientsoft.jpatest.domain.UserInfo</class>
  <properties>
   <property name="eclipselink.target-server" value="SunAS9" />
   <property name="eclipselink.logging.level" value="FINEST" />
   <property name="eclipselink.session-name" value="JPATestSession" />

   <!-- Ensure Eclipselink knows we have an Oracle Database
        so that Oracle specific features work correctly -->
   <property name="eclipselink.target-database" value="Oracle"/>

   <!-- This will cause EclipseLink to create the database schema
        automatically on every run.
        You can also do this from the JPA Tools/Create Tables from Entities
        project context menu option in Eclipse, which may well be preferrable-->
   <!--
   <property name="eclipselink.ddl-generation" value="drop-and-create-tables" />
   <property name="eclipselink.ddl-generation.output-mode" value="database" />
   -->

  </properties>
 </persistence-unit>
</persistence>

Comments Off on Using Oracle Specific features in JPA with Eclipselink