8. Spring Data JPA OpenJpa
8.1. Introduction
Retomamos a arquitetura anterior, que agora implementamos com uma camada JPA / OpenJpa.
![]() |
8.2. Configuração do ambiente de trabalho
Com o STS, descarregue o projeto [myql-config-jpa-eclipselink] [1-4]:
![]() |
e, em seguida, importe o projeto [mysl-config-jpa-openjpa] [5], que se encontra na pasta [<exemples>/spring-database-config/mysql/eclipse] [6]:
![]() |
Feito isto, reinicie o ambiente Maven (Alt-F5) de todos os projetos presentes em [Package Explorer]:
![]() |
Em seguida, para verificar o ambiente de trabalho, execute a configuração de execução denominada [spring-jpa-generic-JUnitTestDao-openjpa]:
![]() | ![]() |
Esta configuração executa o teste [JUnitTestDao]. Este teste deve ser bem-sucedido:
![]() |
8.3. O projeto de configuração da camada JPA
![]() |
Este projeto tem como função configurar a camada JPA da arquitetura abaixo:
![]() |
8.3.1. Configuração do Maven
O projeto é um projeto Maven e está configurado pelo seguinte ficheiro [pom.xml]:
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<groupId>dvp.spring.database</groupId>
<artifactId>generic-config-jpa</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>configuration mysql openjpa</name>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.2.3.RELEASE</version>
</parent>
<dependencies>
<!-- dependências variáveis ********************************************** -->
<!-- JPA fornecedor -->
<dependency>
<groupId>org.apache.openjpa</groupId>
<artifactId>openjpa</artifactId>
<version>2.3.0</version>
</dependency>
<!-- dependências constantes ********************************************** -->
<!-- Spring Data -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
</dependency>
<!-- configuração herdada de JDBC -->
<dependency>
<groupId>dvp.spring.database</groupId>
<artifactId>generic-config-jdbc</artifactId>
<version>0.0.1-SNAPSHOT</version>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.7</java.version>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.18.1</version>
</plugin>
</plugins>
</build>
</project>
- linhas 5-7: o artefacto Maven gerado por este projeto. É o mesmo que o do projeto [mysql-config-jpa-hibernate]. Isto significa que apenas um destes projetos pode estar ativo de cada vez;
- linhas 10-14: o projeto Maven pai que define a versão da maioria das dependências necessárias ao projeto;
- linhas 19-23: a biblioteca OpenJpa;
- linhas 26-29: a biblioteca Spring Data;
- linhas 32-34: o projeto de configuração da camada JPA baseia-se no projeto de configuração da camada JDBC, que define, entre outras coisas, o controlador JDBC do SGBD utilizado e as coordenadas da base de dados a utilizar;
- linhas 35-40: o projeto de configuração da camada JDBC inclui a biblioteca [Spring JDBC], que aqui é substituída pela biblioteca [Spring Data JPA]. Por isso, recomenda-se que não seja incluída nas dependências do projeto. No entanto, se permanecer, isso não causará erros;
No final, as dependências são as seguintes:
![]() |
8.3.2. Configuração do Spring
![]() |
A classe [ConfigJpa] configura o projeto Spring da seguinte forma:
package generic.jpa.config;
import generic.jdbc.config.ConfigJdbc;
import javax.persistence.EntityManagerFactory;
import org.apache.tomcat.jdbc.pool.DataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.JpaVendorAdapter;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.Database;
import org.springframework.orm.jpa.vendor.OpenJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;
@Configuration
@Import({ConfigJdbc.class})
public class ConfigJpa {
// o provedor JPA
@Bean
public JpaVendorAdapter jpaVendorAdapter() {
OpenJpaVendorAdapter openJpaVendorAdapter = new OpenJpaVendorAdapter();
openJpaVendorAdapter.setShowSql(false);
openJpaVendorAdapter.setDatabase(Database.MYSQL);
openJpaVendorAdapter.setGenerateDdl(true);
return openJpaVendorAdapter;
}
// pacotes de entidades JPA
public final static String[] ENTITIES_PACKAGES = { "generic.jpa.entities.dbproduitscategories" };
// fonte de dados
@Bean
public DataSource dataSource() {
// fonte de dados TomcatJdbc
DataSource dataSource = new DataSource();
// configuração de acesso JDBC
dataSource.setDriverClassName(ConfigJdbc.DRIVER_CLASSNAME);
dataSource.setUsername(ConfigJdbc.USER_DBPRODUITSCATEGORIES);
dataSource.setPassword(ConfigJdbc.PASSWD_DBPRODUITSCATEGORIES);
dataSource.setUrl(ConfigJdbc.URL_DBPRODUITSCATEGORIES);
// ligações abertas inicialmente
dataSource.setInitialSize(5);
// resultado
return dataSource;
}
// EntityManagerFactory
@Bean
public EntityManagerFactory entityManagerFactory(JpaVendorAdapter jpaVendorAdapter, DataSource dataSource) {
LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
factory.setJpaVendorAdapter(jpaVendorAdapter);
factory.setPackagesToScan(ENTITIES_PACKAGES);
factory.setDataSource(dataSource);
factory.afterPropertiesSet();
return factory.getObject();
}
// Gestor de transações
@Bean
public PlatformTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
JpaTransactionManager txManager = new JpaTransactionManager();
txManager.setEntityManagerFactory(entityManagerFactory);
return txManager;
}
}
Esta configuração é análoga à descrita no parágrafo 6.3.2, para a implementação JPA do Hibernate. Apenas detalhamos as diferenças:
- linhas 23-30: o bean [jpaVendorAdapter] é agora implementado com OpenJpa;
8.4. O ficheiro [persistence.xml]
![]() |
<?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="generic-jpa-entities-dbproduitscategories" transaction-type="RESOURCE_LOCAL">
<!-- entidades JPA -->
<class>generic.jpa.entities.dbproduitscategories.Categorie</class>
<class>generic.jpa.entities.dbproduitscategories.Produit</class>
<class>generic.jpa.entities.dbproduitscategories.User</class>
<class>generic.jpa.entities.dbproduitscategories.Role</class>
<class>generic.jpa.entities.dbproduitscategories.UserRole</class>
<exclude-unlisted-classes />
</persistence-unit>
<persistence-unit name="generic-jpa-entities-dbproduits" transaction-type="RESOURCE_LOCAL">
<!-- Entidades JPA -->
<class>generic.jpa.entities.dbproduits.Produit</class>
<exclude-unlisted-classes />
</persistence-unit>
</persistence>
- linha 4: a unidade de persistência associada à base [dbproduitscategories]. Pode ter qualquer nome (atributo name);
- linhas 6-10: as cinco entidades JPA a gerir;
- linhas 13-17: outra unidade de persistência associada à base [dbproduits]. O OpenJpa permite ter um ficheiro de persistência com várias unidades de persistência. O EclipseLink não permite isso. Recorde-se que, com o Hibernate, não se utilizou nenhum ficheiro de persistência;
8.5. A camada de testes
![]() |
![]() |
Os testes acima são idênticos aos das implementações Spring JDBC, Spring JPA Hibernate e Spring JPA EclipseLink. Consulte as páginas seguintes, se necessário:
- [JUnitTestCheckArguments]: parágrafo 4.11.1;
- [JUnitTestDao]: parágrafo 4.11.2;
- [JUnitTestPushTheLimits]: parágrafo 4.11.3;
- [JUnitTestProxies]: parágrafo 6.4.5;
As configurações de execução a utilizar são as seguintes:
![]() | ![]() |
![]() | ![]() |
Para que as entidades JPA sejam enriquecidas (woven) pela OpenJpa, é necessário que as aplicações Java ou os testes JUnit sejam executados com um agente Java. Este irá enriquecer as entidades JPA antes de estas serem carregadas pelo JVM [http://openjpa.apache.org/builds/1.2.3/apache-openjpa/docs/ref_guide_pc_enhance.html]. Vejamos, por exemplo, a configuração do teste [JUnitTestDao]:
![]() |
- no separador [Arguments] [1], indica-se a referência do agente Java para o JVM de acordo com a sintaxe [2]. O agente Java é o arquivo [openjpa-<version>.jar], que se encontra na pasta [<m2-repo>/org/apache/openjpa/<version>]. A pasta <m2-repo> está indicada na configuração do Eclipse ([3] abaixo):
![]() |
No [2], acima, foi utilizada uma variável [M2_REPO] definida pelo utilizador:
![]() |
A variável [M2_REPO] recebeu o valor visível em [3].
Os resultados obtidos para os testes [JUnitTestDao] e [JUnitTestPushTheLimits] são os seguintes:
![]() |
![]() |
![]() |
- em [1], [JUnitTestPushTheLimits-EclipseLink]: 70,583 s;
- em [2], [JUnitTestPushTheLimits-Hibernate]: 78,945 s;
- em [3], [JUnitTestPushTheLimits-JDBC]: 36,09 s;
- em [4], [JUnitTestPushTheLimits-OpenJpa]: 80,394 s;
Os resultados obtidos na consola para o teste [JUnitTestProxies] são os seguintes:
Vemos aqui que, quando se acede ao campo [Categorie.produits] de uma categoria do tipo PROXY e ao campo [Produit.categorie] de um produto do tipo PROXY, obtém-se um ponteiro null em ambos os casos (linhas 7 e 17).























