OpenJPA #
Apache OpenJPA ist eine freie Implementation der JPA-Spezifikation von Sun. Sie basiert auf einer Implementation von Bea. Ich habe einige kleinere Experimente damit gemacht und möchte diese hier festhalten.
Im Netbeans-generierten Code die JPA-Bibliothek austauschen #
Ich habe den von Netbeans benutzten Persistenz-Provider von "toplink" ausgetauscht durch Apache OpenJPA. Dies war nötig, da ersterer nicht unter Maemo/Jalimo lief. Das ging folgendermassen: Ich habe die beiden eingebundenenen Bibliotheken
toplink-essentials toplink-essentials-agent
entfernt und dafür aus dem von http://openjpa.apache.org heruntergeladenen ein paar hinzugefügt:
commons-collections-3.2.jar commons-lang-2.1.jar geronimo-jpa_3.0_spec-1.0.jar geronimo-jta_1.1_spec-1.1.jar openjpa-1.1.0.jar serp-1.13.1.jar
Danach musste die persistence.xml-Datei angepasst werden. Die Angabe des <provider>-Tags habe ich komplett weggelassen (man kann dort die Klasse des openjpa-Providers angeben, aber wenn man gar nichts angibt, nimmt er den einzigen vorhandenen automatisch; so sollte die Datei später wahlweise mit beiden JPA-Bibliotheken arbeiten können. Dann habe ich zusätzliche Properties angegeben wie in der OpenJPA Doku angegeben, um die Parameter der Datenbankverbindung anzugeben. Auch hier sollte man die alten Properties stehen lassen können, um ggf. beide Bibliotheken nutzen zu können.
Im Prinzip lief das Programm nun schon. Allerdings kam bei der Änderung von Daten eine unschöne Exception:
java.lang.UnsupportedOperationException: Result lists are read-only.
Hier scheint es eine Besonderheit von OpenJPA zu geben, daß erzeugte Listen nicht beschreibbar sind. Dies konnte ich nach Lesen dieser Mail von der OpenJPA-Liste durch eine kleine Änderung an zwei Stellen im Code leicht beheben. (Man kopiert die Liste einfach einmal, bevor man sie benutzt.)
persistence.xml entfernen #
// die Konfiguration Map<String, String> map = new HashMap<String, String>(); map.put("openjpa.ConnectionURL", "jdbc:h2:~/citedb"); map.put("openjpa.ConnectionDriverName", "org.h2.Driver"); map.put("ConnectionUserName", "sa"); map.put("openjpa.RuntimeUnenhancedClasses", "supported"); // Datenbank bauen wenn nicht vorhanden map.put("openjpa.jdbc.SynchronizeMappings", "buildSchema"); // die class Angabe im XML. List<Class<?>> types = new ArrayList<Class<?>>(); // jede Klasse angeben types.add(Cite.class); if (!types.isEmpty()) { StringBuffer buf = new StringBuffer(); for (Class<?> c : types) { if (buf.length() > 0) buf.append(";"); buf.append(c.getName()); } // das setzen der typen. Damit JPA die subclassen bauen kann. // hmm evtl. gehts nur mit JDK 1.6. noch nicht ohne JDK getestet. map.put("openjpa.MetaDataFactory", "jpa(Types=" + buf.toString() + ")"); } // wie gewohnt weitermachen EntityManagerFactory fac = OpenJPAPersistence.getEntityManagerFactory(map); EntityManager e = fac.createEntityManager();