0

I have the following interface:

public interface SnapshotRepository extends JpaRepository<Snapshot, Integer>, ISnapshotRepositoryExtra { }

that as you can see extends:

public interface ISnapshotRepositoryExtra {
    Optional<Snapshot> latest();
}

... I've implemented that latest() method in the following classes:

@Transactional
public class SnapshotRepositoryExtra implements ISnapshotRepositoryExtra {

    @PersistenceContext
    private EntityManager entityManager;

    @Override
    public Optional<Snapshot> latest() {
        return (Optional<Snapshot>) entityManager
                .createQuery("SELECT r FROM snapshot r order by timestamp DESC LIMIT 1")
                .getResultStream().findFirst();
    }
}

However when I launch the project, I see:

java.lang.IllegalArgumentException: Failed to create query for method public abstract java.util.Optional com...persistance.snapshot.ISnapshotRepositoryExtra.latest()! No property latest found for type Snapshot!

So my question is, why Spring does not see the class SnapshotRepositoryExtra that I've just made?

Alberto Sinigaglia
  • 12,097
  • 2
  • 20
  • 48
  • Because Spring tries to implement the interface by itself. Why not use an interface method with `@NativeQuery`? – Turing85 May 12 '21 at 21:44
  • @Turing85 and are there ways to tell Spring to take that class as implementation? (btw, is to have the Optional, but this is only a case where i can use `@Query`, but there are others where I can't) – Alberto Sinigaglia May 12 '21 at 21:46
  • Not that I know of. Spring tries to implement the method in a `JpaRepository` by itself, either by evaluating `@(Native)Query`-annotations or by [SpEL-conventitons](https://docs.spring.io/spring-data/jpa/docs/current-SNAPSHOT/reference/html/#jpa.query-methods). --- As far as I know, Spring Data JAP supports `Optional`. – Turing85 May 12 '21 at 21:52
  • I don't expect that `@Transactional` goes on the repository interface. Instead it should go on a service class. – K.Nicholas May 12 '21 at 21:52
  • @K.Nicholas I would advice against annotating the whole service-class with `@Transactional`. A better solution would be to annotate only methods that actually need transactional semantics, and configure the transaction properrly (e.g. by setting `readOnly = true` if applicable). – Turing85 May 12 '21 at 21:54
  • @Turing85 So in other words, there is no way to add "a custom method" to the JpaRepository interface? – Alberto Sinigaglia May 12 '21 at 21:56
  • As I said: there is. Add the method to the interface, annotate the method with `@Query`, set it as native query ([Spring documentation](https://docs.spring.io/spring-data/jpa/docs/current-SNAPSHOT/reference/html/#jpa.query-methods.at-query.native)) – Turing85 May 12 '21 at 21:58
  • @Turing85 well, thank you then, I'll try using `@Query` – Alberto Sinigaglia May 12 '21 at 22:01
  • @Turing85 - transactional is for multiple tables, so does it make sense on a single repository? It certainly doesn't belong on read method. – K.Nicholas May 12 '21 at 23:34
  • @K.Nicholas "*transactional is for multiple tables*" - Not really. `@Transactional` is for... well... transactional semantics. This means that either all operations encapsulated in a transaction pass or none of them. This can be (and often is) used on a single table. And it definitively belongs on read methods. That is what [`Transactional.readOnly`](https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/transaction/annotation/Transactional.html#readOnly--) is for. – Turing85 May 13 '21 at 05:31
  • Yea, not really. Try giving some useful information if you're going to bother. https://stackoverflow.com/questions/1614139/spring-transactional-read-only-propagation – K.Nicholas May 13 '21 at 10:54

1 Answers1

0

Spring Data is picky about how you name things. According to the documentation :

The most important part of the class name that corresponds to the fragment interface is the Impl postfix.

In other words, you need to call your interface something like SnapshotRepositoryExtra and the implementation SnapshotRepositoryExtraImpl for Spring Data to recognise it (most examples I've seen would use something like CustomSnapshotRepository for the interface, but I don't think that convention is required).

That's for the latest version; previous versions of Spring Data had different naming requirements.

rimesc
  • 158
  • 2
  • 7