Подтвердить что ты не робот

Программно загружать классы Entity с 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, поэтому не обязательно программно.

4b9b3361

Ответ 1

С помощью 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;
    }
}

Затем я скорректировал свой Spring контекст 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 Entity или MappedSuperclass в пути к классам добавляется в путь к классам. Мне пришлось отображать префикс имени пакета для сканирования, из-за чего com.austinmichael есть вообще. Вы можете зарегистрировать второй ReflectionsPersistenceUnitPostProcessor с другим префиксом имени пакета, если хотите, если ваши сущности не используют общий префикс имени пакета.

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

Ответ 2

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

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

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

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

Ссылки

Ответ 3

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