设置Query.setMaxResults()时触发NullPointerException的解决方法
问题
我用Java实现了EntityA的分页查询,代码如下:
public List<EntityA> getAllEntityAByAAndDPaginated( Collection<Long> a, Collection<Long> d, int numberOfResults, int page ) { TypedQuery<EntityA> q = entityManager.createNamedQuery(EntityA.GET_BY_A_AND_D, EntityA.class); q.setParameter(A, a); q.setParameter(D, d); q.setMaxResults((page + 1) * numberOfResults * d.size()); // 去掉这句就能正常运行! return a != null && !a.isEmpty() && d != null && !d.isEmpty() ? q.getResultList() : new ArrayList<>(); }
为优化查询性能,我设置了(page + 1) * numberOfResults * d.size()作为最大返回结果数,但执行时触发了NullPointerException:
java.lang.NullPointerException at java.base/java.util.ArrayList.<init>(ArrayList.java:179) at org.eclipse.persistence.mappings.ForeignReferenceMapping.prepareNestedJoinQueryClone(ForeignReferenceMapping.java:2455) at org.eclipse.persistence.mappings.OneToOneMapping.valueFromRowInternalWithJoin(OneToOneMapping.java:1814) at org.eclipse.persistence.mappings.ForeignReferenceMapping.valueFromRow(ForeignReferenceMapping.java:2177) at org.eclipse.persistence.mappings.ForeignReferenceMapping.buildCloneFromRow(ForeignReferenceMapping.java:341) at org.eclipse.persistence.internal.descriptors.ObjectBuilder.buildAttributesIntoWorkingCopyClone(ObjectBuilder.java:2007) at org.eclipse.persistence.internal.descriptors.ObjectBuilder.buildWorkingCopyCloneFromRow(ObjectBuilder.java:2260) at org.eclipse.persistence.internal.descriptors.ObjectBuilder.buildObjectInUnitOfWork(ObjectBuilder.java:858) at org.eclipse.persistence.internal.descriptors.ObjectBuilder.buildObject(ObjectBuilder.java:745) at org.eclipse.persistence.internal.descriptors.ObjectBuilder.buildObject(ObjectBuilder.java:699) at ...
异常栈显示程序尝试向结果列表添加null值,移除q.setMaxResults(...)语句后代码可正常运行,且EntityA对应的数据库中无空值,请问该如何修复此问题?
修复方案
修正分页逻辑
当前setMaxResults的计算逻辑完全错误:分页的核心是用setFirstResult指定起始位置,setMaxResults指定单页数量,不需要乘以d.size()。正确的分页写法如下:int firstResult = page * numberOfResults; q.setFirstResult(firstResult); q.setMaxResults(numberOfResults);原逻辑会无意义放大查询结果数,触发EclipseLink处理关联映射时的边界异常。
排查关联映射配置
异常栈指向OneToOne映射的处理,说明问题出在EntityA的关联对象加载环节:- 检查命名查询
EntityA.GET_BY_A_AND_D是否使用左连接(LEFT JOIN)加载关联对象,若关联对象必须存在,改成内连接(INNER JOIN)可避免关联对象为null的情况; - 若必须保留左连接,给实体类的OneToOne映射添加
optional=false配置,或确保数据库关联字段有非空约束,强制ORM加载非空关联对象。
- 检查命名查询
提前校验参数
原代码中setMaxResults的调用在参数校验之前,若d为null会直接触发NPE。把参数校验逻辑前置:public List<EntityA> getAllEntityAByAAndDPaginated( Collection<Long> a, Collection<Long> d, int numberOfResults, int page ) { if (a == null || a.isEmpty() || d == null || d.isEmpty()) { return new ArrayList<>(); } TypedQuery<EntityA> q = entityManager.createNamedQuery(EntityA.GET_BY_A_AND_D, EntityA.class); q.setParameter(A, a); q.setParameter(D, d); int firstResult = page * numberOfResults; q.setFirstResult(firstResult); q.setMaxResults(numberOfResults); return q.getResultList(); }升级EclipseLink版本
这个NPE可能是特定版本EclipseLink的已知bug,在设置setMaxResults并处理关联映射时触发。升级到最新稳定版可修复这类兼容性问题。
内容的提问来源于stack exchange,提问作者ATW
相关产品推荐
相关产品推荐

