I was recently looking into using JPA (Java Persistence API) in desktop applications to persist the UI’s state. After all, that’s what JSR 296‘s reference implementation relies on to save the frame’s size and position. There are several JPA implementations available out here and I have chosen TopLink from Oracle, as it comes bundled with NetBeans 5.5.
Using JPA in a sample Java application proved to be very easy, particularly with NetBeans wizards and editors. No need to worry about writing the POJOs by hand, no need to worry about writing the XML configuration file, everything is handled for you. And I like that.
What struck me though is how clean and easy the code looks. Yet, I wanted something even easier and cleaner so I tried to use JPA/TopLink with Groovy. I encountered a few issues but thanks to Doug Clarke, Alexandru Popescu and Thomas Risberg I finally have something that works.
The following example requires Java DB (or Apache Derby as you prefer), Oracle TopLink Essentials and a snapshot of Groovy 1.1. To install Groovy 1.1, first install Groovy 1.0 by following the instructions from the website, remove groovy-1.0.jar from the lib/ directory and replace it with groovy-all-1.1-SNAPSHOT.jar. Groovy 1.1 is optional but brings support for annotations, thus avoiding some XML mess.
The full source code of this example, along with Java DB and TopLink, is available for download.
The very first step to use JPA with Groovy is to write your entity bean that you will persist to the database and later retrieve. Being very original, I create the following Person class. The annotations on the id field tell JPA to auto-generate an ID column in the database. Here is the code of Person.groovy:
import javax.persistence.Entity import javax.persistence.GeneratedValue import javax.persistence.GenerationType import javax.persistence.Id @Entity class Person { @Id @GeneratedValue(strategy = GenerationType.AUTO) Long id String firstName String lastName }
Because we are using Groovy, the getters, setters and constructors are automatically generated for us. This bean can now be used to persist data in the database, as the following script, PopulateAddressBook.groovy demonstrates:
import javax.persistence.EntityManager import javax.persistence.EntityManagerFactory import javax.persistence.Persistence def factory = Persistence.createEntityManagerFactory("AddressBookStore") def manager = factory.createEntityManager() manager.getTransaction().begin() manager.persist new Person(firstName: "Alexis", lastName: "Moussine") manager.persist new Person(firstName: "Ludovic", lastName: "Champenois") manager.persist new Person(firstName: "Francois", lastName: "Orsini") manager.persist new Person(firstName: "Eric", lastName: "Mahe") manager.persist new Person(firstName: "Roman", lastName: "Strobl") manager.persist new Person(firstName: "Tor", lastName: "Norbye") manager.persist new Person(firstName: "James", lastName: "Gosling") manager.persist new Person(firstName: "Chet", lastName: "Haase") manager.persist new Person(firstName: "Richard", lastName: "Bair") manager.getTransaction().commit()
This script cannot be run yet as you need to configure the persistence unit that describes the data store. Persistence units are defined in a file called META-INF/persistence.xml. In the example above I have defined a persistence unit called AddressBookStore:
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="AddressBookStore" transaction-type="RESOURCE_LOCAL"> provider>oracle.toplink.essentials.ejb.cmp3.EntityManagerFactoryProviderprovider> properties> property name="toplink.jdbc.url" value="jdbc:derby:address-book;create=true" /> property name="toplink.jdbc.driver" value="org.apache.derby.jdbc.EmbeddedDriver" /> property name="toplink.jdbc.user" value="app" /> property name="toplink.jdbc.password" value="app" /> property name="toplink.ddl-generation" value="create-tables" /> property name="toplink.application-location" value="./db-schema"/> properties> persistence-unit> persistence>
As you can see, this file contains several properties specific to TopLink. You can refer to the online documentation to understand the meaning of each of them. However, it is important to note that this configuration requires to have a folder called db-schema/ in the execution directory. You can either create it or remove the property toplink.application-location.
We also need to tell JPA what beans we want to persist. When using annotations, this is usually done in persistence.xml by adding a <class /> element containing the name of your bean. Unfortunately, some class loading conflict between TopLink and Groovy prevent us from doing so. The solution is to use another configuration file called META-INF/orm.xml. This file can be used to override the beans annotations. It can also be used to describe the persisting field and get rid of the annotations altogether. This is what you want to use with Groovy 1.0 which does not support annotations. In our case, however, we simply need to declare the name of our bean:
xml version="1.0" encoding="UTF-8"?> entity-mappings version="1.0" 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_1_0.xsd"> entity class="Person" name="Person" metadata-complete="false" access="FIELD"> entity> entity-mappings>
You can now run the script to populate the database with a few entries:
groovy -cp ../lib/derby.jar:../lib/toplink-essentials.jar:. PopulateAddressBook.groovy
If you encounter an error, check that you are using Groovy 1.1 and that both XML configuration files are correctly set up. When everything runs smoothly, you can proceed to the last step, querying the database.
The code to query the database and bring back POJOs is surprisingly short. The following asks for the list of all persons and print them by descending order of first names:
import javax.persistence.EntityManager import javax.persistence.EntityManagerFactory import javax.persistence.Persistence import javax.persistence.Query def factory = Persistence.createEntityManagerFactory("AddressBookStore") def manager = factory.createEntityManager() def personQuery = manager.createQuery("SELECT p FROM Person p ORDER BY p.firstName DESC") personQuery.getResultList().each { println "${it.firstName} ${it.lastName}" }
Instead of writing our query in this snippet, we can move it to the bean itself and give it a name:
import javax.persistence.Entity import javax.persistence.GeneratedValue import javax.persistence.GenerationType import javax.persistence.Id import javax.persistence.NamedQueries import javax.persistence.NamedQuery @Entity @NamedQueries(value = [ @NamedQuery(name = "Person.findByFirstName", query = "SELECT p FROM Person p WHERE p.firstName = :firstName") ]) class Person { @Id @GeneratedValue(strategy = GenerationType.AUTO) Long id String firstName String lastName }
The bean now contains a query named Person.findByFirstName which accepts one parameter called firstName. The following snippet shows how to use it to list all of the persons whose first name is “Alexis:”
personQuery = manager.createNamedQuery("Person.findByFirstName") personQuery.setParameter("firstName", "Alexis") personQuery.getResultList().each { println "${it.firstName} ${it.lastName}" }
I hope this example made you want to use Groovy and JPA together. Remember you can download the full example.
Nice example Romain, thanks for making it available for all to see. Keep on Groovying!
wow!!! nice work, thanks for the article!
[...] Original post by Romain Guy [...]
Hi Romain,
I’ve been thinking about using Groovy with JPA for a while now. I just hadn’t gotten around to setting up a Groovy dev environment so I could compile 1.1. So, thanks for the 1.1 snapshot jar. I’m going to try this out with my Groovy Works and see how it works.
Thanks,
Mark
Hi,
May I know what is your reason that you prefer toplink over hibernate? :)
Thanks
james
Mark, the first time I tried to use JPA, I went with Hibernate. The documentation was so large and complex I couldn’t even find a small example like this to make JPA works with Java SE. Also, TopLink is made of one JAR, not a gazillion like Hibernate (gosh, do I hate all those Jakarta dependencies @#!). Last but not least, TopLink is used by NetBeans when you create a persistence unit.
Hmm, I do so prefer seeing POJO versus guessing what side effects will come with writing annotations and scripts – regardless of how groovy or trendy it may be.
While it was not love at first sight for Hibernate, we now have a bond that is strong enough to go public with :-)
With Hibernate I have many, many classes – POJO beans – that I throw over the wall to be persisted or retreived with 0 additional code, so it certainly meets my needs.
Hibernate may have more jars (I use a lot of the Jakarta libs rather than rolling my own) but Hibernate=1 TopLink+Groovy=2
Each to their own of course
aron, you are not comparing things equal here. I’m not advocating using Groovy necessarily, I’m just showing how you can use it with JPA. Ergo, TopLink = 1 JAR and Hibernate is still a gazillion ;-) And without annotations you just have tons of XML. I won’t fight for any of these solutions, I know which I prefer and that’s all I care about :p
Cool, you can actually wire this using Spring 2.0 and have your implementation in Ruby while your interface is Java.
BTW, james. You should be asking why would I choose Hibernate over TopLink instead of the other way around.
If you want to use Hibernate it’s very easy. Just modify the WEB-INF/persistence.xml file to use org.hibernate.ejb.HibernatePersistence as the provider and add the Hibernate specific properties to that file as well. Then add the 10 jars that you need to the classpath. _NO_ changes to the application code is necessary. This is the beauty of JPA – pluggable providers. You get to choose what you like without tying your code to your choice.
Thomas, that’s what I like about JPA. A couple of people sent me emails telling me to try out db4o, an object database, which I did try a few years ago. My main problem with using such a library is that you cannot replace it by another one easily (you can still write your own data access layer, but it’s so much work… ;-)
Hello Romain, i wont comment on the Groovy stuff. For me JPA is a good step forward regarding java and database development.Thouhg I would like to see swing following all these major updates. I am taling about the GUI binding stuff (see Datasets – Master – Detail GUI stuff) available in other platforms for years now. I know that was for some time a project called JDNC (Java Database network compoments) its now subproject of a bigger Swing utils project (cant remember the name). Such compoments are very vital for any decent modern Swing aplpication and still we are waiting to be standard – in some way!
its good tha people like you, which lead the Swing front – you are mentioning JPA and other real world examples – apart from the funcy graphics and filthy rich clients..
please keep posting about Swing from this perspective as well
thanks for your time
Greetings from Athens, greece
Paris: A standard for bindings is coming. Check out JSR 295 (and 296 for that matter.)
Hi Romain,
yes it’s great isn’t it! I myself work on a rich client java project for a couple of years now. When we started the project we decided to go for Java (and not .Net) because of the persistence spec JDO. In combination with Jide’s component framework we were able to show some really nice things in short time. We have now developed quite a solid framework to handle tasks and written generic components to deal with every day issues you encounter in a rich client application which made the start up of this project difficult (I am curious whether jsr296 provides similar solutions, so I need to take a look at it soon). Btw, thanks for your various Java2D tips, I’ve embedded a couple of them in our splash screen;-)
kind regards,
Christiaan
One thing that could show more easyness is the use of a groovy category and then say:
use(PersistencCategory.class){
new Person(firstName:“Alexis”,lastName: “Moussine”).persist()
//… and so on
}
Romain,
Thanks for this blog! Out of interest, what are your thoughts, as a developer of client-side apps, that shipping Groovy with your app will require an extra megabyte (or so) of Groovy JARs?
As it is now, whilst Groovy does compile down to pure Java .class files, they still have a dependency GroovyObject.
I have raised this with the Groovy team http://jira.codehaus.org/browse/GROOVY-1818 but they may need someone more influential (such as yourself) to make the case :)
I actually don’t mind that much. Now, I never had to deploy applications at a large scale where size did matter. But when I see the size of most of the apps I download and install, I don’t really care about 1 MB. Especially when I deem it useful to me, and therefore to the user. I am more concerned about libraries that come with hundreds of dependencies (for instance, any Jakarta library :-) like log4j, common-login or even junit.
It’s a very nice example. I’m playing with it now, but I couldn’t make a @OneToMany relationship work. I think I need something like “Set persons” here. Is this possible with Groovy 1.1, since it doesn’t support Generics yet? Greetings, Ivan
Hi, nice I agree. I’m working with Hibernate and JPA is nice. But what annoys me a bit is that you have to put in the name of the fields as strings, like you did in your query:
query = “SELECT p FROM Person p WHERE p.firstName = :firstName”)
if you change the name of the property, you have to be certain to change it in these strings as well, would be nice if it was possible to specify the fields directly!
IDEs like IntelliJ IDEA will take care of that when you do a refactoring.
Thanks for good post.
I’ll recomend it as good intro into power of Groovy for newbies
[...] Groovy kết hợp với JPA: http://www.curious-creature.org/2007/03/25/persistence-made-easy-with-groovy-and-jpa/ [...]
Romain gz, good woork. Thats what ive been looking for. It works fine, but if i try it with java-embedded-groovy the class Person cannot be found. Have you any idea?
Thanks for the good work. For the Windows users, the -cp option needs “;” as a separator, not “:” as for Linux. It would be nice if you could include the batch files for Windoz:
populate.bat:
groovy -cp ../lib/derby.jar;../lib/toplink-essentials.jar;. PopulateAddressBook.groovy
query.bat
groovy -cp ../lib/derby.jar;../lib/toplink-essentials.jar;. QueryAddressBook.groovy
Just tried it with Groovy Version: 1.5.4 JVM: 1.6.0_02-b06, the example works great.
[...] dans Groovy fonctionne plutôt bien, comme démontré récemment par Romain Guy lorsqu’il integre Groovy et JPA. Je suis sûr qu’avec le support des annotations (un cas unique dans les langages dynamiques [...]
Currently a newbie with Groovy, but trying to implement JPA in a test app with Netbeans. I have downloaded the source etc and can run it fine from the command line – but I want to set it up as a Netbeans Project so that I can work in an IDE to make mods etc etc. Have tried all sorts of ways without success – but my impression was that the whole thing started off as a Netbeans Project.
Sort of problem I have is Netbeans looking for a class to run when I try ‘run file’ on the populate script. Any help appreciated!