Nauka Java Persistence z Apache Maven 2 i dostawcami JPA: OpenJPA, Hibernate i TopLink

Z Jacek Laskowski - Wiki Projektanta Java EE

Mając zestawione środowisko do nauki Java Persistence API (JPA), które przedstawiłem w artykule Java Persistence API z OpenJPA i Derby oraz TestNG z Eclipse IDE w tle postanowiłem je ulepszyć. Celem zmian było wprowadzenie możliwości weryfikacji implementacji specyfikacji JPA wśród różnych dostawców JPA - Apache OpenJPA, Hibernate EntityManager oraz TopLink Essentials. Oczywiście lista dostawców JPA może ulec zmianie w razie potrzeby. Możliwość uruchomienia testów jednostkowych napisanych w TestNG z różnymi dostawcami była możliwa dzięki wykorzystaniu Apache Maven 2, a dokładniej mechanizmowi profili. Wystarczyło odpowiednio zdefiniować profil w pliku projektu - pom.xml i reszta pozostała w gestii Apache Maven 2 (dalej zwanym M2).

Spis treści

Zanim zaczniemy...

Ważne jest, aby rozpocząć artykuł od zestawienia środowiska do uruchamiania testów TestNG z Apache Maven 2, gdzie dostawcą JPA jest Apache OpenJPA zgodnie z artykułem Java Persistence API z OpenJPA i Derby oraz TestNG z Eclipse IDE w tle.

Krótko o profilach w Apache Maven 2

Możliwość uruchamiania testów z różnymi dostawcami JPA jest możliwa korzystając z mechanizmu profili w Apache Maven 2. Profil pozwala na podział konfiguracji projektu - pom.xml - na mniejsze jednostki uzależnione od pewnych ustawień środowiska, które modyfikują główną konfigurację projektu (powodują, że wykonanie zadań w projekcie odbywa się jakby ustawienia profili były podstawowymi w projekcie z elementami konfiguracji głównej). W ten sposób możemy grupować konfiguracje w pojedyńczym projekcie i wyzwalać je jakby były one podstawowymi ustawieniami.

Wykonanie profilu odbywa się przy pomocy opcji -P<nazwa_profilu>. Istnieje również możliwość wykonania profilu w inny sposób, np. zmienna środowiskowa, czy wersja Javy, który jest zdefiniowany w elemencie <activation> profilu. Skorzystamy z możliwości definicji domyślnego profilu przy OpenJPA.

Domyślny profil projektu - openjpa

Mając zdefiniowane środowisko testowe z OpenJPA (patrz poprzedni artykuł), wprowadzamy nowy profil - openjpa - do projektu. Funkcjonalnie, zmiana nie wpłynie w żaden sposób na dotychczasową konfigurację, jednakże dzięki niemu przygotujemy grunt pod kolejne. Profil openjpa będzie profilem domyślnie uruchamianym.

Plik pom.xml

Modyfikujemy plik pom.xml projektu, aby przybrał następującą postać:

<?xml version="1.0"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>pl.jaceklaskowski.jpa.query</groupId>
  <artifactId>jpa-query</artifactId>
  <name>jpa-query</name>
  <version>1.0</version>
  <dependencies>
    <dependency>
      <groupId>org.apache.derby</groupId>
      <artifactId>derby</artifactId>
      <version>10.2.2.0</version>
    </dependency>
    <dependency>
      <groupId>org.apache.derby</groupId>
      <artifactId>derbyclient</artifactId>
      <version>10.2.2.0</version>
    </dependency>
    <dependency>
      <groupId>org.testng</groupId>
      <artifactId>testng</artifactId>
      <version>5.1</version>
      <scope>test</scope>
      <classifier>jdk15</classifier>
    </dependency>
  </dependencies>
  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <configuration>

Niepoprawny język.

Musisz wybrać język w następujący sposób: <source lang="html4strict">...</source>

Języki obsługiwane w podświetlaniu składni:

abap, actionscript, actionscript3, ada, apache, applescript, apt_sources, asm, asp, autoit, avisynth, bash, basic4gl, bf, bibtex, blitzbasic, bnf, boo, c, c_mac, caddcl, cadlisp, cfdg, cfm, cil, cmake, cobol, cpp, cpp-qt, csharp, css, d, dcs, delphi, diff, div, dos, dot, eiffel, email, erlang, fo, fortran, freebasic, genero, gettext, glsl, gml, gnuplot, groovy, haskell, hq9plus, html4strict, idl, ini, inno, intercal, io, java, java5, javascript, kixtart, klonec, klonecpp, latex, lisp, locobasic, lolcode, lotusformulas, lotusscript, lscript, lsl2, lua, m68k, make, matlab, mirc, modula3, mpasm, mxml, mysql, nsis, oberon2, objc, ocaml, ocaml-brief, oobas, oracle11, oracle8, pascal, per, perl, php, php-brief, pic16, pixelbender, plsql, povray, powershell, progress, prolog, properties, providex, python, qbasic, rails, rebol, reg, robots, ruby, sas, scala, scheme, scilab, sdlbasic, smalltalk, smarty, sql, tcl, teraterm, text, thinbasic, tsql, typoscript, vb, vbnet, verilog, vhdl, vim, visualfoxpro, visualprolog, whitespace, whois, winbatch, xml, xorg_conf, xpp, z80

          <target>1.5</target>
        </configuration>
      </plugin>
    </plugins>
  </build>
  <profiles>
    <profile>
      <id>openjpa</id>
      <activation>
        <activeByDefault>true</activeByDefault>
      </activation>
      <dependencies>
        <dependency>
          <groupId>org.apache.openjpa</groupId>
          <artifactId>openjpa-all</artifactId>
          <version>0.9.7-incubating-SNAPSHOT</version>
        </dependency>
      </dependencies>
      <build>
        <plugins>
          <plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>openjpa-maven-plugin</artifactId>
            <executions>
              <execution>
                <phase>process-test-resources</phase>
                <goals>
                  <goal>enhance</goal>
                </goals>
                <configuration>
                  <toolProperties>
                    <property>
                      <name>addDefaultConstructor</name>
                      <value>true</value>
                    </property>
                    <property>
                      <name>enforcePropertyRestrictions</name>
                      <value>true</value>
                    </property>
                  </toolProperties>
                </configuration>
              </execution>
            </executions>
          </plugin>
        </plugins>
        <resources>
          <resource>
            <directory>src/main/resources/openjpa</directory>
          </resource>
        </resources>
      </build>
    </profile>
  </profiles>
</project>

Katalog plików pomocniczych - src/main/resources/openjpa

Jednym z istotnych elementów w nowej konfiguracji jest inna organizacja katalogu z plikami pomocnicznymi projektu. Każdy dostawca JPA posiada własną konfigurację i każdy otrzyma swój własny katalog na pliki konfiguracyjne, m.in. META-INF/persistence.xml (można pokusić się o sprytniejszą konfigurację, ale pozostawiam to dociekliwym jako zadanie domowe).

Tworzymy nowy katalog src/main/resources/openjpa, w którym umieszczamy katalog META-INF z plikiem persistence.xml.

Grafika:m2-jpa-openjpa.png

Konfiguracja dostawcy JPA oraz jednostki utrwalania - META-INF/persistence.xml

Zawartość pliku persistence.xml dla Apache OpenJPA jako dostawcy JPA z wbudowaną bazą danych Apache Derby przedstawia się następująco:

<?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="derbyPU" transaction-type="RESOURCE_LOCAL">
    <provider>org.apache.openjpa.persistence.PersistenceProviderImpl</provider>
    <class>pl.jaceklaskowski.jpa.entity.Osoba</class>
    <class>pl.jaceklaskowski.jpa.entity.Projekt</class>
    <class>pl.jaceklaskowski.jpa.entity.PracownikSpecjalny</class>
    <exclude-unlisted-classes />
    <properties>
      <property name="openjpa.ConnectionDriverName" value="org.apache.derby.jdbc.EmbeddedDriver" />
      <property name="openjpa.ConnectionURL" value="jdbc:derby:target/derbyDB;create=true" />
      <property name="openjpa.ConnectionUserName" value="app" />
      <property name="openjpa.ConnectionPassword" value="app" />
      <property name="openjpa.jdbc.SynchronizeMappings" value="buildSchema(SchemaAction='add,deleteTableContents')" />
      <property name="openjpa.Log" value="DefaultLevel=TRACE,SQL=TRACE" />
    </properties>
  </persistence-unit>
</persistence>

Uruchomienie

Mając tak zdefiniowany projekt wykonanie testów pozostaje bez zmian, np. mvn clean test (ze względu na element activeByDefault o wartości true), bądź analogicznie, z jawnym wskazaniem profilu, mvn -Popenjpa clean test.

Na uwagę zasługuje również możliwość uruchomienia pojedyńczego testu przy pomocy -Dtest=<nazwa_skrócona_klasy_testu>, np. mvn -Dtest=ConditionalExpressionsTest -Popenjpa clean test (oczywiście -Popenjpa jest opcjonalne).

$ mvn -Dtest=ConditionalExpressionsTest -Popenjpa clean test
[INFO] Scanning for projects...
[INFO] ----------------------------------------------------------------------------
[INFO] Building jpa-query
[INFO]    task-segment: [clean, test]
[INFO] ----------------------------------------------------------------------------
[INFO] [clean:clean]
[INFO] Deleting directory c:\projs\jpa\target
[INFO] Deleting directory c:\projs\jpa\target\classes
[INFO] Deleting directory c:\projs\jpa\target\test-classes
[INFO] [resources:resources]
[INFO] Using default encoding to copy filtered resources.
[INFO] [compiler:compile]
[INFO] Compiling 5 source files to c:\projs\jpa\target\classes
[INFO] [resources:testResources]
[INFO] Using default encoding to copy filtered resources.
[INFO] [openjpa:enhance {execution: default}]
[INFO]
[ERROR] --------------------
[ERROR]  Standard error from the OpenJPA Enhancer tool:
[ERROR] --------------------
[ERROR] 0  derbyPU  TRACE  [main] openjpa.Runtime - Setting the following properties from "file:/C:/projs/jpa/target/classes/META-INF/persistence.xml" into configuration: {openjpa.
jdbc.SynchronizeMappings=buildSchema(SchemaAction='add,deleteTableContents'), openjpa.ConnectionUserName=app, openjpa.ConnectionPassword=app, openjpa.Log=DefaultLevel=TRACE,SQL=TRA
CE, openjpa.MetaDataFactory=jpa(Types=pl.jaceklaskowski.jpa.entity.Osoba;pl.jaceklaskowski.jpa.entity.Projekt;pl.jaceklaskowski.jpa.entity.PracownikSpecjalny), javax.persistence.pr
ovider=org.apache.openjpa.persistence.PersistenceProviderImpl, openjpa.ConnectionURL=jdbc:derby:target/derbyDB;create=true, openjpa.ConnectionDriverName=org.apache.derby.jdbc.Embed
dedDriver, openjpa.Id=derbyPU}
78  derbyPU  INFO   [main] openjpa.Tool - Enhancer running on type "class pl.jaceklaskowski.jpa.entity.Osoba".
141  derbyPU  TRACE  [main] openjpa.MetaData - Loading metadata for "class pl.jaceklaskowski.jpa.entity.Osoba" under mode "[META]".
141  derbyPU  TRACE  [main] openjpa.MetaData - Scanning resource "META-INF/orm.xml" for persistent types.
156  derbyPU  TRACE  [main] openjpa.MetaData - parsePersistentTypeNames() found [pl.jaceklaskowski.jpa.entity.PracownikSpecjalny, pl.jaceklaskowski.jpa.entity.Osoba, pl.jaceklaskow
ski.jpa.entity.Projekt].
156  derbyPU  INFO   [main] openjpa.MetaData - Found 3 classes with metadata in 15 milliseconds.
...
-------------------------------------------------------
 T E S T S
-------------------------------------------------------
Running pl.jaceklaskowski.jpa.chapter4_6.ConditionalExpressionsTest
15  derbyPU  TRACE  [main] openjpa.Runtime - Setting the following properties from "file:/c:/projs/jpa/target/classes/META-INF/persistence.xml" into configuration: {openjpa.jdbc.Sy
nchronizeMappings=buildSchema(SchemaAction='add,deleteTableContents'), openjpa.BrokerFactory=jdbc, openjpa.ConnectionUserName=app, openjpa.ConnectionPassword=app, openjpa.Log=Defau
ltLevel=TRACE,SQL=TRACE, openjpa.MetaDataFactory=jpa(Types=pl.jaceklaskowski.jpa.entity.Osoba;pl.jaceklaskowski.jpa.entity.Projekt;pl.jaceklaskowski.jpa.entity.PracownikSpecjalny),
 javax.persistence.provider=org.apache.openjpa.persistence.PersistenceProviderImpl, openjpa.ConnectionURL=jdbc:derby:target/derbyDB;create=true, openjpa.ConnectionDriverName=org.ap
ache.derby.jdbc.EmbeddedDriver, openjpa.Id=derbyPU}
62  derbyPU  INFO   [main] openjpa.Runtime - Starting OpenJPA 0.9.7-incubating-SNAPSHOT
...
3515  derbyPU  TRACE  [main] openjpa.Query - Executing query: SELECT DISTINCT o FROM Osoba o, IN(o.projekty) p WHERE p.rodzajProjektu = pl.jaceklaskowski.jpa.entity.RodzajProjektu.
OTWARTY
3609  derbyPU  TRACE  [main] openjpa.jdbc.SQL - <t 9971081, conn 27585366> executing prepstmnt 33066941 SELECT DISTINCT t0.numer, t0.dzienImienin, t0.dzienUrodzin, t0.imie, t0.kraj
, t0.nazwisko, t0.tytul FROM Osoba t0 INNER JOIN Osoba_Projekt t1 ON t0.numer = t1.Osoba_numer INNER JOIN Projekt t2 ON t1.projekty_nazwa = t2.nazwa WHERE (t2.rodzajProjektu = ?) [
params=(int) 0]
3609  derbyPU  TRACE  [main] openjpa.jdbc.SQL - <t 9971081, conn 27585366> [0 ms] spent
3609  derbyPU  TRACE  [main] openjpa.jdbc.JDBC - <t 9971081, conn 27585366> [0 ms] close
3968  derbyPU  TRACE  [main] openjpa.MetaData - Clearing metadata repository "org.apache.openjpa.jdbc.meta.MappingRepository@c12978".
Tests run: 3, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 4.344 sec

Results :

Tests run: 3, Failures: 0, Errors: 0, Skipped: 0

[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 9 seconds
[INFO] Finished at: Tue Mar 27 00:10:46 CEST 2007
[INFO] Final Memory: 7M/254M
[INFO] ------------------------------------------------------------------------

Na uwagę zasługuje wyświetlenie wersji wykorzystywanego oprogramowania - OpenJPA 0.9.7-incubating-SNAPSHOT, co ma niebagatelne znaczenie podczas rozwiązywania ewentualnych problemów.

Profil projektu - hibernate

Instalacja zależności w lokalnym repozytorium Apache Maven 2

Kolejny profil - hibernate - posłuży nam do uruchamiania testów korzystając z Hibernate EntityManager (Hibernate JPA).

W przypadku nauki specyfikacji Java Persistence zalecane jest, abyśmy korzystali z najświeższych wersji oprogramowania, które zapewni nam kompletne środowisko JPA z możliwie niewielką ilością błędów i niezgodności. Do uruchomienia Hibernate w roli dostawcy JPA będą nam potrzebne następujące wersje projektów:

  • Hibernate Core 3.2.2 GA
  • Hibernate Annotations 3.3.0 GA
  • Hibernate EntityManager 3.3.0 GA
  • Hibernate Validator 3.0.0 GA

Wszystkie są do pobrania na stronie Hibernate Binary Releases.

Konieczne jest ich pobranie, ponieważ wymienione wersje nie są dostępne w żadnym ze znanych repozytoriów M2 i będziemy musieli zainstalować je w lokalnym repozytorium ręcznie.

Po rozpakowaniu wspomnianych bibliotek instalujemy je i ich zależności do lokalnego repozytorium:

mvn install:install-file -DgroupId=org.hibernate -DartifactId=hibernate-annotations \
   -Dversion=3.3.0.ga -Dpackaging=jar -Dfile=c:/apps/hibernate-annotations-3.3.0.GA/hibernate-annotations.jar

mvn install:install-file -DgroupId=org.hibernate -DartifactId=hibernate-entitymanager \
   -Dversion=3.3.0.ga -Dpackaging=jar -Dfile=c:/apps/hibernate-entitymanager-3.3.0.GA/hibernate-entitymanager.jar

mvn install:install-file -DgroupId=org.hibernate -DartifactId=hibernate-commons-annotations \
   -Dversion=3.0.0.GA -Dpackaging=jar -Dfile=c:/apps/hibernate-entitymanager-3.3.0.GA/lib/hibernate-commons-annotations.jar

mvn install:install-file -DgroupId=org.hibernate -DartifactId=hibernate-validator \
   -Dversion=3.0.0.ga -Dpackaging=jar -Dfile=c:/apps/hibernate-validator-3.0.0.GA/hibernate-validator.jar

mvn install:install-file -DgroupId=javassist -DartifactId=javassist \
   -Dversion=3.4 -Dpackaging=jar -Dfile=c:/apps/hibernate-3.2.2.GA/lib/javassist.jar

Dodatkowo potrzebna będzie biblioteka JTA 1.0.1B, który nie znajduje się w repozytoriach M2 ze względu na jej licencję (więcej na stronie Coping with SUN JARs), ale jest dystrybuowana m.in. z Hibernate, więc wystarczy zainstalować bibliotekę do repozytorium lokalnego Maven wykonując polecenie:

mvn install:install-file -DgroupId=javax.transaction -DartifactId=jta -Dversion=1.0.1B -Dpackaging=jar -Dfile=c:/apps/hibernate-3.2.2.GA/lib/jta.jar

Plik pom.xml

Po zainstalowaniu bibliotek w lokalnym repozytorium Maven, przechodzimy do konfiguracji projektu - modyfikacji pliku pom.xml - o definicję profilu hibernate.

Część pliku pom.xml odpowiadająca profilowi hibernate:

<profile>
  <id>hibernate</id>
  <dependencies>
    <dependency>
      <groupId>org.hibernate</groupId>
      <artifactId>hibernate</artifactId>
      <version>3.2.2.ga</version>
    </dependency>
    <dependency>
      <groupId>org.hibernate</groupId>
      <artifactId>hibernate-entitymanager</artifactId>
      <version>3.3.0.ga</version>
    </dependency>
    <dependency>
      <groupId>org.hibernate</groupId>
      <artifactId>hibernate-annotations</artifactId>
      <version>3.3.0.ga</version>
    </dependency>
    <dependency>
      <groupId>org.hibernate</groupId>
      <artifactId>hibernate-commons-annotations</artifactId>
      <version>3.0.0.ga</version>
    </dependency>
    <dependency>
      <groupId>org.hibernate</groupId>
      <artifactId>hibernate-validator</artifactId>
      <version>3.0.0.GA</version>
    </dependency>
    <dependency>
      <groupId>javax.persistence</groupId>
      <artifactId>persistence-api</artifactId>
      <version>1.0</version>
    </dependency>
    <dependency>
      <groupId>jboss</groupId>
      <artifactId>jboss-archive-browsing</artifactId>
      <version>5.0.0alpha-200607201-119</version>
    </dependency>
    <dependency>
      <groupId>javassist</groupId>
      <artifactId>javassist</artifactId>
      <version>3.4</version>
    </dependency>
  </dependencies>
  <build>
    <resources>
      <resource>
        <directory>src/main/resources/hibernate</directory>
      </resource>
    </resources>
  </build>
</profile>

Katalog plików pomocniczych - src/main/resources/hibernate

Tworzymy katalog src/main/resources/hibernate

Grafika:m2-jpa-hibernate.png

Konfiguracja dostawcy JPA oraz jednostki utrwalania - META-INF/persistence.xml

Katalog src/main/resources/hibernate zawiera plik META-INF/persistence.xml (obok już istniejącego katalogu z konfiguracją openjpa):

<?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="derbyPU" transaction-type="RESOURCE_LOCAL">
    <provider>org.hibernate.ejb.HibernatePersistence</provider>
    <class>pl.jaceklaskowski.jpa.entity.Osoba</class>
    <class>pl.jaceklaskowski.jpa.entity.Projekt</class>
    <class>pl.jaceklaskowski.jpa.entity.PracownikSpecjalny</class>
    <exclude-unlisted-classes />
    <properties>
      <property name="hibernate.archive.autodetection" value="class, hbm" />
      <property name="hibernate.show_sql" value="true" />
      <property name="hibernate.format_sql" value="true" />
      <property name="hibernate.connection.driver_class" value="org.apache.derby.jdbc.EmbeddedDriver" />
      <property name="hibernate.connection.url" value="jdbc:derby:target/derbyDB;create=true" />
      <property name="hibernate.connection.username" value="app" />
      <property name="hibernate.connection.password" value="app" />
      <property name="hibernate.dialect" value="org.hibernate.dialect.DerbyDialect" />
      <property name="hibernate.hbm2ddl.auto" value="create-drop" />
    </properties>
  </persistence-unit>
</persistence>

Uruchomienie

Wykonanie testów z Hibernate jako dostawcą JPA i wbudowaną bazą danych Apache Derby, lub innymi słowy uruchomienie profilu hibernate, sprowadza się do wywołania polecenia mvn -Phibernate clean test. W przypadku profilu hibernate, jedyną możliwością jego uruchomienia jest jawne podanie jego nazwy jako argument opcji -P.

$ mvn -Dtest=ConditionalExpressionsTest -Phibernate clean test

[INFO] Scanning for projects...
[INFO] ----------------------------------------------------------------------------
[INFO] Building jpa-query
[INFO]    task-segment: [clean, test]
[INFO] ----------------------------------------------------------------------------
[INFO] [clean:clean]
[INFO] Deleting directory c:\projs\jpa\target
[INFO] Deleting directory c:\projs\jpa\target\classes
[INFO] Deleting directory c:\projs\jpa\target\test-classes
[INFO] [resources:resources]
[INFO] Using default encoding to copy filtered resources.
...
-------------------------------------------------------
 T E S T S
-------------------------------------------------------
Running pl.jaceklaskowski.jpa.chapter4_6.ConditionalExpressionsTest
2007-03-27 00:15:40 org.hibernate.cfg.annotations.Version <clinit>
INFO: Hibernate Annotations 3.3.0.GA
2007-03-27 00:15:40 org.hibernate.cfg.Environment <clinit>
INFO: Hibernate 3.2.2
2007-03-27 00:15:40 org.hibernate.cfg.Environment <clinit>
INFO: hibernate.properties not found
2007-03-27 00:15:40 org.hibernate.cfg.Environment buildBytecodeProvider
INFO: Bytecode provider name : cglib
2007-03-27 00:15:40 org.hibernate.cfg.Environment <clinit>
INFO: using JDK 1.4 java.sql.Timestamp handling
2007-03-27 00:15:40 org.hibernate.ejb.Version <clinit>
INFO: Hibernate EntityManager 3.3.0.GA
2007-03-27 00:15:40 org.hibernate.cfg.AnnotationBinder bindClass
INFO: Binding entity from annotated class: pl.jaceklaskowski.jpa.entity.Osoba
2007-03-27 00:15:40 org.hibernate.cfg.annotations.QueryBinder bindQuery
INFO: Binding Named query: wszystkieOsoby => SELECT o FROM Osoba o
2007-03-27 00:15:40 org.hibernate.cfg.annotations.QueryBinder bindQuery
INFO: Binding Named query: znajdzOsobyPoImieniu => SELECT o FROM Osoba o WHERE o.imie LIKE :imie
2007-03-27 00:15:40 org.hibernate.cfg.annotations.EntityBinder bindTable
INFO: Bind entity pl.jaceklaskowski.jpa.entity.Osoba on table Osoba
2007-03-27 00:15:40 org.hibernate.cfg.AnnotationBinder bindClass
INFO: Binding entity from annotated class: pl.jaceklaskowski.jpa.entity.Projekt
2007-03-27 00:15:40 org.hibernate.cfg.annotations.EntityBinder bindTable
INFO: Bind entity pl.jaceklaskowski.jpa.entity.Projekt on table Projekt
2007-03-27 00:15:40 org.hibernate.cfg.AnnotationBinder bindClass
INFO: Binding entity from annotated class: pl.jaceklaskowski.jpa.entity.PracownikSpecjalny
2007-03-27 00:15:40 org.hibernate.validator.Version <clinit>
INFO: Hibernate Validator 3.0.0.GA
2007-03-27 00:15:41 org.hibernate.connection.DriverManagerConnectionProvider configure
INFO: Using Hibernate built-in connection pool (not for production use!)
2007-03-27 00:15:41 org.hibernate.connection.DriverManagerConnectionProvider configure
INFO: Hibernate connection pool size: 20
2007-03-27 00:15:41 org.hibernate.connection.DriverManagerConnectionProvider configure
INFO: autocommit mode: true
2007-03-27 00:15:41 org.hibernate.connection.DriverManagerConnectionProvider configure
INFO: using driver: org.apache.derby.jdbc.EmbeddedDriver at URL: jdbc:derby:target/derbyDB;create=true
2007-03-27 00:15:41 org.hibernate.connection.DriverManagerConnectionProvider configure
INFO: connection properties: {user=app, password=****, autocommit=true, release_mode=auto}
2007-03-27 00:15:42 org.hibernate.cfg.SettingsFactory buildSettings
INFO: RDBMS: Apache Derby, version: 10.2.2.0 - (485682)
2007-03-27 00:15:42 org.hibernate.cfg.SettingsFactory buildSettings
INFO: JDBC driver: Apache Derby Embedded JDBC Driver, version: 10.2.2.0 - (485682)
2007-03-27 00:15:42 org.hibernate.dialect.Dialect <init>
INFO: Using dialect: org.hibernate.dialect.DerbyDialect
...
Tests run: 3, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 4.343 sec

Results :

Tests run: 3, Failures: 0, Errors: 0, Skipped: 0

[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 8 seconds
[INFO] Finished at: Tue Mar 27 00:15:44 CEST 2007
[INFO] Final Memory: 6M/254M
[INFO] ------------------------------------------------------------------------

I kolejny raz możemy przekonać się o wykorzystywanym oprogramowaniu - Hibernate Annotations 3.3.0.GA, Hibernate EntityManager 3.3.0.GA, Hibernate Validator 3.0.0.GA, Apache Derby, version: 10.2.2.0 - (485682), Apache Derby Embedded JDBC Driver, version: 10.2.2.0 - (485682).

Profil projektu - toplink

Plik pom.xml

Kolejny profil - toplink - to powtórzenie kroków wykonywanych poprzednio z profilami openjpa oraz hibernate (za wyjątkiem instalacji zależności w lokalnym repozytorium). Modyfikacja pliku pom.xml sprowadza się do dodania następującej sekcji:

<profile>
  <id>toplink</id>
  <dependencies>
    <dependency>
      <groupId>toplink.essentials</groupId>
      <artifactId>toplink-essentials</artifactId>
      <version>2.0-40</version>
    </dependency>
  </dependencies>
  <build>
    <resources>
      <resource>
        <directory>src/main/resources/toplink</directory>
      </resource>
    </resources>
  </build>
  <repositories>
    <repository>
      <id>java.net</id>
      <name>java.net Maven Repository</name>
      <url>https://maven-repository.dev.java.net/nonav/repository</url>
      <layout>legacy</layout>
    </repository>
  </repositories>
</profile>

Ważnym elementem jest definicja nowego repozytorium Maven - java.net - dla zależności toplink.essentials.toplink-essentials-2.0-40.jar. Jest to repozytorium, w którym znajduje się wiele bibliotek będących implementacjami specyfikacji Java EE 5.

Katalog plików pomocniczych - src/main/resources/toplink

Tworzymy dedykowany katalog src/main/resources/toplink.

Grafika:m2-jpa-toplink.png

Konfiguracja dostawcy JPA oraz jednostki utrwalania - META-INF/persistence.xml

Katalog src/main/resources/toplink zawiera plik META-INF/persistence.xml (obok już istniejących katalogów z konfiguracją openjpa i hibernate):

<?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="derbyPU" transaction-type="RESOURCE_LOCAL">
    <provider>oracle.toplink.essentials.ejb.cmp3.EntityManagerFactoryProvider</provider>
    <class>pl.jaceklaskowski.jpa.entity.Osoba</class>
    <class>pl.jaceklaskowski.jpa.entity.Projekt</class>
    <class>pl.jaceklaskowski.jpa.entity.PracownikSpecjalny</class>
    <exclude-unlisted-classes />
    <properties>
      <property name="toplink.jdbc.driver" value="org.apache.derby.jdbc.EmbeddedDriver" />
      <property name="toplink.jdbc.url" value="jdbc:derby:target/derbyDB;create=true" />
      <property name="toplink.jdbc.user" value="app" />
      <property name="toplink.jdbc.password" value="app" />
      <property name="toplink.ddl-generation" value="create-tables" />
    </properties>
  </persistence-unit>
</persistence>

Uruchomienie

Wykonanie testów z TopLink Essentials jako dostawcą JPA, lub innymi słowy uruchomienie profilu toplink, sprowadza się do wywołania polecenia mvn -Ptoplink clean test. Podobnie jak miało to miejsce w przypadku profilu hibernate konieczne jest podanie opcji -P z wartością toplink.

$ mvn -Dtest=ConditionalExpressionsTest -Ptoplink clean test
[INFO] Scanning for projects...
[INFO] ----------------------------------------------------------------------------
[INFO] Building jpa-query
[INFO]    task-segment: [clean, test]
[INFO] ----------------------------------------------------------------------------
[INFO] [clean:clean]
[INFO] Deleting directory c:\projs\jpa\target
[INFO] Deleting directory c:\projs\jpa\target\classes
[INFO] Deleting directory c:\projs\jpa\target\test-classes
[INFO] [resources:resources]
[INFO] Using default encoding to copy filtered resources.
[INFO] [compiler:compile]
[INFO] Compiling 5 source files to c:\projs\jpa\target\classes
[INFO] [resources:testResources]
[INFO] Using default encoding to copy filtered resources.
[INFO] [compiler:testCompile]
[INFO] Compiling 4 source files to c:\projs\jpa\target\test-classes
[INFO] [surefire:test]
[INFO] Surefire report directory: c:\projs\jpa\target\surefire-reports

-------------------------------------------------------
 T E S T S
-------------------------------------------------------
Running pl.jaceklaskowski.jpa.chapter4_6.ConditionalExpressionsTest
[TopLink Info]: 2007.03.27 12:06:09.843--ServerSession(3794357)--TopLink, version: Oracle TopLink Essentials - 2.0 (Build 40 (03/21/2007))
[TopLink Info]: 2007.03.27 12:06:11.812--ServerSession(3794357)--file:/c:/projs/jpa/target/classes/-derbyPU login successful
[TopLink Info]: 2007.03.27 12:06:12.765--ServerSession(3794357)--file:/c:/projs/jpa/target/classes/-derbyPU logout successful
Tests run: 3, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 4.063 sec

Results :

Tests run: 3, Failures: 0, Errors: 0, Skipped: 0

[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 7 seconds
[INFO] Finished at: Tue Mar 27 00:06:12 CEST 2007
[INFO] Final Memory: 5M/254M
[INFO] ------------------------------------------------------------------------

Na uwagę zasługuje wyświetlenie wersji TopLink Essentials 2.0 Build 40.

Kompletna konfiguracja projektu - pom.xml

Kompletny plik pom.xml z profilami openjpa, hibernate oraz toplink przedstawia się następująco:

<?xml version="1.0"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>pl.jaceklaskowski.jpa.query</groupId>
  <artifactId>jpa-query</artifactId>
  <name>jpa-query</name>
  <version>1.0</version>
  <dependencies>
    <dependency>
      <groupId>org.apache.derby</groupId>
      <artifactId>derby</artifactId>
      <version>10.2.2.0</version>
    </dependency>
    <dependency>
      <groupId>org.apache.derby</groupId>
      <artifactId>derbyclient</artifactId>
      <version>10.2.2.0</version>
    </dependency>
    <dependency>
      <groupId>org.testng</groupId>
      <artifactId>testng</artifactId>
      <version>5.1</version>
      <scope>test</scope>
      <classifier>jdk15</classifier>
    </dependency>
  </dependencies>
  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <configuration>

Niepoprawny język.

Musisz wybrać język w następujący sposób: <source lang="html4strict">...</source>

Języki obsługiwane w podświetlaniu składni:

abap, actionscript, actionscript3, ada, apache, applescript, apt_sources, asm, asp, autoit, avisynth, bash, basic4gl, bf, bibtex, blitzbasic, bnf, boo, c, c_mac, caddcl, cadlisp, cfdg, cfm, cil, cmake, cobol, cpp, cpp-qt, csharp, css, d, dcs, delphi, diff, div, dos, dot, eiffel, email, erlang, fo, fortran, freebasic, genero, gettext, glsl, gml, gnuplot, groovy, haskell, hq9plus, html4strict, idl, ini, inno, intercal, io, java, java5, javascript, kixtart, klonec, klonecpp, latex, lisp, locobasic, lolcode, lotusformulas, lotusscript, lscript, lsl2, lua, m68k, make, matlab, mirc, modula3, mpasm, mxml, mysql, nsis, oberon2, objc, ocaml, ocaml-brief, oobas, oracle11, oracle8, pascal, per, perl, php, php-brief, pic16, pixelbender, plsql, povray, powershell, progress, prolog, properties, providex, python, qbasic, rails, rebol, reg, robots, ruby, sas, scala, scheme, scilab, sdlbasic, smalltalk, smarty, sql, tcl, teraterm, text, thinbasic, tsql, typoscript, vb, vbnet, verilog, vhdl, vim, visualfoxpro, visualprolog, whitespace, whois, winbatch, xml, xorg_conf, xpp, z80

          <target>1.5</target>
        </configuration>
      </plugin>
    </plugins>
  </build>
  <profiles>
    <profile>
      <id>openjpa</id>
      <activation>
        <activeByDefault>true</activeByDefault>
      </activation>
      <dependencies>
        <dependency>
          <groupId>org.apache.openjpa</groupId>
          <artifactId>openjpa-all</artifactId>
          <version>0.9.7-incubating-SNAPSHOT</version>
        </dependency>
      </dependencies>
      <build>
        <plugins>
          <plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>openjpa-maven-plugin</artifactId>
            <executions>
              <execution>
                <phase>process-test-resources</phase>
                <goals>
                  <goal>enhance</goal>
                </goals>
                <configuration>
                  <toolProperties>
                    <property>
                      <name>addDefaultConstructor</name>
                      <value>true</value>
                    </property>
                    <property>
                      <name>enforcePropertyRestrictions</name>
                      <value>true</value>
                    </property>
                  </toolProperties>
                </configuration>
              </execution>
            </executions>
          </plugin>
        </plugins>
        <resources>
          <resource>
            <directory>src/main/resources/openjpa</directory>
          </resource>
        </resources>
      </build>
    </profile>
    <profile>
      <id>hibernate</id>
      <dependencies>
        <dependency>
          <groupId>org.hibernate</groupId>
          <artifactId>hibernate</artifactId>
          <version>3.2.2.ga</version>
          <exclusions>
            <exclusion>
              <groupId>javax.transaction</groupId>
              <artifactId>jta</artifactId>
            </exclusion>
          </exclusions>
        </dependency>
        <dependency>
          <groupId>org.hibernate</groupId>
          <artifactId>hibernate-entitymanager</artifactId>
          <version>3.3.0.ga</version>
        </dependency>
        <dependency>
          <groupId>org.hibernate</groupId>
          <artifactId>hibernate-annotations</artifactId>
          <version>3.3.0.ga</version>
        </dependency>
        <dependency>
          <groupId>javax.persistence</groupId>
          <artifactId>persistence-api</artifactId>
          <version>1.0</version>
        </dependency>
        <dependency>
          <groupId>jboss</groupId>
          <artifactId>jboss-archive-browsing</artifactId>
          <version>5.0.0alpha-200607201-119</version>
        </dependency>
        <dependency>
          <groupId>org.hibernate</groupId>
          <artifactId>hibernate-commons-annotations</artifactId>
          <version>3.0.0.ga</version>
        </dependency>
        <dependency>
          <groupId>javassist</groupId>
          <artifactId>javassist</artifactId>
          <version>3.4</version>
        </dependency>
        <dependency>
          <groupId>javax.transaction</groupId>
          <artifactId>jta</artifactId>
          <version>1.0.1B</version>
        </dependency>
        <dependency>
          <groupId>org.hibernate</groupId>
          <artifactId>hibernate-validator</artifactId>
          <version>3.0.0.GA</version>
        </dependency>
      </dependencies>
      <build>
        <resources>
          <resource>
            <directory>src/main/resources/hibernate</directory>
          </resource>
        </resources>
      </build>
    </profile>
    <profile>
      <id>toplink</id>
      <dependencies>
        <dependency>
          <groupId>toplink.essentials</groupId>
          <artifactId>toplink-essentials</artifactId>
          <version>2.0-40</version>
        </dependency>
      </dependencies>
      <build>
        <resources>
          <resource>
            <directory>src/main/resources/toplink</directory>
          </resource>
        </resources>
      </build>
      <repositories>
        <repository>
          <id>java.net</id>
          <name>java.net Maven Repository</name>
          <url>https://maven-repository.dev.java.net/nonav/repository</url>
          <layout>legacy</layout>
        </repository>
      </repositories>
    </profile>
  </profiles>
</project>

Eclipse IDE a profile Maven 2

Podczas modyfikacji projektu zdefiniowaliśmy openjpa jako domyślny profil projektu. Eclipse nie rozpoznaje profili i koniecznie należy zdefiniować pojedyńczy katalog zawierający META-INF/persistence.xml, aby był katalogiem ze źródłami. W ten sposób nadal będziemy mieli możliwość uruchamiania testów z wybranym dostawcą JPA, np. Apache OpenJPA, z poziomu Eclipse IDE.

Grafika:m2-jpa-openjpa-sourcecatalog.png
Osobiste