Blazebit / blaze-persistence

Rich Criteria API for JPA providers
https://persistence.blazebit.com
Apache License 2.0
741 stars 90 forks source link

CriteriaBuilder#function not working after configuration #1942

Closed AlexSischin closed 3 weeks ago

AlexSischin commented 1 month ago

Description

Hi! I'm new to this amazing library and I'm stuck upon an issue. Not sure whether this should be a bug or a question.

I'm trying to integrate blaze persistence in an existing project that uses Criteria API with Spring Specifications like this:

@NonNull
public static Specification<ObjectEntity> parentIdIn(@Nullable Collection<UUID> parentIds) {
    return (root, query, cb) -> {
        if (parentIds == null) {
            return cb.conjunction();
        }

        String parents = parentIds.stream()
                .filter(Objects::nonNull)
                .map(UUID::toString)
                .collect(Collectors.joining(","));
        return root.get("id").in(
                cb.function(
                        "SELECT id FROM get_objects_by_parents",
                        List.class,
                        cb.literal(parents)
                )
        );
    };
}

This function encapsulates some complex JSON processing logic. After I imported blaze-persistence and configured it, this stopped working.

Expected behavior

Legacy Specifications that use CriteriaBuilder#function work.

Actual behavior

The following error occurs:

com.blazebit.persistence.parser.expression.SyntaxErrorException: Could not parse expression '((generatedObjectEntity_0.deletedAt IS NULL) AND (generatedObjectEntity_0.company.id=:generated_param_0)) AND (((((((((((((((((1=1) AND (generatedObjectEntity_0.id IN (SELECT id FROM get_objects_by_parents('a321e18b-25ef-4d21-8d5c-7a413f2291a1')))) AND ((1=1) OR (1=1))) AND (1=1)) AND (1=1)) AND (((1=1) OR (1=1)) OR (1=1))) AND (1=1)) AND (1=1)) AND (1=1)) AND (1=1)) AND (1=1)) AND (1=1)) AND (1=1)) AND (1=1)) AND (1=1)) AND (1=1)) AND (1=1))', line 1:175 no viable alternative at input '(SELECTid'
    at com.blazebit.persistence.parser.expression.AbstractExpressionFactory.createExpression(AbstractExpressionFactory.java:183)
    at com.blazebit.persistence.parser.expression.AbstractExpressionFactory.createBooleanExpression(AbstractExpressionFactory.java:253)
    at com.blazebit.persistence.parser.expression.AbstractCachingExpressionFactory$5.get(AbstractCachingExpressionFactory.java:77)
    at com.blazebit.persistence.parser.expression.AbstractCachingExpressionFactory.getOrDefault(AbstractCachingExpressionFactory.java:158)
    at com.blazebit.persistence.parser.expression.AbstractCachingExpressionFactory.createBooleanExpression(AbstractCachingExpressionFactory.java:146)
    at com.blazebit.persistence.impl.JpqlMacroAwareExpressionFactory.createBooleanExpression(JpqlMacroAwareExpressionFactory.java:145)
    at com.blazebit.persistence.impl.AbstractCommonQueryBuilder.setWhereExpression(AbstractCommonQueryBuilder.java:1524)
    at com.blazebit.persistence.impl.AbstractFullQueryBuilder.setWhereExpression(AbstractFullQueryBuilder.java:90)
    at com.blazebit.persistence.criteria.impl.InternalQuery.renderWhere(InternalQuery.java:660)
    at com.blazebit.persistence.criteria.impl.InternalQuery.render(InternalQuery.java:283)
    at com.blazebit.persistence.criteria.impl.BlazeCriteriaQueryImpl.createCriteriaBuilder(BlazeCriteriaQueryImpl.java:280)
    at com.blazebit.persistence.spring.data.base.repository.AbstractEntityViewAwareRepository.getQuery(AbstractEntityViewAwareRepository.java:565)
    at com.blazebit.persistence.spring.data.base.repository.AbstractEntityViewAwareRepository.getQuery(AbstractEntityViewAwareRepository.java:539)
    at com.blazebit.persistence.spring.data.base.repository.AbstractEntityViewAwareRepository.findAll(AbstractEntityViewAwareRepository.java:515)
    at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
    at java.base/java.lang.reflect.Method.invoke(Method.java:580)
    at org.springframework.data.repository.core.support.RepositoryMethodInvoker$RepositoryFragmentMethodInvoker.lambda$new$0(RepositoryMethodInvoker.java:289)
    at org.springframework.data.repository.core.support.RepositoryMethodInvoker.doInvoke(RepositoryMethodInvoker.java:137)
    at org.springframework.data.repository.core.support.RepositoryMethodInvoker.invoke(RepositoryMethodInvoker.java:121)
    at org.springframework.data.repository.core.support.RepositoryComposition$RepositoryFragments.invoke(RepositoryComposition.java:530)
    at org.springframework.data.repository.core.support.RepositoryComposition.invoke(RepositoryComposition.java:286)
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$ImplementationMethodExecutionInterceptor.invoke(RepositoryFactorySupport.java:640)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.doInvoke(QueryExecutorMethodInterceptor.java:164)
    at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.invoke(QueryExecutorMethodInterceptor.java:139)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:81)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at com.blazebit.persistence.spring.data.repository.EntityViewReplacingMethodInterceptor.invoke(EntityViewReplacingMethodInterceptor.java:51)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:123)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:388)
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:119)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:137)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at com.blazebit.persistence.spring.data.base.repository.EntityViewAwareCrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(EntityViewAwareCrudMethodMetadataPostProcessor.java:142)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:61)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:215)
    at jdk.proxy3/jdk.proxy3.$Proxy287.findAll(Unknown Source)
    at com.nlmk.smdk.backend.app.core.service.object.ObjectService.search(ObjectService.java:414)
    at com.nlmk.smdk.backend.app.core.service.object.ObjectService$$FastClassBySpringCGLIB$$c39a9220.invoke(<generated>)
    at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:793)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:763)
    at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:102)
    at com.nlmk.smdk.backend.commons.util.additional_sort.AdditionalSortAspect.invokeInContext(AdditionalSortAspect.java:50)
    at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
    at java.base/java.lang.reflect.Method.invoke(Method.java:580)
    at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:634)
    at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:624)
    at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:72)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:763)
    at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:123)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:388)
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:119)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:763)
    at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:763)
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:708)
    at com.nlmk.smdk.backend.app.core.service.object.ObjectService$$EnhancerBySpringCGLIB$$2c02e41b.search(<generated>)
    at com.nlmk.smdk.backend.app.core.controller.ObjectController.lambda$search$2(ObjectController.java:195)
    at com.nlmk.smdk.backend.app.core.converter.object.ObjectShortResourceConverter.convertPage(ObjectShortResourceConverter.java:25)
    at com.nlmk.smdk.backend.app.core.converter.object.ObjectShortResourceConverter$$FastClassBySpringCGLIB$$9a0fab6.invoke(<generated>)
    at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:793)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:763)
    at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:123)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:388)
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:119)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:763)
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:708)
    at com.nlmk.smdk.backend.app.core.converter.object.ObjectShortResourceConverter$$EnhancerBySpringCGLIB$$14314395.convertPage(<generated>)
    at com.nlmk.smdk.backend.app.core.controller.ObjectController.search(ObjectController.java:194)
    at com.nlmk.smdk.backend.app.core.controller.ObjectController$$FastClassBySpringCGLIB$$ed978dcd.invoke(<generated>)
    at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:793)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:763)
    at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:89)
    at com.nlmk.smdk.backend.commons.metric.aop.ApiExceptionsAspect.invokeInContext(ApiExceptionsAspect.java:28)
    at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
    at java.base/java.lang.reflect.Method.invoke(Method.java:580)
    at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:634)
    at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:624)
    at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:72)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:175)
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:763)
    at org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor.invoke(MethodSecurityInterceptor.java:61)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:763)
    at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:763)
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:708)
    at com.nlmk.smdk.backend.app.core.controller.ObjectController$$EnhancerBySpringCGLIB$$61f6f73e.search(<generated>)
    at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
    at java.base/java.lang.reflect.Method.invoke(Method.java:580)
    at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205)
    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:150)
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808)
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1072)
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:965)
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
    at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:528)
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:596)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:209)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153)
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:178)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153)
    at org.springframework.web.filter.AbstractRequestLoggingFilter.doFilterInternal(AbstractRequestLoggingFilter.java:289)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:178)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:111)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:178)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:337)
    at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:115)
    at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:81)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
    at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:122)
    at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:116)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
    at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:126)
    at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:81)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
    at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:109)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
    at com.nlmk.smdk.backend.config.filter.JwtRequestFilter.doFilterInternal(JwtRequestFilter.java:37)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
    at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:149)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
    at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
    at org.springframework.web.filter.CorsFilter.doFilterInternal(CorsFilter.java:91)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
    at org.springframework.security.web.header.HeaderWriterFilter.doHeadersAfter(HeaderWriterFilter.java:90)
    at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:75)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
    at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:112)
    at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:82)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
    at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:55)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
    at org.springframework.security.web.session.DisableEncodeUrlFilter.doFilterInternal(DisableEncodeUrlFilter.java:42)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
    at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:221)
    at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:186)
    at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:354)
    at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:267)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:178)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153)
    at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:178)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153)
    at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:178)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153)
    at org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter.doFilterInternal(WebMvcMetricsFilter.java:96)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:178)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153)
    at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:178)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:167)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:90)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:492)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:130)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:93)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
    at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:389)
    at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63)
    at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:926)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1791)
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
    at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191)
    at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.base/java.lang.Thread.run(Thread.java:1583)
Caused by: com.blazebit.persistence.parser.expression.SyntaxErrorException: line 1:175 no viable alternative at input '(SELECTid'
    at com.blazebit.persistence.parser.expression.AbstractExpressionFactory$1.syntaxError(AbstractExpressionFactory.java:58)
    at com.blazebit.persistence.parser.antlr.ProxyErrorListener.syntaxError(ProxyErrorListener.java:41)
    at com.blazebit.persistence.parser.antlr.Parser.notifyErrorListeners(Parser.java:544)
    at com.blazebit.persistence.parser.antlr.DefaultErrorStrategy.reportNoViableAlternative(DefaultErrorStrategy.java:310)
    at com.blazebit.persistence.parser.antlr.DefaultErrorStrategy.reportError(DefaultErrorStrategy.java:136)
    at com.blazebit.persistence.parser.JPQLNextParser.inList(JPQLNextParser.java:9114)
    at com.blazebit.persistence.parser.JPQLNextParser.predicate(JPQLNextParser.java:8829)
    at com.blazebit.persistence.parser.JPQLNextParser.predicate(JPQLNextParser.java:7653)
    at com.blazebit.persistence.parser.JPQLNextParser.predicate(JPQLNextParser.java:8941)
    at com.blazebit.persistence.parser.JPQLNextParser.predicate(JPQLNextParser.java:7653)
    at com.blazebit.persistence.parser.JPQLNextParser.predicate(JPQLNextParser.java:7653)
    at com.blazebit.persistence.parser.JPQLNextParser.predicate(JPQLNextParser.java:7653)
    at com.blazebit.persistence.parser.JPQLNextParser.predicate(JPQLNextParser.java:7653)
    at com.blazebit.persistence.parser.JPQLNextParser.predicate(JPQLNextParser.java:7653)
    at com.blazebit.persistence.parser.JPQLNextParser.predicate(JPQLNextParser.java:7653)
    at com.blazebit.persistence.parser.JPQLNextParser.predicate(JPQLNextParser.java:7653)
    at com.blazebit.persistence.parser.JPQLNextParser.predicate(JPQLNextParser.java:7653)
    at com.blazebit.persistence.parser.JPQLNextParser.predicate(JPQLNextParser.java:7653)
    at com.blazebit.persistence.parser.JPQLNextParser.predicate(JPQLNextParser.java:7653)
    at com.blazebit.persistence.parser.JPQLNextParser.predicate(JPQLNextParser.java:7653)
    at com.blazebit.persistence.parser.JPQLNextParser.predicate(JPQLNextParser.java:7653)
    at com.blazebit.persistence.parser.JPQLNextParser.predicate(JPQLNextParser.java:7653)
    at com.blazebit.persistence.parser.JPQLNextParser.predicate(JPQLNextParser.java:7653)
    at com.blazebit.persistence.parser.JPQLNextParser.predicate(JPQLNextParser.java:7653)
    at com.blazebit.persistence.parser.JPQLNextParser.predicate(JPQLNextParser.java:7653)
    at com.blazebit.persistence.parser.JPQLNextParser.predicate(JPQLNextParser.java:8941)
    at com.blazebit.persistence.parser.JPQLNextParser.parsePredicate(JPQLNextParser.java:821)
    at com.blazebit.persistence.parser.expression.AbstractExpressionFactory$5.invokeRule(AbstractExpressionFactory.java:102)
    at com.blazebit.persistence.parser.expression.AbstractExpressionFactory.createExpression(AbstractExpressionFactory.java:179)
    ... 205 common frames omitted

Steps to reproduce

Imports:

    implementation 'com.blazebit:blaze-persistence-entity-view-api:1.6.12'
    implementation 'com.blazebit:blaze-persistence-entity-view-processor:1.6.12'
    implementation 'com.blazebit:blaze-persistence-integration-entity-view-spring:1.6.12'
    implementation 'com.blazebit:blaze-persistence-integration-spring-data-2.7:1.6.12'
    implementation 'com.blazebit:blaze-persistence-jpa-criteria-api:1.6.12'
    implementation 'com.blazebit:blaze-persistence-integration-hibernate-5.6:1.6.12'
    implementation 'com.blazebit:blaze-persistence-integration-spring-data-webmvc:1.6.12'
    runtimeOnly 'com.blazebit:blaze-persistence-entity-view-impl:1.6.12'
    runtimeOnly 'com.blazebit:blaze-persistence-jpa-criteria-impl:1.6.12'

Config:

@Configuration
public class BlazePersistenceConfig {

    @PersistenceUnit
    private EntityManagerFactory entityManagerFactory;

    @Bean
    @Scope(ConfigurableBeanFactory.SCOPE_SINGLETON)
    @Lazy(false)
    public CriteriaBuilderFactory createCriteriaBuilderFactory() {
        CriteriaBuilderConfiguration config = Criteria.getDefault();
        return config.createCriteriaBuilderFactory(entityManagerFactory);
    }

    @Bean
    @Scope(ConfigurableBeanFactory.SCOPE_SINGLETON)
    @Lazy(false)
    public EntityViewManager createEntityViewManager(
            CriteriaBuilderFactory cbf,
            EntityViewConfiguration entityViewConfiguration
    ) {
        return entityViewConfiguration.createEntityViewManager(cbf);
    }
}

What I've tried

I've tried to create a jpql function:

public class GetObjectsByParentsFunction implements JpqlFunction {
    @Override
    public boolean hasArguments() {
        return true;
    }

    @Override
    public boolean hasParenthesesIfNoArguments() {
        return true;
    }

    @Override
    public Class<?> getReturnType(Class<?> aClass) {
        return List.class;
    }

    @Override
    public void render(FunctionRenderContext context) {
        context.addChunk("SELECT id FROM get_objects_by_parents(");
        context.addArgument(0);
        context.addChunk(")");
    }
}

register it like this:

JpqlFunctionGroup getObjectsByParentsFunction = new JpqlFunctionGroup(
        "GET_OBJECTS_BY_PARENTS",
        new GetObjectsByParentsFunction()
);
config.registerFunction(getObjectsByParentsFunction);

and use it like this:

root.get("id").in(
        cb.function(
                "GET_OBJECTS_BY_PARENTS",
                List.class,
                cb.literal(parents)
        )
);

This doesn't work either. I get another error:

Caused by: java.lang.IllegalArgumentException: No object leaf allowed but model is an object leaf
    at com.blazebit.persistence.impl.AbstractCommonQueryBuilder.applyImplicitJoins(AbstractCommonQueryBuilder.java:2712)
    at com.blazebit.persistence.impl.PaginatedCriteriaBuilderImpl.prepareAndCheck(PaginatedCriteriaBuilderImpl.java:728)
    at com.blazebit.persistence.impl.PaginatedCriteriaBuilderImpl.getQuery(PaginatedCriteriaBuilderImpl.java:521)
    at com.blazebit.persistence.impl.PaginatedCriteriaBuilderImpl.getQuery(PaginatedCriteriaBuilderImpl.java:88)
...

I've also heard about .isExpression thing, but don't get how to use it in a Specification.

The only option I currently see is to invoke this function using plain JDBC and then paste the results in a simple .in expression, but this would create a significant overhead.

Environment

Version: 1.6.12 JPA-Provider: Hibernate 5.6.15 DBMS: PostgreSQL 14.7 Application Server: Java SE

beikov commented 1 month ago

This looks correct to me. Do you think you could provide a reproducer for this?

AlexSischin commented 1 month ago

This looks correct to me. Do you think you could provide a reproducer for this?

Ok, I will try in a few days

AlexSischin commented 1 month ago

This looks correct to me. Do you think you could provide a reproducer for this?

Here is the reproducer based on the Spring Boot template. You will have to create a local Postgres database for it.

AlexSischin commented 3 weeks ago

I've finally made it work! I'm so sorry for wasting your time... The second mentioned specification was totally correct:

root.get("id").in(
        cb.function(
                "GET_OBJECTS_BY_PARENTS",
                List.class, // this should be UUID.class, but both work
                cb.literal(parents)
        )
);

The exception No object leaf allowed but model is an object leaf was actually due to Pageable had a sort by a ManyToOne property. I just removed it.

And also I had to change the return type for my Jpql function (it was a List):

public class GetObjectsByParentsFunction implements JpqlFunction {
    @Override
    public boolean hasArguments() {
        return true;
    }

    @Override
    public boolean hasParenthesesIfNoArguments() {
        return true;
    }

    @Override
    public Class<?> getReturnType(Class<?> firstArgClass) {
        return UUID.class;
    }

    @Override
    public void render(FunctionRenderContext context) {
        context.addChunk("SELECT id FROM get_objects_by_parents(");
        context.addArgument(0);
        context.addChunk(")");
    }
}

So, even though Hibernate worked before somehow, the code had some issues that should have been addressed anyway. Apologies for a false alarm

beikov commented 3 weeks ago

Glad it worked out for you!