web-dev-qa-db-fra.com

Créer JPA EntityManager sans le fichier de configuration persistence.xml

Existe-t-il un moyen d'initialiser la EntityManager sans qu'une unité de persistance soit définie? Pouvez-vous donner toutes les propriétés requises pour créer un gestionnaire d'entités? Je dois créer la EntityManager à partir des valeurs spécifiées par l'utilisateur au moment de l'exécution. La mise à jour du persistence.xml et la recompilation ne sont pas une option.

Toute idée sur la façon de procéder est plus que bienvenue!

70
javydreamercsw

Existe-t-il un moyen d'initialiser le EntityManager sans qu'une unité de persistance soit définie?

Vous devez définir au moins une unité de persistance dans le descripteur de déploiement persistence.xml.

Pouvez-vous donner toutes les propriétés requises pour créer un Entitymanager?

  • L'attribut name est requis. Les autres attributs et éléments sont facultatifs. (Spécification JPA). Cela devrait donc être plus ou moins votre fichier persistence.xml minimal:
<persistence>
    <persistence-unit name="[REQUIRED_PERSISTENCE_UNIT_NAME_GOES_HERE]">
        SOME_PROPERTIES
    </persistence-unit>
</persistence>

Dans les environnements Java EE, les éléments jta-data-source et non-jta-data-source permettent de spécifier le nom JNDI global de la source de données JTA et/ou non JTA à utiliser par le fournisseur de persistance.

Ainsi, si votre serveur d'applications cible prend en charge JTA (JBoss, Websphere, GlassFish), votre persistence.xml ressemble à ceci:

<persistence>
    <persistence-unit name="[REQUIRED_PERSISTENCE_UNIT_NAME_GOES_HERE]">
        <!--GLOBAL_JNDI_GOES_HERE-->
        <jta-data-source>jdbc/myDS</jta-data-source>
    </persistence-unit>
</persistence>

Si votre serveur d'applications cible ne prend pas en charge JTA (Tomcat), votre persistence.xml ressemble à ceci:

<persistence>
    <persistence-unit name="[REQUIRED_PERSISTENCE_UNIT_NAME_GOES_HERE]">
        <!--GLOBAL_JNDI_GOES_HERE-->
        <non-jta-data-source>jdbc/myDS</non-jta-data-source>
    </persistence-unit>
</persistence>

Si votre source de données n'est pas liée à un JNDI global (par exemple, en dehors d'un conteneur Java EE), vous définissez généralement les propriétés du fournisseur JPA, du pilote, de l'URL, de l'utilisateur et du mot de passe. Mais nom de la propriété dépend du fournisseur JPA. Ainsi, pour Hibernate en tant que fournisseur JPA, votre fichier persistence.xml ressemblera à ceci:

<persistence>
    <persistence-unit name="[REQUIRED_PERSISTENCE_UNIT_NAME_GOES_HERE]">
        <provider>org.hibernate.ejb.HibernatePersistence</provider>
        <class>br.com.persistence.SomeClass</class>
        <properties>
            <property name="hibernate.connection.driver_class" value="org.Apache.derby.jdbc.ClientDriver"/>
            <property name="hibernate.connection.url" value="jdbc:derby://localhost:1527/EmpServDB;create=true"/>
            <property name="hibernate.connection.username" value="APP"/>
            <property name="hibernate.connection.password" value="APP"/>
        </properties>
    </persistence-unit>
</persistence>

Attribut Type de transaction

En général, dans les environnements Java EE, un type de transaction de RESOURCE_LOCAL suppose qu'une source de données non-JTA sera fournie. Dans un environnement Java EE, si cet élément n'est pas spécifié, la valeur par défaut est JTA. Dans un environnement Java SE, si cet élément n'est pas spécifié, une valeur par défaut de RESOURCE_LOCAL peut être utilisée.

  • Pour assurer la portabilité d'une application Java SE, il est nécessaire de répertorier explicitement les classes de persistance gérées incluses dans l'unité de persistance (spécification JPA).

Je dois créer le EntityManager à partir des valeurs spécifiées par l'utilisateur lors de l'exécution

Alors utilisez ceci:

Map addedOrOverridenProperties = new HashMap();

// Let's suppose we are using Hibernate as JPA provider
addedOrOverridenProperties.put("hibernate.show_sql", true);

Persistence.createEntityManagerFactory(<PERSISTENCE_UNIT_NAME_GOES_HERE>, addedOrOverridenProperties);
55
Arthur Ronald

Oui, vous pouvez utiliser aucun fichier xml utilisant spring comme ceci dans une classe @Configuration (ou son équivalent print config xml):

@Bean
public LocalContainerEntityManagerFactoryBean emf(){
    properties.put("javax.persistence.jdbc.driver", dbDriverClassName);
    properties.put("javax.persistence.jdbc.url", dbConnectionURL);
    properties.put("javax.persistence.jdbc.user", dbUser); //if needed

    LocalContainerEntityManagerFactoryBean emf = new LocalContainerEntityManagerFactoryBean();
    emf.setPersistenceProviderClass(org.Eclipse.persistence.jpa.PersistenceProvider.class); //If your using Eclipse or change it to whatever you're using
    emf.setPackagesToScan("com.yourpkg"); //The packages to search for Entities, line required to avoid looking into the persistence.xml
    emf.setPersistenceUnitName(SysConstants.SysConfigPU);
    emf.setJpaPropertyMap(properties);
    emf.setLoadTimeWeaver(new ReflectiveLoadTimeWeaver()); //required unless you know what your doing
    return emf;
}
24
Frank Orellana

J'ai pu créer un EntityManager avec Hibernate et PostgreSQL uniquement à l'aide de code Java (avec une configuration Spring) comme suit:

@Bean
public DataSource dataSource() {
    final PGSimpleDataSource dataSource = new PGSimpleDataSource();

    dataSource.setDatabaseName( "mytestdb" );
    dataSource.setUser( "myuser" );
    dataSource.setPassword("mypass");

    return dataSource;
}

@Bean
public Properties hibernateProperties(){
    final Properties properties = new Properties();

    properties.put( "hibernate.dialect", "org.hibernate.dialect.PostgreSQLDialect" );
    properties.put( "hibernate.connection.driver_class", "org.postgresql.Driver" );
    properties.put( "hibernate.hbm2ddl.auto", "create-drop" );

    return properties;
}

@Bean
public EntityManagerFactory entityManagerFactory( DataSource dataSource, Properties hibernateProperties ){
    final LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
    em.setDataSource( dataSource );
    em.setPackagesToScan( "net.initech.domain" );
    em.setJpaVendorAdapter( new HibernateJpaVendorAdapter() );
    em.setJpaProperties( hibernateProperties );
    em.setPersistenceUnitName( "mytestdomain" );
    em.setPersistenceProviderClass(HibernatePersistenceProvider.class);
    em.afterPropertiesSet();

    return em.getObject();
}

L'appel à LocalContainerEntityManagerFactoryBean.afterPropertiesSet() est essentiel car sinon, l'usine ne sera jamais construite et getObject() retournera null et vous poursuivrez après NullPointerException toute la journée. > :-(

Cela a ensuite fonctionné avec le code suivant:

PageEntry pe = new PageEntry();
pe.setLinkName( "Google" );
pe.setLinkDestination( new URL( "http://www.google.com" ) );

EntityTransaction entTrans = entityManager.getTransaction();
entTrans.begin();
entityManager.persist( pe );
entTrans.commit();

Où mon entité était ceci: 

@Entity
@Table(name = "page_entries")
public class PageEntry {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;

    private String linkName;
    private URL linkDestination;

    // gets & setters omitted
}
16
ArtB

Voici une solution sans Spring . Les constantes sont extraites de org.hibernate.cfg.AvailableSettings

entityManagerFactory = new HibernatePersistenceProvider().createContainerEntityManagerFactory(
            archiverPersistenceUnitInfo(),
            ImmutableMap.<String, Object>builder()
                    .put(JPA_JDBC_DRIVER, JDBC_DRIVER)
                    .put(JPA_JDBC_URL, JDBC_URL)
                    .put(DIALECT, Oracle12cDialect.class)
                    .put(HBM2DDL_AUTO, CREATE)
                    .put(SHOW_SQL, false)
                    .put(QUERY_STARTUP_CHECKING, false)
                    .put(GENERATE_STATISTICS, false)
                    .put(USE_REFLECTION_OPTIMIZER, false)
                    .put(USE_SECOND_LEVEL_CACHE, false)
                    .put(USE_QUERY_CACHE, false)
                    .put(USE_STRUCTURED_CACHE, false)
                    .put(STATEMENT_BATCH_SIZE, 20)
                    .build());

entityManager = entityManagerFactory.createEntityManager();

Et l'infâme PersistenceUnitInfo 

private static PersistenceUnitInfo archiverPersistenceUnitInfo() {
    return new PersistenceUnitInfo() {
        @Override
        public String getPersistenceUnitName() {
            return "ApplicationPersistenceUnit";
        }

        @Override
        public String getPersistenceProviderClassName() {
            return "org.hibernate.jpa.HibernatePersistenceProvider";
        }

        @Override
        public PersistenceUnitTransactionType getTransactionType() {
            return PersistenceUnitTransactionType.RESOURCE_LOCAL;
        }

        @Override
        public DataSource getJtaDataSource() {
            return null;
        }

        @Override
        public DataSource getNonJtaDataSource() {
            return null;
        }

        @Override
        public List<String> getMappingFileNames() {
            return Collections.emptyList();
        }

        @Override
        public List<URL> getJarFileUrls() {
            try {
                return Collections.list(this.getClass()
                                            .getClassLoader()
                                            .getResources(""));
            } catch (IOException e) {
                throw new UncheckedIOException(e);
            }
        }

        @Override
        public URL getPersistenceUnitRootUrl() {
            return null;
        }

        @Override
        public List<String> getManagedClassNames() {
            return Collections.emptyList();
        }

        @Override
        public boolean excludeUnlistedClasses() {
            return false;
        }

        @Override
        public SharedCacheMode getSharedCacheMode() {
            return null;
        }

        @Override
        public ValidationMode getValidationMode() {
            return null;
        }

        @Override
        public Properties getProperties() {
            return new Properties();
        }

        @Override
        public String getPersistenceXMLSchemaVersion() {
            return null;
        }

        @Override
        public ClassLoader getClassLoader() {
            return null;
        }

        @Override
        public void addTransformer(ClassTransformer transformer) {

        }

        @Override
        public ClassLoader getNewTempClassLoader() {
            return null;
        }
    };
}
14
Brice

Avec JPA simple, en supposant que vous ayez une implémentation PersistenceProvider (par exemple, Hibernate), vous pouvez utiliser la méthode PersistenceProvider # createContainerEntityManagerFactory (PersistenceUnitInfo info, map map) pour initialiser EntityManagerFactory sans avoir besoin d'un persistence.xml.

Cependant, il est embêtant de devoir implémenter l'interface PersistenceUnitInfo, il est donc préférable d'utiliser Spring ou Hibernate, qui prennent tous deux en charge l'amorçage de JPA sans fichier persistence.xml:

this.nativeEntityManagerFactory = provider.createContainerEntityManagerFactory(
    this.persistenceUnitInfo, 
    getJpaPropertyMap()
);

PersistenceUnitInfo est implémenté par la classe MutablePersistenceUnitInfo .

Découvrez cet article pour une belle démonstration de la façon dont vous pouvez atteindre cet objectif avec Hibernate.

5
Vlad Mihalcea

DataNucleus JPA que j’utilise utilise aussi une manière de le faire dans sa documentation . Pas besoin de Spring, ni d'implémentation laide de PersistenceUnitInfo.

Il suffit de faire comme suit

import org.datanucleus.metadata.PersistenceUnitMetaData;
import org.datanucleus.api.jpa.JPAEntityManagerFactory;

PersistenceUnitMetaData pumd = new PersistenceUnitMetaData("dynamic-unit", "RESOURCE_LOCAL", null);
pumd.addClassName("mydomain.test.A");
pumd.setExcludeUnlistedClasses();
pumd.addProperty("javax.persistence.jdbc.url", "jdbc:h2:mem:nucleus");
pumd.addProperty("javax.persistence.jdbc.user", "sa");
pumd.addProperty("javax.persistence.jdbc.password", "");
pumd.addProperty("datanucleus.schema.autoCreateAll", "true");

EntityManagerFactory emf = new JPAEntityManagerFactory(pumd, null);
0
Billy Frost