Skip to content

SPI fragment can not be introduced by @NoRepositoryBean #3212

Open
@quaff

Description

@quaff
Contributor

Thanks to 4df7a16, Spring Data can introduce SPI fragments by specifying them in spring.factories, it works fine if repository extends the SPI interface, but it will fails if repository extends an @NoRepositoryBean base repository which extends the SPI interface.

Given:

public interface Fragment {
	String getName();
}

public class FragmentImpl implements Fragment {
	public String getName() {
		return "fragment";
	}
}

Following interface hierarchies works:

@NoRepositoryBean
interface ExcludedRepository extends JpaRepository<TestEntity, Long> {
}

interface TestEntityRepository extends ExcludedRepository, Fragment {
}

Following interface hierarchies fails:

@NoRepositoryBean
interface ExcludedRepository extends JpaRepository<TestEntity, Long>, Fragment {
}

interface TestEntityRepository extends ExcludedRepository {
}
Caused by: org.springframework.data.mapping.PropertyReferenceException: No property 'getName' found for type 'TestEntity'
	at org.springframework.data.mapping.PropertyPath.<init>(PropertyPath.java:94) ~[spring-data-commons-3.4.0.jar:3.4.0]
	at org.springframework.data.mapping.PropertyPath.create(PropertyPath.java:455) ~[spring-data-commons-3.4.0.jar:3.4.0]
	at org.springframework.data.mapping.PropertyPath.create(PropertyPath.java:431) ~[spring-data-commons-3.4.0.jar:3.4.0]
	at org.springframework.data.mapping.PropertyPath.lambda$from$0(PropertyPath.java:384) ~[spring-data-commons-3.4.0.jar:3.4.0]
	at java.base/java.util.concurrent.ConcurrentMap.computeIfAbsent(ConcurrentMap.java:330) ~[na:na]
	at org.springframework.data.mapping.PropertyPath.from(PropertyPath.java:366) ~[spring-data-commons-3.4.0.jar:3.4.0]
	at org.springframework.data.mapping.PropertyPath.from(PropertyPath.java:344) ~[spring-data-commons-3.4.0.jar:3.4.0]
	at org.springframework.data.repository.query.parser.Part.<init>(Part.java:81) ~[spring-data-commons-3.4.0.jar:3.4.0]
	at org.springframework.data.repository.query.parser.PartTree$OrPart.lambda$new$0(PartTree.java:259) ~[spring-data-commons-3.4.0.jar:3.4.0]
	at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) ~[na:na]
	at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:179) ~[na:na]
	at java.base/java.util.Spliterators$ArraySpliterator.forEachRemaining(Spliterators.java:992) ~[na:na]
	at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509) ~[na:na]
	at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499) ~[na:na]
	at java.base/java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:921) ~[na:na]
	at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) ~[na:na]
	at java.base/java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:682) ~[na:na]
	at org.springframework.data.repository.query.parser.PartTree$OrPart.<init>(PartTree.java:260) ~[spring-data-commons-3.4.0.jar:3.4.0]
	at org.springframework.data.repository.query.parser.PartTree$Predicate.lambda$new$0(PartTree.java:389) ~[spring-data-commons-3.4.0.jar:3.4.0]
	at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) ~[na:na]
	at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:179) ~[na:na]
	at java.base/java.util.Spliterators$ArraySpliterator.forEachRemaining(Spliterators.java:992) ~[na:na]
	at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509) ~[na:na]
	at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499) ~[na:na]
	at java.base/java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:921) ~[na:na]
	at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) ~[na:na]
	at java.base/java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:682) ~[na:na]
	at org.springframework.data.repository.query.parser.PartTree$Predicate.<init>(PartTree.java:390) ~[spring-data-commons-3.4.0.jar:3.4.0]
	at org.springframework.data.repository.query.parser.PartTree.<init>(PartTree.java:100) ~[spring-data-commons-3.4.0.jar:3.4.0]
	at org.springframework.data.jpa.repository.query.PartTreeJpaQuery.<init>(PartTreeJpaQuery.java:101) ~[spring-data-jpa-3.4.0.jar:3.4.0]

Here is reproducer project spifragment.zip
.

Activity

quaff

quaff commented on Nov 25, 2024

@quaff
ContributorAuthor

It caused by FragmentMetadata::getFragmentInterfaces doesn't consider indirect super interfaces.

public Stream<String> getFragmentInterfaces(String interfaceName) {
Assert.hasText(interfaceName, "Interface name must not be null or empty");
return Arrays.stream(getClassMetadata(interfaceName).getInterfaceNames()) //
.filter(this::isCandidate);
}

I'll try to fix it later.

self-assigned this
on Nov 25, 2024
added a commit that references this issue on Nov 25, 2024
c732728
mp911de

mp911de commented on Nov 27, 2024

@mp911de
Member

We intentionally do not consider super-interfaces for repository fragment detection so in that sense the code works as designed and is not broken. Super-interfaces can reside in other packages and then we open a can of worms asking for consideration of fragment implementations that can reside in other packages, regardless of the SPI feature we recently shipped.

added
for: team-attentionAn issue we need to discuss as a team to make progress
status: on-holdWe cannot start working on this issue yet
and removed on Nov 27, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

for: team-attentionAn issue we need to discuss as a team to make progressstatus: on-holdWe cannot start working on this issue yettype: enhancementA general enhancement

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

    Participants

    @quaff@mp911de@spring-projects-issues

    Issue actions

      SPI fragment can not be introduced by `@NoRepositoryBean` · Issue #3212 · spring-projects/spring-data-commons