Open
Description
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 commentedon Nov 25, 2024
It caused by
FragmentMetadata::getFragmentInterfaces
doesn't consider indirect super interfaces.spring-data-commons/src/main/java/org/springframework/data/repository/config/FragmentMetadata.java
Lines 51 to 57 in 4718c45
I'll try to fix it later.
Register indirect fragment introduced by super interfaces
mp911de commentedon Nov 27, 2024
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.