Программно загружать классы сущностей с помощью JPA 2.0? - PullRequest
22 голосов
/ 15 мая 2010

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

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

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

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

Ответы [ 3 ]

27 голосов
/ 28 декабря 2011

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

5 голосов
/ 23 мая 2010

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

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

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

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

Ссылки

3 голосов
/ 15 мая 2010

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

...