0

UPDATE: I have checked this page and it does not seem to be the same problem. SO's auto-closer mistakenly thought they're the same. This talks about a specific error that I am having.


I am trying to create a custom Spring Data JPA repository that adds custom behavior to all repositories. I've followed all the instructions I could find for this, but I still keep coming up with

"PropertyReferenceException: No property 'advancedSearch' found for type 'X'"

from my pom:

  <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.7.3</version>
    <relativePath />
  </parent>
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
  </dependency>

Here's my code. JpqlQuery is a class I wrote. This is my interface.

@NoRepositoryBean
public interface QueryRepository<T, ID extends Serializable> extends JpaRepository<T, ID>
{
  QueryResults<T> advancedSearch(JpqlQuery<T> query) throws Exception;
}

I will be creating sub-interfaces extending that interface like so:

public interface AddressRepository extends QueryRepository<Address,Long>
{
}

This is the implementation. Note that it is the name of the interface plus "Impl" which I have read is necessary. I've tried putting this in a sub-package of the interface and also the same package as the interface, but it made no difference.

public class QueryRepositoryImpl<T, ID extends Serializable> extends SimpleJpaRepository<T, ID>
    implements QueryRepository<T, ID>
{
  @PersistenceContext
  private final EntityManager em;

  public QueryRepositoryImpl(Class<T> domainClass, EntityManager em)
  {
    super(domainClass, em);
    this.em = em;
  }

  public QueryRepositoryImpl(JpaEntityInformation<T, ?> entityInformation, EntityManager em)
  {
    super(entityInformation, em);
    this.em = em;
  }

  @Override
  @Transactional
  public QueryResults<T> advancedSearch(
    JpqlQuery<T> query) throws Exception
  {
...
  }
}

I also added the package name for the implementation to a ComponentScan annotation on the main application class:

@EnableEurekaClient
@SpringBootApplication
@ComponentScan({ //
                 "com.mycompany.common.repositories.impl" // For QueryRepositoryImpl
})
public class CoreRestServiceApplication
{
  ...
}

and added the following to a Configuration class in a service.

@Configuration
@EnableJpaRepositories(//
basePackages = {"com.mycompany.common.repositories.impl"}, //
repositoryBaseClass = QueryRepositoryImpl.class) // takes the place of the QueryRepositoryFactoryBean 
public class ApplicationConfiguration
{
  ...
}

The QueryRepository and QueryRepositoryImpl classes are in one jar and the services that use it are in different jars/projects. Could this be the error?

What am I missing or doing wrong?

Gary Kephart
  • 4,860
  • 5
  • 39
  • 52
  • Your interface shouldn't extend `JpaRepository`. You should have another interface that extends both `JpaRepository` and your custom interface. However what you are building feels like is the same as is offered by the `JpaSpecificationExecutor` interface (building dynamic queries based on a `Specification`). – M. Deinum Sep 21 '22 at 05:49
  • QueryRepository is that other interface. I will have other repository classes, like AddressQueryRepository that will extend QueryRepository. – Gary Kephart Sep 21 '22 at 17:27
  • No `QueryRepository` isn't that interface. `QueryRepository` shouldn't extend `JpaRepository`. Your `AddressQueryRepository` should extend both `QueryRepository` and `JpaRepository`. As I stated in my initial comment. – M. Deinum Sep 22 '22 at 05:27
  • QueryRepository now does not extends anything. AddressRepository extends JpaRepository, QueryRepository. I removed NoRepositoryBean annotation from QueryRepository and Repository annotation from AddressRepository. QueryRepositoryImpl now does not implement QueryRepository. All these are from https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.custom-implementations although it conflict with https://www.baeldung.com/spring-data-jpa-method-in-all-repositories. Still same problem. – Gary Kephart Sep 23 '22 at 16:34
  • The `QueryRepositoryImpl` **should** implement `QueryRepository` as shown in the reference documentation. You shouldn't define a `repositoryBaseClass` to your `@EnableJpaRepository` in fact, as you are using Spring Boot` you shouldn't even have that nor should you have the `@ComponentScan` on your `@SpringBootApplication` annotated class. Also make sure that the interface **and** repository implementation are in the same package. – M. Deinum Sep 26 '22 at 06:40
  • I now get "Field addressRepository in AddressRestController required a bean of type 'com.mycompany.corerestservice.repositories.AddressRepository' that could not be found". If I comment out the "NoRepositoryBean" annotation on AddressRepository, I then get "No property 'advancedSearch' found for type 'Address'" – Gary Kephart Sep 26 '22 at 22:16
  • BTW, the ref doc I'm using is https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.custom-implementations – Gary Kephart Sep 26 '22 at 22:43
  • I know which documentation you are using and you aren't following it properly. Your `AddressRepository` must extend `JpaRepository` (or `CrudRepository` or whichever of the interfaces yu choose and `QueryRepository` your `QueryRepositoryImpl` needs to be in the **same package** as the `QueryRepository` else it won't be picked up by Spring Data JPA. The question marked as duplicate is a duplicate as it describes the solution on what to do to solve it. Which you aren't fully following. – M. Deinum Sep 27 '22 at 08:13
  • I DID put the impl in the same package based on what you said, but I found nothing in section 4.6 that said that it can't be in a sub-package. In fact, if you look at Example 37, it shows implementations in different packages. Also, if you look at Example 40, it shows "@EnableJpaRepositories(repositoryBaseClass = MyRepositoryImpl.class)" and the preceding text talks about how that is mandatory. – Gary Kephart Sep 27 '22 at 15:59
  • Which are totally different samples! The first is one for a custom repository for a **single** method, the sample with the baseClass is for a custom implementation of **all methods** from the interfaces including the `CrudRepository`. If you follow samples you should also read the descriptions and not blindly follow code snippets. Now my memory fails me if the `QueryRepositoryImpl` needs an `@Component` or not. You could try that, also your `QueryRepositoryImpl` should not extend `SimpleJpaRepository` but only provide the implemention for your method. – M. Deinum Sep 27 '22 at 17:32
  • And what I'm trying to accomplish, but may drop for simplicity sake, is to create "a custom Spring Data JPA repository that adds custom behavior to all repositories" as I stated in the question. That is, section 4.6.2. – Gary Kephart Sep 27 '22 at 18:16

0 Answers0