Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Errors during entity graph call to DB after upgrading Spring boot/spring-data-jpa-entity-graph #128

Open
mr-nothing opened this issue Sep 20, 2023 · 1 comment

Comments

@mr-nothing
Copy link

mr-nothing commented Sep 20, 2023

What steps will reproduce the problem ?

I'm not sure if there is an easy way to reproduce the issue since I don't face it in a local environment but this error always come up in k8s environment. Here are probable steps that cause it:

Steps to reproduce the behaviour:

  1. Try to fetch entities by id with method findAllById (probably with a long list of ids, but not sure if length of the list matters) in repository component with defaultEntityGraph overridden and EntityGraphJpaRepository interface implemented in async manner. To be more precise I use Netflix DGS and it's entity fetchers which use ForkJoinPools under the hood to parallel requests to backend services, as far as I know.

What is the expected output ?

The request to database is executed with no issues.

What happens instead ?

The error is faced:

j.l.IllegalArgumentException: org.hibernate.query.hql.spi.SqmQueryImplementor referenced from a method is not visible from class loader
at j.l.r.Proxy$ProxyBuilder.ensureVisible(Unknown Source)
at j.l.r.Proxy$ProxyBuilder.validateProxyInterfaces(Unknown Source)
at j.l.r.Proxy$ProxyBuilder.<init>(Unknown Source)
at j.lang.reflect.Proxy.lambda$getProxyConstructor$1(Unknown Source)
at j.i.l.AbstractClassLoaderValue$Memoizer.get(Unknown Source)
at j.i.l.AbstractClassLoaderValue.computeIfAbsent(Unknown Source)
at j.lang.reflect.Proxy.getProxyConstructor(Unknown Source)
at j.lang.reflect.Proxy.newProxyInstance(Unknown Source)
at o.s.a.f.JdkDynamicAopProxy.getProxy(JdkDynamicAopProxy.java:123)
at o.s.a.f.JdkDynamicAopProxy.getProxy(JdkDynamicAopProxy.java:115)
at o.s.a.f.ProxyFactory.getProxy(ProxyFactory.java:97)
at c.c.s.d.j.e.g.r.s.RepositoryQueryEntityGraphInjector.proxy(RepositoryQueryEntityGraphInjector.java:37)
at c.c.s.d.j.e.g.r.s.RepositoryEntityManagerEntityGraphInjector.invoke(RepositoryEntityManagerEntityGraphInjector.java:70)
at o.s.a.f.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
at o.s.a.f.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:244)
at j.proxy2.$Proxy218.createQuery(Unknown Source)
at o.s.d.j.r.s.SimpleJpaRepository.getQuery(SimpleJpaRepository.java:755)
at o.s.d.j.r.s.SimpleJpaRepository.getQuery(SimpleJpaRepository.java:733)
at o.s.d.j.r.s.SimpleJpaRepository.findAllById(SimpleJpaRepository.java:408)
at j.i.r.NativeMethodAccessorImpl.invoke0(Unknown Source)
at j.i.r.NativeMethodAccessorImpl.invoke(Unknown Source)
at j.i.r.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at j.l.reflect.Method.invoke(Unknown Source)
at o.s.d.r.c.s.RepositoryMethodInvoker$RepositoryFragmentMethodInvoker.lambda$new$0(RepositoryMethodInvoker.java:288)
at o.s.d.r.c.s.RepositoryMethodInvoker.doInvoke(RepositoryMethodInvoker.java:136)
at o.s.d.r.c.s.RepositoryMethodInvoker.invoke(RepositoryMethodInvoker.java:120)
at o.s.d.r.c.s.RepositoryComposition$RepositoryFragments.invoke(RepositoryComposition.java:516)
at o.s.d.r.c.s.RepositoryComposition.invoke(RepositoryComposition.java:285)
at o.s.d.r.c.s.RepositoryFactorySupport$ImplementationMethodExecutionInterceptor.invoke(RepositoryFactorySupport.java:628)
at o.s.a.f.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
... 10 frames truncated
... 39 common frames omitted\nWrapped by: o.s.d.InvalidDataAccessApiUsageException: org.hibernate.query.hql.spi.SqmQueryImplementor referenced from a method is not visible from class loader
at o.s.o.j.EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(EntityManagerFactoryUtils.java:371)
at o.s.o.j.v.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:234)
at o.s.o.j.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:550)
at o.s.d.s.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:61)
at o.s.d.s.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:242)
at o.s.d.s.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:152)
at o.s.a.f.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
at c.c.s.d.j.e.g.r.s.RepositoryMethodInvocation.proceed(RepositoryMethodInvocation.java:23)
at c.c.s.d.j.e.g.r.s.EntityGraphQueryHintCandidates.doInvoke(EntityGraphQueryHintCandidates.java:96)
at c.c.s.d.j.e.g.r.s.EntityGraphQueryHintCandidates.invoke(EntityGraphQueryHintCandidates.java:60)
at o.s.a.f.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
at o.s.d.j.r.s.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:164)
at o.s.a.f.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
at o.s.a.i.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97)
at o.s.a.f.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)

Environment

  • Spring Data JPA version (not the Spring Boot one): 3.1.2
  • ORM with version:
    • org.hibernate.common:hibernate-commons-annotations:6.0.6.Final
    • org.hibernate.orm:hibernate-core:6.2.7.Final
    • org.hibernate.validator:hibernate-validator:8.0.1.Final
  • spring-data-jpa-entity-graph version: 3.1.0

Link to an automated test demonstrating the problem

No luck to create a test or provide environment to reproduce it.

Additional context

I talked with guys from spring boot and they gave me some places worth to look at: spring-projects/spring-boot#37474

@SergeantGrumbles
Copy link

Hey, just an FYI as this came up for myself. Its not kubernetes, its within a docker container, so I was able to recreate this in an unrelated project locally.

I believe this is fixed by the following answer on stackoverflow:

https://stackoverflow.com/a/59444016

which in turn depends on the following solution in creating a ForkJoinerWorkerThreadFactory and propagating the correct class loader to the other thread.

https://stackoverflow.com/questions/49113207/completablefuture-forkjoinpool-set-class-loader/57551188#57551188

public class MyForkJoinWorkerThreadFactory implements ForkJoinPool.ForkJoinWorkerThreadFactory {

    @Override
    public final ForkJoinWorkerThread newThread(ForkJoinPool pool) {
        return new MyForkJoinWorkerThread(pool);
    }

    private static class MyForkJoinWorkerThread extends ForkJoinWorkerThread {

        private MyForkJoinWorkerThread(final ForkJoinPool pool) {
            super(pool);
            // set the correct classloader here
            setContextClassLoader(Thread.currentThread().getContextClassLoader());
        }
    }
}

Delcare custom executor:

@Bean(name = "customExecutor")
    public Executor customExecutor() {
        MyForkJoinWorkerThreadFactory factory = new MyForkJoinWorkerThreadFactory();
        ForkJoinPool myCommonPool = new ForkJoinPool(Math.min(32767, Runtime.getRuntime().availableProcessors()), factory, null, false);

        return new DelegatingSecurityContextExecutor(myCommonPool, SecurityContextHolder.getContext());
    }

At that point the usage of data loader should use the customExecutor bean

 @Bean(name = "myDataLoader")
    @Scope(value = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS)
    public DataLoader<Object, Object> myDataLoader(@Qualifier("customExecutor") Executor customExecutor) {
return DataLoaderFactory.newDataLoader(myValue -> {

CompletableFuture.supplyAsync(() -> {
                return 1L; // perform the actual work causing the exception here
            }, customExecutor));
}):

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants