Monday, February 25, 2008

Testing EclipseLink JPA applications in JavaSE

I spend part of my work days writing examples and helping users debug issues. I spend the majority of this time using JPA with our TopLink and now EclipseLink's advanced features.

One little piece of code I always find myself looking for is a way to take a JPA persistence unit configuration and use it in JavaSE without changing it. The idea is that my persistence unit which should run in the container should also be testable easily outside.

In the past I posted some examples of using XML to accomplish this but the following is the Java code that I use in my JavaSE examples and unit tests without going down the road of a separate persistence unit definition in XML for both worlds.


import static org.eclipse.persistence.jpa.config.PersistenceUnitProperties.*;

...

Map properties = new HashMap();

// Ensure RESOURCE_LOCAL transactions is used.
properties.put(TRANSACTION_TYPE,
PersistenceUnitTransactionType.RESOURCE_LOCAL.name());

// Configure the internal EclipseLink connection pool
properties.put(JDBC_DRIVER, "oracle.jdbc.OracleDriver");
properties.put(JDBC_URL, "jdbc:oracle:thin:@localhost:1521:ORCL");
properties.put(JDBC_USER, "user-name");
properties.put(JDBC_PASSWORD, "password");
properties.put(JDBC_READ_CONNECTIONS_MIN, "1");
properties.put(JDBC_WRITE_CONNECTIONS_MIN, "1");

// Configure logging. FINE ensures all SQL is shown
properties.put(LOGGING_LEVEL, "FINE");

// Ensure that no server-platform is configured
properties.put(TARGET_SERVER, TargetServer.None);


I can then create my EntityManagerFactory using:


Persistence.createEntityManagerFactory("unit-name", properties);


The only remaining struggle I have is specifying which classes are my entities. The simplest way is to explicitly reference them in the persistence.xml or an associated orm.xml file. If they are listed explicitly then I do not need to worry about the automatic discovery.

EclipseLink does support automatic discovery of entity classes in JavaSE but you need to enable its usage using:

<persistence-unit name="unit-name">
<exclude-unlisted-classes>false</exclude-unlisted-classes>
</persistence-unit>

Hopefully having these snippets of code and XML handy will help some of you out and now I can easily find them wherever I am working.

Doug

4 comments:

Hasley said...

hello help please.

to create Persistence.createEntityManagerFactory with different properties does not receive the changes

code
Map properties = new HashMap();

properties.put("eclipselink.target-database", "MySQL4" );
properties.put("eclipselink.jdbc.driver", "com.mysql.jdbc.Driver" );
properties.put("eclipselink.jdbc.url", "jdbc:mysql://localhost:3306/tramisaludprototipo2");
properties.put("eclipselink.jdbc.user", "root");
properties.put("eclipselink.jdbc.password", "root");

emf = Persistence.createEntityManagerFactory("com.change.date",properties);
em = emf.createEntityManager();

Unknown said...

Hi,

I was just wondering. Are you sure about the dynamic entity discovery in a SE environment. I was just trying it, but I end up with a bunch of

Caused by: java.lang.IllegalArgumentException: Object: ... is not a known entity type

exceptions. If I specify the classes directly in my persistence.xml, my test successfully runs through, so it seems that my basic setup is ok and the dynamic discovery is just not working ?!?!

cheers,

thasso

Doug said...

Thasso,

Given the increasing quantity of examples I have around I just always find it easier to list the classes in the persistence.xml so that I don't have to worry about auto-detction finding more classes then I expect. I will dig further into the auto-detection algorithm and see if we can better document it.

I do not believe any auto-detection is covered for SE usage in the JPA 1.0 specification.

Doug

Anonymous said...

Doug,

thanks for the fast reply. And I think you are right, its not part of the spec, but I need this for one of our project where we know the entity classes only at runtime, and therefore I just can't add them to the persistence.xml.
Anyway, I was able to find a way to manipulate the persistence.xml at runtime. I tried to document the attemp here :

http://java.randgestalten.de/?p=82

Basically, I wrote a WrapperArchive that intercepts attemts to get an InputStream to the persistence.xml and than manipulate that stream. I know, I know, this might break with upcoming releases, but works for me for the moment and might come in handy when writing tests in SE environment.

thasso