Reputation: 14003
I get an NPE using NULL
in a fairly simple JPQL query, see stack trace below:
15:25:46,724 ERROR [net.bbstats.framework.cdi.BaseCdiBean] (default task-1) CompetitionProvider.loadEntities() threw RetrieveException: net.bbstats.framework.exception.RetrieveException: java.lang.IllegalArgumentException: Exception [EclipseLink-6168] (Eclipse Persistence Services - 2.7.5.v20191016-ea124dd158): org.eclipse.persistence.exceptions.QueryException
Exception Description: Query failed to prepare, unexpected error occurred: [java.lang.NullPointerException].
Internal Exception: java.lang.NullPointerException
Query: ReportQuery(name="Competition.findDtosBySeason" referenceClass=Group jpql="
SELECT NEW net.bbstats.dto.CompetitionListDto(
gr,
gl.name,
se.startYear,
NULL, <--
SIZE(rd.groups),
sc.level,
scl.code,
scl.name,
tt.code,
tt.ageGroup,
tt.gender,
cm.type,
cm.name,
gc,
CASE WHEN COUNT(pa.roster.id) > 0 THEN TRUE ELSE FALSE END
)
FROM Group gr
LEFT JOIN gr.groupLabel gl
LEFT JOIN gr.participations pa
JOIN gr.round rd
JOIN rd.season se
JOIN rd.subCompetition sc
JOIN sc.subCompetitionLabels scl
JOIN sc.teamType tt
JOIN sc.competition cm
JOIN cm.geoContext gc
WHERE se.startYear = :seasonStartYear
")
at net.bbstats.view.domain.CompetitionProvider.loadEntities(CompetitionProvider.java:32)
at net.bbstats.framework.management.BaseProvider.getEntities(BaseProvider.java:77)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at javax.el.BeanELResolver.getValue(BeanELResolver.java:241)
at com.sun.faces.el.DemuxCompositeELResolver._getValue(DemuxCompositeELResolver.java:180)
at com.sun.faces.el.DemuxCompositeELResolver.getValue(DemuxCompositeELResolver.java:208)
at com.sun.el.parser.AstValue.getValue(AstValue.java:139)
at com.sun.el.parser.AstValue.getValue(AstValue.java:203)
at com.sun.el.ValueExpressionImpl.getValue(ValueExpressionImpl.java:226)
at org.jboss.weld.module.web.el.WeldValueExpression.getValue(WeldValueExpression.java:50)
at org.jboss.weld.module.web.el.WeldValueExpression.getValue(WeldValueExpression.java:50)
at com.sun.faces.facelets.el.TagValueExpression.getValue(TagValueExpression.java:115)
at javax.faces.component.ComponentStateHelper.eval(ComponentStateHelper.java:200)
at javax.faces.component.ComponentStateHelper.eval(ComponentStateHelper.java:187)
at javax.faces.component.UIData.getValue(UIData.java:766)
at org.primefaces.component.api.UIData.getDataModel(UIData.java:824)
at javax.faces.component.UIData.getRowCount(UIData.java:371)
at org.primefaces.component.datatable.DataTableRenderer.encodeTbody(DataTableRenderer.java:1187)
at org.primefaces.component.datatable.DataTableRenderer.encodeTbody(DataTableRenderer.java:1166)
at org.primefaces.component.datatable.DataTableRenderer.encodeRegularTable(DataTableRenderer.java:452)
at org.primefaces.component.datatable.DataTableRenderer.encodeMarkup(DataTableRenderer.java:383)
at org.primefaces.component.datatable.DataTableRenderer.encodeEnd(DataTableRenderer.java:96)
at javax.faces.component.UIComponentBase.encodeEnd(UIComponentBase.java:949)
at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1912)
at javax.faces.render.Renderer.encodeChildren(Renderer.java:176)
at javax.faces.component.UIComponentBase.encodeChildren(UIComponentBase.java:918)
at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1905)
at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1908)
at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1908)
at com.sun.faces.application.view.FaceletViewHandlingStrategy.renderView(FaceletViewHandlingStrategy.java:491)
at com.sun.faces.application.view.MultiViewHandler.renderView(MultiViewHandler.java:194)
at javax.faces.application.ViewHandlerWrapper.renderView(ViewHandlerWrapper.java:151)
at javax.faces.application.ViewHandlerWrapper.renderView(ViewHandlerWrapper.java:151)
at javax.faces.application.ViewHandlerWrapper.renderView(ViewHandlerWrapper.java:151)
at org.omnifaces.viewhandler.OmniViewHandler.renderView(OmniViewHandler.java:121)
at com.sun.faces.lifecycle.RenderResponsePhase.execute(RenderResponsePhase.java:126)
at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:100)
at com.sun.faces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:223)
at javax.faces.webapp.FacesServlet.service(FacesServlet.java:671)
at io.undertow.servlet.handlers.ServletHandler.handleRequest(ServletHandler.java:74)
at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:129)
at io.opentracing.contrib.jaxrs2.server.SpanFinishingFilter.doFilter(SpanFinishingFilter.java:55)
at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61)
at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131)
at io.undertow.servlet.handlers.FilterHandler.handleRequest(FilterHandler.java:84)
at io.undertow.servlet.handlers.security.ServletSecurityRoleHandler.handleRequest(ServletSecurityRoleHandler.java:62)
at io.undertow.servlet.handlers.ServletChain$1.handleRequest(ServletChain.java:68)
at io.undertow.servlet.handlers.ServletDispatchingHandler.handleRequest(ServletDispatchingHandler.java:36)
at org.wildfly.extension.undertow.security.SecurityContextAssociationHandler.handleRequest(SecurityContextAssociationHandler.java:78)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at io.undertow.servlet.handlers.security.SSLInformationAssociationHandler.handleRequest(SSLInformationAssociationHandler.java:132)
at io.undertow.servlet.handlers.security.ServletAuthenticationCallHandler.handleRequest(ServletAuthenticationCallHandler.java:57)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at io.undertow.security.handlers.AbstractConfidentialityHandler.handleRequest(AbstractConfidentialityHandler.java:46)
at io.undertow.servlet.handlers.security.ServletConfidentialityConstraintHandler.handleRequest(ServletConfidentialityConstraintHandler.java:64)
at io.undertow.security.handlers.AuthenticationMechanismsHandler.handleRequest(AuthenticationMechanismsHandler.java:60)
at io.undertow.servlet.handlers.security.CachedAuthenticatedSessionHandler.handleRequest(CachedAuthenticatedSessionHandler.java:77)
at io.undertow.security.handlers.NotificationReceiverHandler.handleRequest(NotificationReceiverHandler.java:50)
at io.undertow.security.handlers.AbstractSecurityContextAssociationHandler.handleRequest(AbstractSecurityContextAssociationHandler.java:43)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at org.wildfly.extension.undertow.security.jacc.JACCContextIdHandler.handleRequest(JACCContextIdHandler.java:61)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at org.wildfly.extension.undertow.deployment.GlobalRequestControllerHandler.handleRequest(GlobalRequestControllerHandler.java:68)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest(ServletInitialHandler.java:292)
at io.undertow.servlet.handlers.ServletInitialHandler.access$100(ServletInitialHandler.java:81)
at io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:138)
at io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:135)
at io.undertow.servlet.core.ServletRequestContextThreadSetupAction$1.call(ServletRequestContextThreadSetupAction.java:48)
at io.undertow.servlet.core.ContextClassLoaderSetupAction$1.call(ContextClassLoaderSetupAction.java:43)
at org.wildfly.extension.undertow.security.SecurityContextThreadSetupAction.lambda$create$0(SecurityContextThreadSetupAction.java:105)
at org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1502)
at org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1502)
at org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1502)
at org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1502)
at org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1502)
at io.undertow.servlet.handlers.ServletInitialHandler.dispatchRequest(ServletInitialHandler.java:272)
at io.undertow.servlet.handlers.ServletInitialHandler.access$000(ServletInitialHandler.java:81)
at io.undertow.servlet.handlers.ServletInitialHandler$1.handleRequest(ServletInitialHandler.java:104)
at io.undertow.server.Connectors.executeRootHandler(Connectors.java:360)
at io.undertow.server.HttpServerExchange$1.run(HttpServerExchange.java:830)
at org.jboss.threads.ContextClassLoaderSavingRunnable.run(ContextClassLoaderSavingRunnable.java:35)
at org.jboss.threads.EnhancedQueueExecutor.safeRun(EnhancedQueueExecutor.java:1985)
at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.doRunTask(EnhancedQueueExecutor.java:1487)
at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1378)
at java.lang.Thread.run(Thread.java:748)
Replacing the NULL
with the actual identifier/value gets rids of the NPE.
EDIT:
2nd example:
Caused by: Exception [EclipseLink-6168] (Eclipse Persistence Services - 2.7.5.v20191016-ea124dd158): org.eclipse.persistence.exceptions.QueryException
Exception Description: Query failed to prepare, unexpected error occurred: [java.lang.NullPointerException].
Internal Exception: java.lang.NullPointerException
Query: ReportQuery(name="Competition.findDtosBySeason" referenceClass=Group jpql="
SELECT NEW net.bbstats.dto.TestDto(
NULL
)
FROM Group gr
")
at org.eclipse.persistence.exceptions.QueryException.prepareFailed(QueryException.java:1598)
at org.eclipse.persistence.queries.DatabaseQuery.checkPrepare(DatabaseQuery.java:692)
at org.eclipse.persistence.queries.ObjectLevelReadQuery.checkPrepare(ObjectLevelReadQuery.java:968)
at org.eclipse.persistence.queries.DatabaseQuery.checkPrepare(DatabaseQuery.java:622)
at org.eclipse.persistence.internal.jpa.QueryImpl.getDatabaseQueryInternal(QueryImpl.java:346)
... 96 more
Caused by: java.lang.NullPointerException
at org.eclipse.persistence.queries.ConstructorReportItem.initialize(ConstructorReportItem.java:187)
at org.eclipse.persistence.queries.ReportQuery.prepare(ReportQuery.java:1105)
at org.eclipse.persistence.queries.DatabaseQuery.checkPrepare(DatabaseQuery.java:673)
... 99 more
DTO:
import java.io.Serializable;
public class TestDto implements Serializable
{
private static final long serialVersionUID = 1L;
public TestDto( String test )
{
}
}
EDIT #2:
Caused by: Exception [EclipseLink-6168] (Eclipse Persistence Services - 2.5.2.v20140319-9ad6abd): org.eclipse.persistence.exceptions.QueryException
Exception Description: Query failed to prepare, unexpected error occurred: [java.lang.NullPointerException].
Internal Exception: java.lang.NullPointerException
Query: ReportQuery(name="Competition.findDtosBySeason" referenceClass=Group jpql="
SELECT NEW net.bbstats.dto.TestDto(
NULL
)
FROM Group gr
")
at org.eclipse.persistence.exceptions.QueryException.prepareFailed(QueryException.java:1590)
at org.eclipse.persistence.queries.DatabaseQuery.checkPrepare(DatabaseQuery.java:680)
at org.eclipse.persistence.queries.ObjectLevelReadQuery.checkPrepare(ObjectLevelReadQuery.java:901)
at org.eclipse.persistence.queries.DatabaseQuery.checkPrepare(DatabaseQuery.java:613)
at org.eclipse.persistence.internal.jpa.QueryImpl.getDatabaseQueryInternal(QueryImpl.java:341)
at org.eclipse.persistence.internal.jpa.EntityManagerImpl.createNamedQuery(EntityManagerImpl.java:1124)
at org.eclipse.persistence.internal.jpa.EntityManagerImpl.createNamedQuery(EntityManagerImpl.java:1144)
at org.jboss.as.jpa.container.AbstractEntityManager.createNamedQuery(AbstractEntityManager.java:99)
at net.bbstats.framework.service.Repository.findByNamedQuery(Repository.java:173)
at net.bbstats.framework.service.Repository.findByNamedQuery(Repository.java:166)
at net.bbstats.framework.service.Repository.findByNamedQuery(Repository.java:159)
at net.bbstats.framework.service.Repository.findByNamedQuery(Repository.java:140)
at net.bbstats.view.domain.CompetitionProvider.loadEntities(CompetitionProvider.java:28)
... 88 more
Caused by: java.lang.NullPointerException
at org.eclipse.persistence.queries.ConstructorReportItem.initialize(ConstructorReportItem.java:167)
at org.eclipse.persistence.queries.ReportQuery.prepare(ReportQuery.java:1059)
at org.eclipse.persistence.queries.DatabaseQuery.checkPrepare(DatabaseQuery.java:661)
... 99 more
QUESTION:
Is this a bug?
Using EclipseLink 2.7.5
EDIT #2: EclipseLink version 2.5.2 fails as well.
Upvotes: 0
Views: 1164
Reputation: 22514
Mikko Maunu is right in his answer, the grammar does not allow using NULL
literals except in IS NULL
, IS NOT NULL
or as an assigned value in a UPDATE
statement, so it is better not to depend on your particular JPA provider allowing that in some circumstances.
But disallowing NULL
does not mean that you cannot generate a null value of the correct type and avoid implementing multiple constructors as he suggests (when you have multiple constructors with huge argument lists it can be hard to tell which constructor is called for a particular query)
You can use:
NULLIF(<literal>, <literal>)
where <literal>
is an arbitrary (non-null) literal of the desired type. <literal>
will fix the type of the NULLIF
expression to the type you desire, so that your JPA provider can find the matching constructor via reflection.
So, in your test query the following should work:
SELECT NEW net.bbstats.dto.TestDto(
NULLIF('dummy_string', 'dummy_string')
)
FROM Group gr
In your actual query, modify the literal value according to the typed null you want to generate. For example, if you want a number you could use NULLIF(0, 0)
.
Similarly, you should be able to use a more general CASE
expression, but NULLIF
is in my opinion shorter and less confusing. Use a comment to document this workaround, anyway.
Upvotes: 0
Reputation: 42114
It is not a bug. According BNF (for example JPA 2.1 Specification page 210 - 215) sole usage of NULL
(as an addition to IS [NOT] NULL
) is in new_value, which is then used only in update statements.
new_value ::= scalar_expression | simple_entity_expression |NULL
Without this limitation it would be unclear which constructor to call in case of multiple constructors with same number of parameters.
Easiest workaround is to introduce new constructor without this value.
Upvotes: 2