NPE on jpa findAll with BOM / predicate
I have the following spec that should check if Magazines
of File
is listed Magazines
under 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)));
}
};
}
And in my service I do this:
public int findFilesWithSubscription(long subscriptionId) {
List<File> fileList = fileRepository.findAll(FileSpecs.getContainingMagazines(subscriptionId));
return fileList.size();
}
The participating objects are as follows:
@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;
and
@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;
finally,
@Entity
@Table(name = "nim_magazine")
public class Magazine
This last table is quite important.
Now I am testing using DWR because I couldn't find a better way to test quickly and there is still no stack trace or sql even though hibernate does setShowSql(true)
. I am getting this message:
2300777 [http-bio-9090-exec-4] WARN o.d.dwrp.BaseCallMarshaller - --Erroring: batchId[2] message[java.lang.NullPointerException]
So my questions are:
- What am I doing wrong?
- How can I check / debug specs and / or predicates better than dwr so that I can get stack traces etc.
Edit
After jumping to the Junit test class for some time, I got the following stack trace:
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)
source to share
I have always found the criteria API to be very cumbersome and can generate terrible SQL queries even for trivial joins .
Try this HQL query:
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
)
While you can also check any / some / member , these expressions can lead to very complex SQL queries. Try the suggested sub-selection and see how it goes.
I'm not sure if this works, but you can also use the suggestion with an additional connection:
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
)
For registering SQL queries and parameters, you can set up datasurce-proxy in front of your application datasource .
source to share