JPA 实体未在 EntityManager 中注册

JPA Entity not registered with EntityManager

我一直在使用 Guice 实现模块化体系结构应用程序,每个应用程序模块都分成单独的 eclipse 项目并拥有自己的 Guice 模块。我在注册不在 JPA 持久性项目中的 JPA 实体时遇到了问题。项目里面的注册没问题,其他项目上的就不行。在单个项目和单个 Guice 模块上实现应用程序时没有问题。

配置似乎没问题,但很可能是我遗漏了什么。 这是我在尝试从数据库中获取实体时遇到的错误:

Caused by: java.lang.IllegalArgumentException: Not an entity: class org.gradle.security.persistence.jpa.entities.impl.SubjectImpl
at org.hibernate.jpa.internal.metamodel.MetamodelImpl.entity(MetamodelImpl.java:203)
at org.hibernate.jpa.criteria.QueryStructure.from(QueryStructure.java:139)
at org.hibernate.jpa.criteria.CriteriaQueryImpl.from(CriteriaQueryImpl.java:173)
at org.gradle.security.pbeingersistence.jpa.dao.impl.SubjectDAOImpl.findByPrincipal(SubjectDAOImpl.java:48)

下面的 SubjectDAOImpl 和最后一行尝试获取实体时的错误,

    public Subject findByPrincipal(String principal, LockModeType lockMode) {
    CriteriaQuery<SubjectImpl> criteria = criteriaQuery(SubjectImpl.class);
    CriteriaBuilder cb = getEM().getCriteriaBuilder();

    Root<SubjectImpl> activation = criteria.from(SubjectImpl.class);
    ....

SubjectImpl 为:

@Entity
@Audited
@Table(name=SubjectImpl.TABLE_NAME, schema=Config.Schemas.DEFAULT)
public class SubjectImpl extends BaseEntityImpl implements Subject {

    public static final String TABLE_NAME = Config.TABLE_PREFIX + "subject";

    @Basic(optional = false)
    @Column(name = "principal", unique = true)
    protected String principal;
    ......
}

Guice模块配置如下:

安全模块:

private static class SecurityModule extends AbstractModule {

    @Override
    protected void configure() {
        bind(Subject.class).to(SubjectImpl.class).asEagerSingleton();
        ...
        bind(SubjectDAO.class).to(SubjectDAOImpl.class).asEagerSingleton();
    }

}

持久化模块:

public class JPAPersistenceModule extends AbstractModule implements ArchetypeModule {
    @Override
    protected void configure() {
        try {
        Properties props = new Properties();
        InputStream is = new FileInputStream(
                this.getClass().getClassLoader().getResource(PersistenceProperties.DEFAULT_PROPERTIES_FILE).getPath());
        props.load(is);
        Names.bindProperties(binder(), props);

        bind(PersistenceProperties.class).asEagerSingleton();
        JpaPersistModule persistModule = new JpaPersistModule(PersistenceProperties.PERSISTENCE_UNIT);
        persistModule.properties(props);
        install(persistModule);
    } catch (IOException e) {
        LOGGER.error("Could not load persistence module: ", e);
        System.exit(-1);
    }
}

和服务器模块:

public class ServerModule extends JerseyServletModule implements ArchetypeModule {
    @Override
    protected void configureServlets() {
        filter("/*").through(PersistFilter.class);
        serve("/rest","/rest/*").with(GuiceContainer.class);
    }
}

Guice 模块按以下顺序安装:JPAPersistenceModule、SecurityModule、ServerModule。 无法解决这个问题,你能帮帮我吗?

在与使用相同架构和类似技术实现项目的朋友交谈后,我发现原因是由于 JPA Hibernate 限制。与许多其他注释不同,JPA 实现的注释只能在实现 Guice 持久化模块的项目上检测到。

此问题的解决方法是使用反射捕获所有带有注释的 类(Reflections 库为您完成此操作)并将其传递给 properties 参数上的 Guice JpaPersistModule。 结果应该与此有些相似:

props.put(org.hibernate.jpa.AvailableSettings.LOADED_CLASSES, Lists.newArrayList(EntityLoader.loadEntities()));

JpaPersistModule persistModule = new JpaPersistModule(PersistenceProperties.PERSISTENCE_UNIT);
persistModule.properties(props);
install(persistModule);