Kawu
Kawu

Reputation: 14003

NullPointerException when using NULL in a constructor expression using EclipseLink

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

Answers (2)

gpeche
gpeche

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

Mikko Maunu
Mikko Maunu

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

Related Questions