Программная загрузка классов сущностей с помощью JPA 2.0?

С Hibernate вы можете загружать свои Entity классы как:

sessionFactory = new AnnotationConfiguration()
                    .addPackage("test.animals")
                    .addAnnotatedClass(Flight.class)
                    .addAnnotatedClass(Sky.class)
                    .addAnnotatedClass(Person.class)
                    .addAnnotatedClass(Dog.class);

Есть ли способ сделать то же самое - программно загрузить ваши классы Entity - совместимым с JPA 2.0 способом?

Причина этого вопроса в том, что я хотел бы динамически загружать мои Entity классы, не обязательно программно.


person wen    schedule 15.05.2010    source источник


Ответы (3)


С помощью Spring я сделал это совместимым с JPA способом.

Мой файл "persistence.xml" выглядит пустым, в элементе <persistence-unit> нет перечисленных сущностей.

Затем я написал класс, который реализовал PersistenceUnitPostProcessor следующим образом:

import java.util.Set;
import javax.persistence.Entity;
import javax.persistence.MappedSuperclass;
import org.reflections.Reflections;
import org.reflections.scanners.TypeAnnotationsScanner;
import org.springframework.orm.jpa.persistenceunit.MutablePersistenceUnitInfo;
import org.springframework.orm.jpa.persistenceunit.PersistenceUnitPostProcessor;

public class ReflectionsPersistenceUnitPostProcessor implements PersistenceUnitPostProcessor {

    private String reflectionsRoot;
    private Logger log = LoggerFactory.getLogger(ReflectionsPersistenceUnitPostProcessor.class);

    @Override
    public void postProcessPersistenceUnitInfo(MutablePersistenceUnitInfo pui) {
            Reflections r = new Reflections(this.reflectionsRoot, new TypeAnnotationsScanner());
            Set<String> entityClasses = r.getStore().getTypesAnnotatedWith(Entity.class.getName());
            Set<String> mappedSuperClasses = r.getStore().getTypesAnnotatedWith(MappedSuperclass.class.getName());

            for (String clzz : mappedSuperClasses)
            {
                    pui.addManagedClassName(clzz);
            }


            for (String clzz : entityClasses)
            {
                    pui.addManagedClassName(clzz);
            }

    }

    public String getReflectionsRoot() {
            return reflectionsRoot;
    }

    public void setReflectionsRoot(String reflectionsRoot) {
            this.reflectionsRoot = reflectionsRoot;
    }
}

Затем я настроил свой весенний контекст xml следующим образом:

<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
            <property name="dataSource" ref="dataSource" />
            <property name="jpaVendorAdapter">
                    <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
                            <property name="showSql" value="false" />
                            <property name="generateDdl" value="true" />
                            <property name="databasePlatform" value="org.hibernate.dialect.MySQL5InnoDBDialect" />
                    </bean>
            </property>
            <property name="persistenceUnitName" value="GenericPersistenceUnit"/>
            <property name="persistenceXmlLocation" value="classpath:META-INF/persistence.xml"/>
            <property name="persistenceUnitPostProcessors">
                    <list>
                            <bean class="com.austinmichael.core.repository.ReflectionsPersistenceUnitPostProcessor">
                                    <property name="reflectionsRoot" value="com.austinmichael"/>
                            </bean>
                    </list>
            </property>
    </bean>

Обратите внимание на регистрацию ReflectionsPersistenceUnitPostProcessor в настройке persistenceUnitPostProcessors.

Вот и все. Каждый класс с аннотацией JPA или MappedSuperclass в пути к классам добавляется в путь к классам. Я должен был дать размышлениям префикс имени пакета для сканирования, поэтому com.austinmichael там вообще есть. Вы можете зарегистрировать второй ReflectionsPersistenceUnitPostProcessor с другим префиксом имени пакета, если хотите, если ваши объекты не имеют общего префикса имени пакета.

Но теперь это агностик JPAVendor.

person Carl Horton    schedule 27.12.2011
comment
Можно ли использовать этот метод для программной установки имени базы данных и других свойств в persistence.xml? - person Jared Hooper; 22.10.2015

Есть ли способ сделать то же самое - программно загрузить ваши классы Entity - совместимым с JPA 2.0 способом?

Нет, это не поддерживается JPA, поэтому вам придется делать это в зависимости от поставщика. Джеймс Сазерленд описал процесс для EclipseLink в этой теме, например это:

Вы можете получить доступ к EclipseLink ServerSession из EntityManagerFactoryImpl (getServerSession()) и использовать его 'addDescriptor(ClassDescriptor) или addDescriptors() API для добавления EclipseLink ClassDescriptor. Вам нужно будет создать ClassDescriptor объекты метаданных напрямую (или использовать Mapping Workbench для их создания), поскольку загрузка из аннотаций JPA или orm.xml будет более сложной.

Также просмотрите эту более свежую ветку для получения дополнительных примеров кода. (API выглядит немного многословным).

использованная литература

person Pascal Thivent    schedule 23.05.2010
comment
Разве это не уничтожает всю цель JPA? Это дает вам большой контроль, но за счет того, что вам приходится делать абсолютно все вручную. Или я неправильно это понимаю? - person wen; 23.05.2010
comment
@Dennetik Как-то да. Но я не думаю, что в EclipseLink есть что-то столь же лаконичное, как Hibernate. И я даже не уверен, куда девать шаг плетения, если вам нужен ленивый ToOne. Другими словами, я не совсем уверен в том, что вы хотите сделать, но у меня такое чувство, что JPA может не подходить. - person Pascal Thivent; 23.05.2010
comment
Есть что-нибудь для Hibernate? - person Ondra Žižka; 17.06.2011

Я не думаю, что есть такая возможность - JPA поддерживает сканирование пути к классам на предмет сущностей или явное перечисление классов сущностей в файле persistence.xml. Поскольку вы используете спящий режим в качестве поставщика сохраняемости, вы всегда можете прибегнуть к коду спящего режима. Взгляните на классы HibernateEntityManager и HibernateEntityManagerFactory. Вы можете преобразовать в них фабрики менеджеров сущностей и менеджеров сущностей и выполнять обычные функции гибернации.

person Bozhidar Batsov    schedule 15.05.2010
comment
Честно говоря, я использую EclipseLink-2.0.2. Я рассмотрю сканирование путей к классам, так как это звучит многообещающе. Вы хоть представляете, будет ли это работать с модификациями байт-кода (перед созданием EntityManager) с такими библиотеками, как Javassist? - person wen; 16.05.2010