java - 带有规范/谓词的JPA findAll上的NPE

标签 java hibernate jpa predicate specifications

我有以下规范,应该检查MagazinesFile是否在Magazines下的Subscription列表中:

public static Specification<File> getContainingMagazines(final long subscriptionId){
    return new Specification<File>() {
        @Override
        public Predicate toPredicate(Root<File> root, CriteriaQuery<?> query, CriteriaBuilder cb) {

        Subquery<Subscription> subscriptionSubquery = query.subquery(Subscription.class);
        Root<Subscription> subscriptionRoot = subscriptionSubquery.from(Subscription.class);
        ListJoin<Subscription, Magazine> subscriptionMagazineJoin = subscriptionRoot.join(Subscription_.magazines);

        Path<Long> subscriptionIdPath = subscriptionRoot.get(Subscription_.id);

        subscriptionSubquery.
                select(subscriptionRoot).
                where(cb.equal(subscriptionIdPath, subscriptionId));

        ListJoin<File, Magazine> magazinesJoin = root.join(File_.magazines);

        return cb.and(magazinesJoin.get(Magazine_.id).in(subscriptionMagazineJoin.get(Magazine_.id)));
        }
    };
}

在我的服务中,我正在这样做:
public int findFilesWithSubscription(long subscriptionId) {
        List<File> fileList = fileRepository.findAll(FileSpecs.getContainingMagazines(subscriptionId));
        return fileList.size();
    }

涉及的实体如下:
@Entity
@Table(name = "nim_file")
public class File

@ManyToMany(fetch = FetchType.LAZY)
@JoinTable(
        name = "nim_file_magazines",
        joinColumns = @JoinColumn(name = "file_id"),
        inverseJoinColumns = @JoinColumn(name = "magazine_id")
)
private List<Magazine> magazines;


@Entity
@Table(name = "nim_subscription")
public class Subscription

@ManyToMany(fetch = FetchType.EAGER)
@JoinTable(name = "nim_subscription_magazines",
        joinColumns = @JoinColumn(name = "subscription_id"),
        inverseJoinColumns = @JoinColumn(name = "magazine_id")
)
private List<Magazine> magazines;

最后
@Entity
@Table(name = "nim_magazine")
public class Magazine

最后一个几乎是一个查找表。

现在,我正在使用DWR进行测试,因为我找不到快速测试的更好方法,并且即使hibernate具有setShowSql(true),到目前为止也没有堆栈跟踪或sql显示。我只会收到此消息:
2300777 [http-bio-9090-exec-4] WARN  o.d.dwrp.BaseCallMarshaller - --Erroring: batchId[2] message[java.lang.NullPointerException] 

所以我的问题是:
  • 我在做什么错?
  • 如何比dwr更好地测试/调试规范和/或谓词,以便获得堆栈跟踪等信息?


  • 编辑

    经过一些迁移到Junit测试类后,我获得了以下堆栈跟踪:
    java.lang.NullPointerException
    at org.hibernate.hql.internal.ast.tree.InLogicOperatorNode.isNodeAcceptable(InLogicOperatorNode.java:99)
    at org.hibernate.hql.internal.ast.tree.InLogicOperatorNode.initialize(InLogicOperatorNode.java:79)
    at org.hibernate.hql.internal.ast.HqlSqlWalker.prepareLogicOperator(HqlSqlWalker.java:1224)
    at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.comparisonExpr(HqlSqlBaseWalker.java:4242)
    at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.logicalExpr(HqlSqlBaseWalker.java:1947)
    at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.whereClause(HqlSqlBaseWalker.java:794)
    at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.query(HqlSqlBaseWalker.java:595)
    at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.selectStatement(HqlSqlBaseWalker.java:299)
    at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.statement(HqlSqlBaseWalker.java:247)
    at org.hibernate.hql.internal.ast.QueryTranslatorImpl.analyze(QueryTranslatorImpl.java:248)
    at org.hibernate.hql.internal.ast.QueryTranslatorImpl.doCompile(QueryTranslatorImpl.java:183)
    at org.hibernate.hql.internal.ast.QueryTranslatorImpl.compile(QueryTranslatorImpl.java:136)
    at org.hibernate.engine.query.spi.HQLQueryPlan.<init>(HQLQueryPlan.java:105)
    at org.hibernate.engine.query.spi.HQLQueryPlan.<init>(HQLQueryPlan.java:80)
    at org.hibernate.engine.query.spi.QueryPlanCache.getHQLQueryPlan(QueryPlanCache.java:168)
    at org.hibernate.internal.AbstractSessionImpl.getHQLQueryPlan(AbstractSessionImpl.java:219)
    at org.hibernate.internal.AbstractSessionImpl.createQuery(AbstractSessionImpl.java:197)
    at org.hibernate.internal.SessionImpl.createQuery(SessionImpl.java:1736)
    at org.hibernate.ejb.AbstractEntityManagerImpl.createQuery(AbstractEntityManagerImpl.java:452)
    at org.hibernate.ejb.criteria.CriteriaQueryCompiler.compile(CriteriaQueryCompiler.java:221)
    at org.hibernate.ejb.AbstractEntityManagerImpl.createQuery(AbstractEntityManagerImpl.java:587)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:289)
    at com.sun.proxy.$Proxy109.createQuery(Unknown Source)
    at org.springframework.data.jpa.repository.support.SimpleJpaRepository.getQuery(SimpleJpaRepository.java:491)
    at org.springframework.data.jpa.repository.support.SimpleJpaRepository.findAll(SimpleJpaRepository.java:342)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.executeMethodOn(RepositoryFactorySupport.java:405)
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:390)
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:344)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
    at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:98)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:266)
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:95)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
    at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:136)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
    at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodIntercceptor.invoke(CrudMethodMetadataPostProcessor.java:111)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
    at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:207)
    at com.sun.proxy.$Proxy153.findAll(Unknown Source)
    at test.nimchip.repository.FileRepositoryTest.testVictimizationFetch(FileRepositoryTest.java:118)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:72)
    at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:81)
    at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:216)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:82)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
    at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:60)
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:67)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:162)
    at org.junit.runners.Suite.runChild(Suite.java:127)
    at org.junit.runners.Suite.runChild(Suite.java:26)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:160)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:74)
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:211)
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:67)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:134)
    

    最佳答案

    我总是发现使用Criteria API和it may generate horrible SQL statements even for trivial joins非常麻烦。

    请尝试以下HQL查询:

    select f
    from File f
    inner join f.magazines file_magazine
    where exists (
        select s 
        from Subscription s
        inner join s.magazines subscr_magazine
        where s.id = :subscription_id and subscr_magazine.id = file_magazine.id
    )
    

    虽然您也可以检查any/some/member of,但是这些表达式可能导致非常复杂的SQL查询。尝试建议的子选择,然后看看如何进行。

    我不确定这是否可行,但您也可以使用带有额外的join子句:
    select f
    from File f
    inner join f.magazines file_magazine
    where exists (
        select s 
        from Subscription s
        inner join s.magazines subscr_magazine with subscr_magazine.id = file_magazine.id
        where s.id = :subscription_id
    )
    

    为了记录所有SQL查询以及参数,您可以在应用程序数据源的前面set up a datasurce-proxy

    关于java - 带有规范/谓词的JPA findAll上的NPE,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26680604/

    相关文章:

    java - Spring-data-neo4j + @Query 抛出 PropertyReferenceException

    java - 在 Playstore 上为您的 Android 应用程序提供升级时,是否可以对本地保存的数据运行代码/任务?

    java - Android parse.com 无法上传文件

    java - 从数据库同步实体管理器

    java - 我可以编写一个 hibernate 实体吗?

    java - 有没有办法用 Hibernate 迁移 JPA 表名?

    java - 转发 : Issues porting application from tomcat 5. 0.28 到 tomcat 7.0.57

    来自简单 SQL 查询的 Hibernate 条件查询(带有嵌套子查询)

    java - @PersistenceUnit 注释不起作用

    java - JPA存储库读取、删除和保存具有旧ID的对象