Initialisation de JPA par programme en Java

Démarrer JPA par programme en Java

1. Vue d'ensemble

La plupart des applications pilotées par JPA utilisent fortement le fichier“persistence.xml” pour obtenir une implémentation JPA, commeHibernate ouOpenJPA.

Notre approche iciprovides a centralized mechanism for configuring one or more persistence units able lespersistence contexts associés.

Et bien que cette approche ne soit pas intrinsèquement erronée, elle ne convient pas aux cas d’utilisation où il est nécessaire de tester isolément les composants d’application qui utilisent différentes unités de persistance.

Du bon côté,it’s possible to bootstrap a JPA implementation without resorting to the “persistence.xml” file at all, by just using plain Java.

Dans ce didacticiel, nous allons voir comment y parvenir avec Hibernate.

2. Implémentation de l'interfacePersistenceUnitInfo

Dans une configuration JPA «xml» typique, l’implémentation JPA prend automatiquement en charge l’implémentation desPersistenceUnitInfo interface.

Using all the data gathered by parsing the “persistence.xml” file, tle fournisseur de persistance utilise cette implémentation pour créer une fabrique de gestionnaires d'entités. De cette usine, nous pouvons obtenir un gestionnaire d'entités.

Since we won’t rely on the “persistence.xml” file, the first thing that we need to do is to provide our own PersistenceUnitInfo implementation. Nous utiliserons Hibernate pour notre fournisseur de persistance:

public class HibernatePersistenceUnitInfo implements PersistenceUnitInfo {

    public static String JPA_VERSION = "2.1";
    private String persistenceUnitName;
    private PersistenceUnitTransactionType transactionType
      = PersistenceUnitTransactionType.RESOURCE_LOCAL;
    private List managedClassNames;
    private List mappingFileNames = new ArrayList<>();
    private Properties properties;
    private DataSource jtaDataSource;
    private DataSource nonjtaDataSource;
    private List transformers = new ArrayList<>();

    public HibernatePersistenceUnitInfo(
      String persistenceUnitName, List managedClassNames, Properties properties) {
        this.persistenceUnitName = persistenceUnitName;
        this.managedClassNames = managedClassNames;
        this.properties = properties;
    }

    // standard setters / getters
}

En un mot, la classeHibernatePersistenceUnitInfo n'est qu'un simple conteneur de données, qui stocke les paramètres de configuration liés à une unité de persistance spécifique. Cela inclut le nom de l'unité de persistance, les noms des classes d'entités gérées, le type de transaction, les sources de données JTA et non JTA, etc.

3. Création d’une usine Entity Manager avec la classeEntityManagerFactoryBuilderImpl d’Hibernate

Maintenant que nous avons une implémentation personnalisée dePersistenceUnitInfo en place, la dernière chose que nous devons faire est d'obtenir une fabrique de gestionnaire d'entités.

Hibernate makes this process a breeze, with its EntityManagerFactoryBuilderImpl class (a neat implementation of the builder pattern).

Pour fournir un niveau d'abstraction plus élevé, créons une classe qui englobe la fonctionnalité deEntityManagerFactoryBuilderImpl.

Tout d'abord, présentons les méthodes qui prennent en chargecreating an entity manager factory and an entity manager, en utilisant la classeHibernate’s EntityManagerFactoryBuilderImpl et notre classeHibernatePersistenceUnitInfo:

public class JpaEntityManagerFactory {
    private String DB_URL = "jdbc:mysql://databaseurl";
    private String DB_USER_NAME = "username";
    private String DB_PASSWORD = "password";
    private Class[] entityClasses;

    public JpaEntityManagerFactory(Class[] entityClasses) {
        this.entityClasses = entityClasses;
    }

    public EntityManager getEntityManager() {
        return getEntityManagerFactory().createEntityManager();
    }

    protected EntityManagerFactory getEntityManagerFactory() {
        PersistenceUnitInfo persistenceUnitInfo = getPersistenceUnitInfo(
          getClass().getSimpleName());
        Map configuration = new HashMap<>();
        return new EntityManagerFactoryBuilderImpl(
          new PersistenceUnitInfoDescriptor(persistenceUnitInfo), configuration)
          .build();
    }

    protected HibernatePersistenceUnitInfo getPersistenceUnitInfo(String name) {
        return new HibernatePersistenceUnitInfo(name, getEntityClassNames(), getProperties());
    }

    // additional methods
}

Ensuite, jetons un coup d'œil auxmethods that provide the parameters required by EntityManagerFactoryBuilderImpl and HibernatePersistenceUnitInfo.

Ces paramètres incluent les classes d'entités gérées, les noms des classes d'entités, les propriétés de configuration d'Hibernate et un objetMysqlDataSource:

public class JpaEntityManagerFactory {
    //...

    protected List getEntityClassNames() {
        return Arrays.asList(getEntities())
          .stream()
          .map(Class::getName)
          .collect(Collectors.toList());
    }

    protected Properties getProperties() {
        Properties properties = new Properties();
        properties.put("hibernate.dialect", "org.hibernate.dialect.MySQLDialect");
        properties.put("hibernate.id.new_generator_mappings", false);
        properties.put("hibernate.connection.datasource", getMysqlDataSource());
        return properties;
    }

    protected Class[] getEntities() {
        return entityClasses;
    }

    protected DataSource getMysqlDataSource() {
        MysqlDataSource mysqlDataSource = new MysqlDataSource();
        mysqlDataSource.setURL(DB_URL);
        mysqlDataSource.setUser(DB_USER_NAME);
        mysqlDataSource.setPassword(DB_PASSWORD);
        return mysqlDataSource;
    }
}

Par souci de simplicité, nous avons codé en dur les paramètres de connexion à la base de données dans la classeJpaEntityManagerFactory. En production, cependant, nous devrions les stocker dans un fichier de propriétés séparé.

De plus, la méthodegetMysqlDataSource() renvoie un objetMysqlDataSource entièrement initialisé.

Nous avons fait cela simplement pour garder les choses faciles à suivre. Dans une conception plus réaliste et faiblement couplée, nous aurionsinject a DataSource object using EntityManagerFactoryBuilderImpl's withDataSource() method, rather than creating it within the class.

4. Exécution d'opérations CRUD avec un gestionnaire d'entités

Enfin, voyons comment utiliser une instanceJpaEntityManagerFactory pour obtenir un gestionnaire d'entités JPA et effectuer des opérations CRUD. (Notez que nous avons omis la classeUser par souci de concision):

public static void main(String[] args) {
    EntityManager entityManager = getJpaEntityManager();
    User user = entityManager.find(User.class, 1);

    entityManager.getTransaction().begin();
    user.setName("John");
    user.setEmail("[email protected]");
    entityManager.merge(user);
    entityManager.getTransaction().commit();

    entityManager.getTransaction().begin();
    entityManager.persist(new User("Monica", "[email protected]"));
    entityManager.getTransaction().commit();

    // additional CRUD operations
}

private static class EntityManagerHolder {
    private static final EntityManager ENTITY_MANAGER = new JpaEntityManagerFactory(
      new Class[]{User.class})
      .getEntityManager();
}

public static EntityManager getJpaEntityManager() {
    return EntityManagerHolder.ENTITY_MANAGER;
}

5. Conclusion

Dans cet article, nous avons montré comment démarrer par programme un gestionnaire d’entités JPA à l’aide d’une implémentation personnalisée desPersistenceUnitInfo interface and Hibernate’s EntityManagerFactoryBuilderImpl class de JPA, sans avoir à compter sur les “persistence.xml” file. traditionnels

Comme d'habitude, tous les exemples de code présentés dans cet article sont disponiblesover on GitHub.