Darrera actualització: 25-06-2020

Propòsit

Aquest mòdul proporciona accés amb transaccionalitat amb la base de dades, permetent la execució d’operacions dintre de transaccions.

Aquest mòdul utilitza Spring Data JPA i QueryDSL. Es pot trobar informació sobre aquests frameworks a la documentació de referència:

Instal·lació i Configuració

Instal·lació

El mòdul de persistència i el corresponent test unitari s’inclou per defecte dins del core de Canigó 3. Durant el procés de creació de l’aplicació, l’eina de suport al desenvolupament inclourà la referència dins del pom.xml. En cas d’una instal- lació manual afegir les següents línies al pom.xml de l’aplicació:

<canigo.persistence.jpa.version>[2.3.0,2.4.0)</canigo.persistence.jpa.version>

<dependency>
	<groupId>cat.gencat.ctti</groupId>
	<artifactId>canigo.persistence.jpa</artifactId>
	<version>${canigo.persistence.jpa.version}</version>
</dependency>

Al pom.xml també s’ha d’afegir el plugin que genera les classes per als filtres de QueryDSL i el que executa el test unitari del mòdul de persistència:

<build>
	...
	<plugins>
		...
		<plugin>
			<groupId>com.mysema.maven</groupId>
			<artifactId>apt-maven-plugin</artifactId>
			<version>1.1.3</version>
			<executions>
				<execution>
					<goals>
						<goal>process</goal>
					</goals>
					<configuration>
						<outputDirectory>target/generated-sources/java</outputDirectory>
						<processor>com.querydsl.apt.jpa.JPAAnnotationProcessor</processor>
					</configuration>
				</execution>
			</executions>
		</plugin>
		...
	</plugins>
	...
</build>	

Configuració

La configuració es realitza automàticament a partir de l’eina de suport al desenvolupament (plugin de Canigó per a Eclipse)

En cas que no es generi automàticament el codi, s’ha de realitzar manualment la següent configuració:

jpa.properties

Ubicació proposada: <PROJECT_ROOT>/src/main/resources/config/props/jpa.properties

Propietat Requerit Descripció
*.persistence.database Si Sistema de base de dades al que es conectarà.
*.persistence.dialect Si El nom de classe que permet a JPA generar SQL per a una base de dades relacional en particular. Aquests són els dialectes certificats: org.hibernate.dialect.Oracle12cDialect
org.hibernate.dialect.Oracle10gDialect
org.hibernate.dialect.Oracle9iDialect
org.hibernate.dialect.Oracle8iDialect
org.hibernate.dialect.MySQL5Dialect
org.hibernate.dialect.MySQLDialect <– Versions < 5
org.hibernate.dialect.HSQLDialect
org.hibernate.dialect.PostgreSQLDialect
*.persistence.showSQL No Escriu totes les sentències SQL al log aplicatiu.
Per defecte: true
*.persistence.generateDdl No Exporta el DDL (Data Definition Language) a la BD després que l’EntityManagerFactory s’inicialitzi, creant/actualitzant les taules.
Valor per defecte: false
*.persistence.hibernate.connection.release_mode No Serveix per especificar quan Hibernate ha d’alliberar les connexions JDBC. Una connexió JDBC es manté fins que la sessió és tancada explícitament o desconnectat per defecte. Per a un datasource JTA s’hauria de seleccionar after_statement, i per non-JTA after_transaction. En mode auto, se seleccionarà after_statement per a JTA i CMT, i afte_transaction per JDBC.
Per defecte: auto
*.persistence.hibernate.connection.autocommit No Habilita l’autocommit per a connexions pooled JDBC
*.persistence.hibernate.generate_statistics No Hibernate recopila informació útil per a tunning.
Per defecte: false
*.persistence.hibernate.jdbc.use_scrollable_resultset No Habilita l’ús de JDBC2 scrollable resultsets a Hibernate.
Per defecte: true

persistence.xml

Ubicació: <PROJECT_ROOT>/src/main/resources/config/persistence/persistence.xml

<persistence xmlns="http://java.sun.com/xml/ns/persistence"	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd"
	version="1.0">

	<persistence-unit name="canigo" transaction-type="RESOURCE_LOCAL"/>

</persistence>

app-custom-persistence-jpa.xml

Ubicació: <PROJECT_ROOT>/src/main/resources/spring/app-custom-persistence-jpa.xml

Exemple del fitxer de configuració per a un base de dades H2:

<?xml version="1.0" encoding="ISO-8859-1"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
	xmlns:p="http://www.springframework.org/schema/p" xmlns:tx="http://www.springframework.org/schema/tx"
	xmlns:jdbc="http://www.springframework.org/schema/jdbc"
	xmlns:jpa="http://www.springframework.org/schema/data/jpa"
	xsi:schemaLocation="http://www.springframework.org/schema/beans 
           http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
           http://www.springframework.org/schema/tx 
           http://www.springframework.org/schema/tx/spring-tx-4.3.xsd
           http://www.springframework.org/schema/jdbc 
           http://www.springframework.org/schema/jdbc/spring-jdbc-4.3.xsd
           http://www.springframework.org/schema/aop 
           http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
           http://www.springframework.org/schema/data/jpa
    	   http://www.springframework.org/schema/data/jpa/spring-jpa.xsd">

	<aop:aspectj-autoproxy />
	
	<jpa:repositories base-package="cat.gencat.test.repository" base-class="cat.gencat.ctti.canigo.arch.persistence.jpa.repository.impl.JPAGenericRepositoryImpl"/>
	
	<bean id="jpaVendorAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
		<description>
			Fem servir Hibernate com a motor de persistència per sota de JPA.
		</description>
		<property name="showSql" value="true" />
		<property name="generateDdl" value="false" />
		<property name="database" value="${persistence.database}" />
		<property name="databasePlatform" value="${persistence.dialect}" />
	</bean>

	<tx:advice id="txAdvice">
		<tx:attributes>
			<tx:method name="get*" propagation="REQUIRED" read-only="true" />
			<tx:method name="filter*" propagation="REQUIRED" read-only="true" />
			<tx:method name="find*" propagation="REQUIRED" read-only="true" />
			<tx:method name="load*" propagation="SUPPORTS" read-only="true" />
			<tx:method name="save*" propagation="REQUIRED" />
			<tx:method name="update*" propagation="REQUIRED" />
			<tx:method name="delete*" propagation="REQUIRED" />
			<tx:method name="insert*" propagation="REQUIRED" />
		</tx:attributes>
	</tx:advice>
	
	<jdbc:embedded-database id="dataSource" type="H2">
		<jdbc:script location="classpath:scripts/h2/h2-db-app-h2db-schema.sql"/>
		<jdbc:script location="classpath:scripts/h2/h2-db-app-h2db-data.sql"/>
	</jdbc:embedded-database>

</beans>

Exemple del fitxer de configuració per a un base de dades Oracle, Mysql o Postgres per jdbc:

<?xml version="1.0" encoding="ISO-8859-1"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
	xmlns:p="http://www.springframework.org/schema/p" xmlns:tx="http://www.springframework.org/schema/tx"
	xmlns:jdbc="http://www.springframework.org/schema/jdbc"
	xmlns:jpa="http://www.springframework.org/schema/data/jpa"
	xsi:schemaLocation="http://www.springframework.org/schema/beans 
           http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
           http://www.springframework.org/schema/tx 
           http://www.springframework.org/schema/tx/spring-tx-4.3.xsd
           http://www.springframework.org/schema/jdbc 
           http://www.springframework.org/schema/jdbc/spring-jdbc-4.3.xsd
           http://www.springframework.org/schema/aop 
           http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
           http://www.springframework.org/schema/data/jpa
    	   http://www.springframework.org/schema/data/jpa/spring-jpa.xsd">

	<aop:aspectj-autoproxy />
	
	<jpa:repositories base-package="cat.gencat.test.repository" base-class="cat.gencat.ctti.canigo.arch.persistence.jpa.repository.impl.JPAGenericRepositoryImpl"/>
	
	<bean id="jpaVendorAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
		<description>
			Fem servir Hibernate com a motor de persistència per sota de JPA.
		</description>
		<property name="showSql" value="true" />
		<property name="generateDdl" value="false" />
		<property name="database" value="${persistence.database}" />
		<property name="databasePlatform" value="${persistence.dialect}" />
	</bean>

	<tx:advice id="txAdvice">
		<tx:attributes>
			<tx:method name="get*" propagation="REQUIRED" read-only="true" />
			<tx:method name="filter*" propagation="REQUIRED" read-only="true" />
			<tx:method name="find*" propagation="REQUIRED" read-only="true" />
			<tx:method name="load*" propagation="SUPPORTS" read-only="true" />
			<tx:method name="save*" propagation="REQUIRED" />
			<tx:method name="update*" propagation="REQUIRED" />
			<tx:method name="delete*" propagation="REQUIRED" />
			<tx:method name="insert*" propagation="REQUIRED" />
		</tx:attributes>
	</tx:advice>
	
	<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource" destroy-method="close">
	  <property name="driverClassName" value="${jdbc.driverClassName}"/>
	  <property name="url" value="${jdbc.url}"/>
	  <property name="username" value="${jdbc.username}"/>
	  <property name="password" value="${jdbc.password}"/>
	</bean>

</beans>

Exemple del fitxer de configuració per a un base de dades Oracle, Mysql o Postgres per jndi:

<?xml version="1.0" encoding="ISO-8859-1"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
	xmlns:p="http://www.springframework.org/schema/p" xmlns:tx="http://www.springframework.org/schema/tx"
	xmlns:jdbc="http://www.springframework.org/schema/jdbc"
	xmlns:jpa="http://www.springframework.org/schema/data/jpa"
	xsi:schemaLocation="http://www.springframework.org/schema/beans 
           http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
           http://www.springframework.org/schema/tx 
           http://www.springframework.org/schema/tx/spring-tx-4.3.xsd
           http://www.springframework.org/schema/jdbc 
           http://www.springframework.org/schema/jdbc/spring-jdbc-4.3.xsd
           http://www.springframework.org/schema/aop 
           http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
           http://www.springframework.org/schema/data/jpa
    	   http://www.springframework.org/schema/data/jpa/spring-jpa.xsd">

	<aop:aspectj-autoproxy />
	
	<jpa:repositories base-package="cat.gencat.test.repository" base-class="cat.gencat.ctti.canigo.arch.persistence.jpa.repository.impl.JPAGenericRepositoryImpl"/>
	
	<bean id="jpaVendorAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
		<description>
			Fem servir Hibernate com a motor de persistència per sota de JPA.
		</description>
		<property name="showSql" value="true" />
		<property name="generateDdl" value="false" />
		<property name="database" value="${persistence.database}" />
		<property name="databasePlatform" value="${persistence.dialect}" />
	</bean>

	<tx:advice id="txAdvice">
		<tx:attributes>
			<tx:method name="get*" propagation="REQUIRED" read-only="true" />
			<tx:method name="filter*" propagation="REQUIRED" read-only="true" />
			<tx:method name="find*" propagation="REQUIRED" read-only="true" />
			<tx:method name="load*" propagation="SUPPORTS" read-only="true" />
			<tx:method name="save*" propagation="REQUIRED" />
			<tx:method name="update*" propagation="REQUIRED" />
			<tx:method name="delete*" propagation="REQUIRED" />
			<tx:method name="insert*" propagation="REQUIRED" />
		</tx:attributes>
	</tx:advice>
	
	<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
	  <property name="jndiName" value="${jndi.name}"/>
	  <property name="lookupOnStartup" value="${jndi.lookupOnStartup:true}"/>
	  <property name="cache" value="${jndi.cache:true}"/>
	  <property name="proxyInterface" value="javax.sql.DataSource"/>
	</bean>

</beans>

Al tag jpa:repositories al paràmetre base-package s’ha d’indicar el package on es troben els repositoris de l’aplicació.

jdbc.properties

Propietat si l’aplicació va per jdbc

Ubicació proposada: <PROJECT_ROOT>/src/main/resources/config/props/jdbc.properties

Propietat Requerit Descripció
*.jdbc.driverClassName Si Nom de classe del driver per a la connexió a la base de dades.
*.jdbc.url Si URL de connexió a la base de dades.
*.jdbc.username Si Usuari de connexió a la base de dades.
*.jdbc.password Si Password de connexió a la base de dades

jndi.properties

Propietat si l’aplicació va per jndi

Ubicació proposada: <PROJECT_ROOT>/src/main/resources/config/props/jndi.properties

Propietat Requerit Descripció
*.jndi.name Si Especifica el nom JNDI a cercar.
*.jndi.lookupOnStartup No Cerca l’objecte JNDI durant l’arranc. Per defecte: true.
*.jndi.cache No Permet cachejar l’objecte JNDI. Per defecte: true.

Ús dels repositoris

Per a utilitzar els repositoris s’ha de generar un objecte Repository per a l’entitat desitjada(T), que ha d’estendre de cat.gencat.ctti.canigo.arch.persistence.jpa.repository.GenericRepository<T, ID extends Serializable>

public interface EquipamentRepository extends GenericRepository<Equipament, Long>{

}

Construcció de queries automàtiques

A un repositori es poden definir mètodes per cada query que es vulgui definir. La construcció utilitza els prefixos find…By, read…By, query…By, count…By i get…By. El mètode pot incoporar la paraula Distinct, concatenar propietats amb And i Or o descriptors com OrderBy o IgnoreCase.

Exemples:

List<Equipament> findDistinctByNomOrMunicipi(String nom, String municipi);
List<Equipament> findByNomIgnoreCase(String nom);
List<Equipament> findByMunicipiOrderByNomDesc(String municipi);

Més informació a la documentació oficial de Spring Data JPA.

Utilització de QueryDSL

Una de les funcionalitats proposades és la d’utilitzar QueryDSL per a realitzar cerques segons filtres dinàmics, amb paginació i/o ordenació.

El GenericRepository proporciona el següent mètode:

Page<T> findAll(Predicate predicate, Pageable pageable);

Aquest mètode espera un objecte org.springframework.data.domain.Pageable que conté el número de pàgina (la primera pàgina és la 0), el nombre d’elements per pàgina, la direcció d’ordenació, el camp d’ordenació. I un objecte Predicate amb la query a realitzar que es construeix de la següent manera:

Primer de tot el filtre ha de ser un String amb el següent patró:

field1Operador1Valor1,field2Operador2Valor2,fieldNOperadorNValorN

  • on Field és el nom d’una propietat de l’entitat (per exemple id)
  • on Operador és un dels tipus d’operador suportats:
Operador Descripció
| major que
| major o igual que < | menor que <: | menor o igual que <> | diferent de : | igual que
  • on valor és el valor amb el qual es vol comparar.

Per exemple, per cercar l’entitat que tingui id major que 15 i amb nom igual a ‘Prova’ el filtre hauria de ser el següent:
id>15,nom:Prova

Projecció de resultats

Amb QueryDSL també es poden realitzar cerques que en comptes de retornar l’objecte sencer, retorni només determinats camps de l’objecte desitjat, els camps no seleccionats els retorna amb valor null

Per a utilitzar les projeccions el GenericRepository proporciona el següent mètode:

Page<T> findAll(FactoryExpression<T> factoryExpression, Predicate predicate, Pageable pageable);

El codi següent retorna una llista dels objectes Equipaments amb nom INDOORKARTING, però aquests objectes només tindran el camp nom.

String search = "nom:INDOORKARTING";
		
Pageable pageable = new PageRequest(0, 5, Sort.Direction.DESC, "nom");
GenericPredicateBuilder<Equipament> builder = new GenericPredicateBuilder<Equipament>(Equipament.class, "equipament");
builder.populateSearchCriteria(search);
		
QEquipament qequipament = QEquipament.equipament;
	
Page<Equipament> page = repository.findAll(Projections.bean(Equipament.class, qequipament.nom ), builder.build(), pageable);

Més informació a la documentació oficial de QueryDSL.

Batch Inserts/Update

La classe GenericRepository també proporciona un mètode per a realitzar inserts/updates de forma massiva amb un rendiment òptim:

public <S extends T> List<S> bulkSave(Iterable<S> entities);

Es pot veure un exemple de com utilitzar aquesta classe al següent howto

Exemple

Per exemple a l’aplicació inicial que genera el plugin de Canigó es generen els següents fitxers:

Equipament.java

Ubicació: <PROJECT_ROOT>/src/main/java/cat/gencat/test/model/Equipament.java

package cat.gencat.test.model;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name = "equipaments")
public class Equipament {

	private Long id;
	private String nom;
	private String municipi;

	public Equipament() {
		
	}
	
	public Equipament(Long id) {
		this.id =id;
	}
	
	@Id
	@Column(name = "id", nullable = false, unique = true)
	public Long getId() {
		return id;
	}

	public void setId(Long id) {
		this.id = id;
	}

	
	@Column(name = "nom", nullable = false, unique = true)
	public String getNom() {
		return nom;
	}

	public void setNom(String nom) {
		this.nom = nom;
	}

	@Column(name = "municipi")
	public String getMunicipi() {
		return municipi;
	}

	public void setMunicipi(String municipi) {
		this.municipi = municipi;
	}	
	
	@Override
	public String toString() {
		return "Equipament [nom=" + nom + "]";
	}
}

EquipamentRepository

Ubicació: <PROJECT_ROOT>/src/main/java/cat/gencat/test/repository/EquipamentRepository.java

package cat.gencat.test.repository;

import java.util.List;

import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;

import com.querydsl.core.types.FactoryExpression;
import com.querydsl.core.types.Predicate;

import cat.gencat.test.model.Equipament;
import cat.gencat.ctti.canigo.arch.persistence.jpa.repository.GenericRepository;

public interface EquipamentRepository extends GenericRepository<Equipament, Long> {

	Page<Equipament> findAll(Predicate predicate, Pageable pageable);
	
	Page<Equipament> findAll(FactoryExpression<Equipament> factoryExpression, Predicate predicate, Pageable pageable);
	
    List<Equipament> findDistinctByNomOrMunicipi(String nom, String municipi);
	List<Equipament> findByNomIgnoreCase(String nom);
	List<Equipament> findByMunicipiOrderByNomDesc(String municipi);
}

EquipamentService

Ubicació: <PROJECT_ROOT>/src/main/java/cat/gencat/test/service/EquipamentService.java

package cat.gencat.test.service;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.stereotype.Service;

import com.querydsl.core.types.Projections;

import cat.gencat.ctti.canigo.arch.persistence.jpa.querydsl.GenericPredicateBuilder;
import cat.gencat.test.model.Equipament;
import cat.gencat.test.model.QEquipament;
import cat.gencat.test.repository.EquipamentRepository;

@Service("equipamentService")
@Lazy
public class EquipamentService {

	@Autowired
	private EquipamentRepository repository;
	
	public List<Equipament> findAll() {
		return repository.findAll();
	}

	public Page<Equipament> findPaginated(Pageable pageable, String filter) {
		
		GenericPredicateBuilder<Equipament> builder = new GenericPredicateBuilder<Equipament>(Equipament.class, "equipament");
		builder.populateSearchCriteria(filter);
		
		return repository.findAll(builder.build(), pageable);
	}
	
	public Page<Equipament> findPaginatedProjeccio(Pageable pageable, String filter) {
		
		GenericPredicateBuilder<Equipament> builder = new GenericPredicateBuilder<Equipament>(Equipament.class, "equipament");
		builder.populateSearchCriteria(filter);
		
	    QEquipament qequipament = QEquipament.equipament;
	    
	    return repository.findAll(Projections.bean(Equipament.class, qequipament.nom ), builder.build(), pageable);
	}

	public Equipament getEquipament(Long equipamentId) {
		return repository.findOne(equipamentId);
	}

	public Long saveEquipament(Equipament equipament) {
		repository.save(equipament);

		return equipament.getId();
	}

	public void updateEquipament(Equipament equipament) {
		repository.save(equipament);
	}

	public void deleteEquipament(Long equipamentId) {
		Equipament equipament = new Equipament(equipamentId);
		repository.delete(equipament);
	}

}

Test

Per executar els tests del mòdul jpa al executar els test de l’aplicació és necessari incorporar la dependencia test-jar del mòdul en el pom:

...
		<dependency>
		   <groupId>cat.gencat.ctti</groupId>
		   <artifactId>canigo.persistence.jpa</artifactId>
		   <type>test-jar</type>
		   <version>${canigo.persistence.jpa.version}</version>
		   <scope>test</scope>
		   <classifier>tests</classifier>
		</dependency>
...

persistence.xml

Ubicació: <PROJECT_ROOT>/src/test/resources/config/persistence/persistence.xml És necessari afegir les entitats del mòdul jpa i les entitats de l’aplicació al fitxer persistence.xml:

<persistence xmlns="http://java.sun.com/xml/ns/persistence"	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd"
	version="1.0">

	<persistence-unit name="canigo" transaction-type="RESOURCE_LOCAL">
		<class>cat.gencat.test.model.Equipament</class>  
		<class>cat.gencat.ctti.canigo.arch.persistence.jpa.repository.Person</class> 
		<class>cat.gencat.ctti.canigo.arch.persistence.jpa.dao.Account</class>
		<class>cat.gencat.ctti.canigo.arch.persistence.jpa.model.json.postgres.EventJson</class>
		<class>cat.gencat.ctti.canigo.arch.persistence.jpa.model.json.postgres.EventJsonb</class>
		<class>cat.gencat.ctti.canigo.arch.persistence.jpa.model.json.postgres.EventJsonbNode</class>
		<class>cat.gencat.ctti.canigo.arch.persistence.jpa.model.json.mysql.EventJson</class>
	</persistence-unit>

</persistence>

On:

  • cat.gencat.test.model.Equipament és l’entitat de l’aplicació
  • cat.gencat.ctti.canigo.arch.persistence.jpa.* son les entitats del mòdul jpa

Amb aquests canvis s’executaran els test del mòdul al executar els tests de l’aplicació

Suport pel tipus de dada JSON

Des de la versió 1.3.1 del mòdul de persistència el tipus de dada JSON està suportat per MySQL i per PostgreSQL, fent la transformació entre JSON i l’objecte mapejat de manera automàtica.

Per fer ús només cal seguir els següents passos:

  1. Anotar l’entitat (o una superclasse) amb @org.hibernate.annotations.TypeDef per definir el/els àlies de mapeig.
  2. Anotar el camp de l’entitat amb @org.hibernate.annotations.Type(type = "json") com al següent exemple:

Un exemple senzill seria el següent:

import cat.gencat.ctti.canigo.arch.persistence.jpa.hibernate.type.json.JsonBinaryType;
import cat.gencat.ctti.canigo.arch.persistence.jpa.hibernate.type.json.JsonNodeBinaryType;
import cat.gencat.ctti.canigo.arch.persistence.jpa.hibernate.type.json.JsonStringType;

import org.hibernate.annotations.Type;
import org.hibernate.annotations.TypeDef;
import org.hibernate.annotations.TypeDefs;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Table;

@TypeDefs({ @TypeDef(name = "json", typeClass = JsonStringType.class),
		@TypeDef(name = "jsonb", typeClass = JsonBinaryType.class),
		@TypeDef(name = "jsonb-node", typeClass = JsonNodeBinaryType.class), })
@Entity(name = "MyCustomer")
@Table(name = "customer")
public class MyCustomer {

	@Type(type = "json")
	@Column
	private ComplexCustomerData complexCustomerData;

	public ComplexCustomerData getComplexCustomerData() {
		return complexCustomerData;
	}
	
	public void setComplexCustomerData(ComplexCustomerData complexCustomerData) {
		this.complexCustomerData =complexCustomerData;
	}
}

NOTA: La definició SQL d’un camp de tipus JSON no és estandard i s’ha de consultar la documentació de la BBDD.