una tipos que persistentes persistente persistencia objetos ejercicios ejemplos datos clase archivos java jpa

java - tipos - que es una clase persistente



Agregar clases de entidad dinámicamente en tiempo de ejecución (2)

JPA aún no ofrece esta función. Aquí hay tres opciones que puede consultar:

  • ¿Carga programáticamente las clases de Entity con JPA 2.0?
    Esta pregunta sobre SO es similar a la tuya. Una respuesta informa que es factible con Spring.

  • JPA 2.0: Agregar clases de entidad a PersistenceUnit * desde diferentes jar * automáticamente
    Buenos consejos se dan aquí.

  • Por último, un trabajo simple:
    1. Genere un persistence.xml sobre la marcha (creación simple de archivos XML) con una nueva unidad de persistencia.
    2. Agregue el archivo de persistencia a classpath dinámicamente ( URLCLassLoader )
    3. Solicite a PersistenceProvider que cargue una nueva unidad de persistencia ( createEntityManagerFactory )

EDITAR:

Si el proveedor de JPA es Hibernate, desde Hibernate 4.0, es posible pasar entidades directamente a este proveedor de JPA sin declararlas en el archivo persistence.xml . Hibernate se encargará de las entidades sobre la marcha.

EDITAR:

Aquí hay una configuración de muestra de JPA 2.1 + Hibernate 4.3.7.Final sin declarar ninguna entidad:

META-INF / persistence.xml

<?xml version="1.0" encoding="UTF-8" ?> <persistence xmlns="http://xmlns.jcp.org/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="2.1"> <persistence-unit name="my-persistence-unit" transaction-type="RESOURCE_LOCAL"> <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider> <properties> <!-- Database Properties --> <property name="javax.persistence.jdbc.url" value="jdbc:postgresql://localhost:5432/my-database" /> <property name="javax.persistence.jdbc.user" value="login" /> <property name="javax.persistence.jdbc.password" value="password" /> <!-- Hibernate Properties --> <property name="hibernate.connection.driver_class" value="org.postgresql.Driver" /> <property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect" /> <property name="hibernate.default_schema" value="public" /> <property name="hibernate.hbm2ddl.auto" value="update" /> <property name="hibernate.show_sql" value="false" /> <property name="hibernate.format_sql" value="true" /> <!-- Connection Pool --> <property name="hibernate.c3p0.min_size" value="5" /> <property name="hibernate.c3p0.max_size" value="20" /> <property name="hibernate.c3p0.timeout" value="500" /> <property name="hibernate.c3p0.max_statements" value="50" /> <property name="hibernate.c3p0.idle_test_period" value="2000" /> </properties> </persistence-unit> </persistence>

Referencias

Tengo este requisito para agregar clases de entidad a la unidad de persistencia en tiempo de ejecución en lugar de especificarlas todas en persistence.xml. ¿Alguien puede ayudarme con lo mismo?

Soy consciente de que Hibernate tiene su propio mecanismo de hacer lo mismo usando:

AnnotationConfiguration.addAnnotatedClass(Class) , etc. - También puede agregar hibernate config ( *.hbm.xml ) archivos mediante programación.

El requisito es que, sin reiniciar el servidor de la aplicación, pueda seguir agregando dinámicamente clases de entidad / sus archivos de configuración (mapeo) a la unidad de persistencia.

Pero la solución para agregar programáticamente clases de entidad / archivos de configuración en tiempo de ejecución a la unidad de persistencia no debe ser específica para una implementación de JPA.


Llego tarde a la fiesta, pero creo que esto les ahorrará a algunas personas un poco de dolor de cabeza. Implementé el escaneo classpath para JPA puro (no se necesita primavera, etc.) que se integra con, por ejemplo, guice-persist si es necesario también.

Esto es lo que debes hacer.

Primero, cambie persistence.xml y agregue su propia implementación, como:

<persistence xmlns="http://xmlns.jcp.org/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="2.1"> <persistence-unit name="my.persistence.unit" transaction-type="RESOURCE_LOCAL"> <provider>my.custom.package.HibernateDynamicPersistenceProvider</provider> <exclude-unlisted-classes>true</exclude-unlisted-classes> <properties> <property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect" /> <property name="hibernate.max_fetch_depth" value="30" /> <property name="hibernate.hbm2ddl.auto" value="update" /> <property name="hibernate.show_sql" value="true" /> </properties> </persistence-unit>

Para que los Proveedores sean reconocidos, deberá hacerlo visible. JPA descubre el uso del mecanismo de carga del servicio, por lo que agregamos:

/src/main/resources/META-INF/services/javax.persistence.spi.PersistenceProvider

Este archivo tiene exactamente una línea:

my.custom.package.HibernateDynamicPersistenceProvider

Finalmente, agregue su propio proveedor y baselo en HibernateProvider (lo base en eso porque quiero usar hibernación):

public class HibernateDynamicPersistenceProvider extends HibernatePersistenceProvider implements PersistenceProvider { private static final Logger log = Logger.getLogger(HibernateDynamicPersistenceProvider.class); public static final String CUSTOM_CLASSES = "CUSTOM_CLASSES"; @Override protected EntityManagerFactoryBuilder getEntityManagerFactoryBuilder( PersistenceUnitDescriptor persistenceUnitDescriptor, Map integration, ClassLoader providedClassLoader) { if(persistenceUnitDescriptor instanceof ParsedPersistenceXmlDescriptor) { ParsedPersistenceXmlDescriptor tmp = (ParsedPersistenceXmlDescriptor) persistenceUnitDescriptor; Object object = integration.get("CUSTOM_CLASSES"); } return super.getEntityManagerFactoryBuilder(persistenceUnitDescriptor, integration, providedClassLoader); } protected EntityManagerFactoryBuilder getEntityManagerFactoryBuilderOrNull(String persistenceUnitName, Map properties, ClassLoader providedClassLoader) { log.debug( String.format("Attempting to obtain correct EntityManagerFactoryBuilder for persistenceUnitName : %s", persistenceUnitName )); final Map integration = wrap( properties ); final List<ParsedPersistenceXmlDescriptor> units; try { units = PersistenceXmlParser.locatePersistenceUnits( integration ); } catch (Exception e) { log.debug( "Unable to locate persistence units", e ); throw new PersistenceException( "Unable to locate persistence units", e ); } log.debug( String.format("Located and parsed %s persistence units; checking each", units.size() )); if ( persistenceUnitName == null && units.size() > 1 ) { // no persistence-unit name to look for was given and we found multiple persistence-units throw new PersistenceException( "No name provided and multiple persistence units found" ); } for ( ParsedPersistenceXmlDescriptor persistenceUnit : units ) { log.debug( String.format( "Checking persistence-unit [name=%s, explicit-provider=%s] against incoming persistence unit name [%s]", persistenceUnit.getName(), persistenceUnit.getProviderClassName(), persistenceUnitName )); final boolean matches = persistenceUnitName == null || persistenceUnit.getName().equals( persistenceUnitName ); if ( !matches ) { log.debug( "Excluding from consideration due to name mis-match" ); continue; } // See if we (Hibernate) are the persistence provider String extractRequestedProviderName = ProviderChecker.extractRequestedProviderName(persistenceUnit, integration); if ( ! ProviderChecker.isProvider( persistenceUnit, properties ) && !(this.getClass().getName().equals(extractRequestedProviderName))) { log.debug( "Excluding from consideration due to provider mis-match" ); continue; } return getEntityManagerFactoryBuilder( persistenceUnit, integration, providedClassLoader ); } log.debug( "Found no matching persistence units" ); return null; } }

Tuve que sobreescribir 2 métodos, primero:

protected EntityManagerFactoryBuilder getEntityManagerFactoryBuilder( PersistenceUnitDescriptor persistenceUnitDescriptor, Map integration, ClassLoader providedClassLoader)

Este es el método de interceptación. Agregué una propiedad personalizada "CUSTOM_CLASSES" que realmente debería llamarse "CUSTOM_PACKAGES" que enumerará todos los paquetes que necesitan ser escaneados. En este punto, soy un poco vago y omitiré el escaneo del classpath, pero puedes hacerlo tú mismo, es bastante directo. A continuación, puede llamar

tmp.addClasses("class1", "class2");

Donde las clases son las que descubriste

El segundo método que estamos anulando es:

protected EntityManagerFactoryBuilder getEntityManagerFactoryBuilderOrNull(String persistenceUnitName, Map properties, ClassLoader providedClassLoader)

Esto se debe a que el proveedor que estamos ampliando está codificado de manera que solo permita que las clases de hibernación creen un EMF. Como tenemos una clase personalizada que intercepta la construcción, nuestros nombres no se suman. Entonces agregué:

String extractRequestedProviderName = ProviderChecker.extractRequestedProviderName(persistenceUnit, integration); if ( ! ProviderChecker.isProvider( persistenceUnit, properties ) && !(this.getClass().getName().equals(extractRequestedProviderName))) { log.debug( "Excluding from consideration due to provider mis-match" ); continue; }

Esto amplía la verificación de hibernación normal para incluir también mi proveedor personalizado para que sea válido.

Wola, hemos terminado, ahora tiene hibernate habilitado escaneo classpath con JPA.