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

java.lang.IllegalStateException is thrown by invoking findBy method #3294

Closed
quaff opened this issue Jan 3, 2024 · 5 comments
Closed

java.lang.IllegalStateException is thrown by invoking findBy method #3294

quaff opened this issue Jan 3, 2024 · 5 comments
Assignees
Labels
type: enhancement A general enhancement

Comments

@quaff
Copy link
Contributor

quaff commented Jan 3, 2024

java.lang.IllegalStateException: No MethodInvocation found: Check that an AOP invocation is in progress, and that the CrudMethodMetadataPopulatingMethodInterceptor is upfront in the interceptor chain.
	at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.currentInvocation(CrudMethodMetadataPostProcessor.java:123)
	at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$ThreadBoundTargetSource.getTarget(CrudMethodMetadataPostProcessor.java:294)
	at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:229)
	at jdk.proxy2/jdk.proxy2.$Proxy100.getLockModeType(Unknown Source)
	at org.springframework.data.jpa.repository.support.SimpleJpaRepository.applyRepositoryMethodMetadata(SimpleJpaRepository.java:845)
	at org.springframework.data.jpa.repository.support.SimpleJpaRepository.getQuery(SimpleJpaRepository.java:756)
	at org.springframework.data.jpa.repository.support.SimpleJpaRepository.lambda$doFindBy$2(SimpleJpaRepository.java:521)
	at org.springframework.data.jpa.repository.support.FetchableFluentQueryBySpecification.createSortedAndProjectedQuery(FetchableFluentQueryBySpecification.java:183)
	at org.springframework.data.jpa.repository.support.FetchableFluentQueryBySpecification.stream(FetchableFluentQueryBySpecification.java:166)
	at findby.FindByTests.findBy(FindByTests.java:30)
	at java.base/java.lang.reflect.Method.invoke(Method.java:568)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)

Here is test case:

package findby;

import java.util.function.Function;
import java.util.stream.Stream;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.data.jpa.domain.AbstractPersistable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.test.context.ContextConfiguration;

import jakarta.persistence.Entity;

@DataJpaTest
@EnableJpaRepositories(basePackageClasses = FindByTests.TestEntityRepository.class, considerNestedRepositories = true)
@EntityScan(basePackageClasses = FindByTests.TestEntity.class)
@ContextConfiguration(classes = FindByTests.class)
class FindByTests {

	@Autowired
	TestEntityRepository repository;

	@Test
	void findBy() {
		// will throw java.lang.IllegalStateException: No MethodInvocation found
		repository.findBy((root, query, cb) -> null, Function.identity()).stream();
	}

	@Test
	void findByInDefaultMethod() {
		// works fine
		repository.findByInDefaultMethod();
	}

	interface TestEntityRepository extends JpaRepository<TestEntity, Long>, JpaSpecificationExecutor<TestEntity> {

		default Stream<TestEntity> findByInDefaultMethod() {
			return findBy((root, query, cb) -> null, Function.identity()).stream();
		}

	}

	@Entity
	static class TestEntity extends AbstractPersistable<Long> {

	}

}

with

plugins {
	id 'java'
	id 'org.springframework.boot' version '3.2.1'
	id 'io.spring.dependency-management' version 'latest.release'
}

group = 'com.example'
version = '0.0.1-SNAPSHOT'

repositories {
	mavenCentral()
}

dependencies {
	implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
	testImplementation 'org.springframework.boot:spring-boot-starter-test'
	testRuntimeOnly 'com.h2database:h2'
}

tasks.named('test') {
	useJUnitPlatform()
}
@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Jan 3, 2024
@pbeltechi
Copy link

I also ecountered this using "org.springframework.boot:spring-boot-starter-data-mongodb"

@christophstrobl
Copy link
Member

Thank you @quaff for reporting and adding the test snippet. The current behaviour, though unintuitive, is the expected one. The findBy method in this case exposes the FetchableFluentQuery outside the repository. So when the stream invocation happens the context is already gone.

We're considering to enhance the current flow so that we capture method metadata early and can provide it later on in this scenario.

Meanwhile you can try it this way repository.findBy((root, query, cb) -> null, FetchableFluentQuery::stream).

@christophstrobl christophstrobl added status: pending-design-work Needs design work before any code can be developed type: enhancement A general enhancement and removed status: waiting-for-triage An issue we've not yet triaged labels Jan 9, 2024
@christophstrobl christophstrobl self-assigned this Jan 9, 2024
@quaff
Copy link
Contributor Author

quaff commented Jan 10, 2024

Meanwhile you can try it this way repository.findBy((root, query, cb) -> null, FetchableFluentQuery::stream).

Thanks, it works, does the document mention such limitation?

@christophstrobl
Copy link
Member

Unfortunately not, all samples are using one of the terminating (one, first, all,...) methods.

@mp911de mp911de assigned mp911de and unassigned christophstrobl Jan 22, 2025
@mp911de mp911de removed the status: pending-design-work Needs design work before any code can be developed label Jan 22, 2025
@mp911de
Copy link
Member

mp911de commented Jan 22, 2025

We can catch these cases by checking whether the returned object is an instance of FluentQuery. If so, then we can throw an exception.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: enhancement A general enhancement
Projects
None yet
Development

No branches or pull requests

5 participants