Reputation: 1358
I am currently migrating an application that manages JPA in form of Hibernate ORM by itself to Spring Boot 2.0.0
with Spring Data JPA 2.0.0
. This application currently has about 50 entities, each with its own data source which I now want to migrate to Spring Data Repositories. Many of those data sources have many quite similar features, i.e. filtering with a custom filter class or fetching an entity by some sort of unique key that is not its id. I could very well just implement a custom base class as described in the Spring Data JPA Reference, but this would mean that I would have to would have to provide custom filters for each and every entity, where I only need on for maybe 10 of them.
Is there any possible way to have Spring Data merge multiple custom repository implementations as shown below?
Entities:
@Entity
public class Artist {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
int id;
@Column(unique = true)
int secondaryId;
String name;
... constructors, getter, setter, etc ...
}
@Entity
public class Album {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
int id;
String name;
... constructors, getter, setter, etc ...
}
Custom repositories with default implementations:
public interface FilterRepository<T> {
public T findByFilter(Filter<T> t);
}
public class FilterRepositoryImpl<T> implements AdditionalRepository<T> {
public T findByFilter(Filter<T> t) {
... return something ...
}
}
public interface FindByFieldRepository<T> {
public T findByField(String fieldName, Object fieldValue);
}
public class FindByFieldRepositoryImpl<T> implements FindByFieldRepository<T> {
public T findByField(String fieldName, Object fieldValue) {
... return something ...
}
}
Spring Data Repositories
@Repository
public interface ArtistRepository extends JpaRepository<Artist, Integer>,
FilterRepository<Artist>, FindByFieldRepository<Artist> {
}
@Repository
public interface AlbumRepository extends JpaRepository<Album, Integer>,
FilterRepository<Album> {
}
Notice that ArtistRepository
extends both custom repositories while AlbumRepository
only extends FilterRepository
. Another repository might extend JpaRepository
but none of the custom defined ones.
Upvotes: 6
Views: 11496
Reputation: 20135
This should be possible with two interfaces and a single custom repository implementation. For example:
Step 1: Simple extension of
JpaRepository
@NoRepositoryBean
public interface FilteringJpaRepository<T> extends JpaRepository<T, Long> {
T findByFilter(Filter<T> t);
}
Step 2: A more complicated extension of
JpaRepository
@NoRepositoryBean
public interface ExtendedJpaRepository<T> extends FilteringJpaRepository<T> {
T findByField(String fieldName, Object fieldValue);
}
Step 3: A custom repository implementation
Add a custom repository implementation as described in the documentation linked to in the question. Also make sure to change the JPA configuration to use the custom implementation.
@NoRepositoryBean
public class ExtendedJpaRepositoryImpl<T>
extends SimpleJpaRepository<T, Long>
implements ExtendedJpaRepository<T> {
...
public T findByFilter(Filter<T> t) { ... }
public T findByField(String fieldName, Object fieldValue) { ... }
}
Step 4: Extend from the appropriate repository as required
public interface AlbumRepository extends FilteringJpaRepository<Album> {}
public interface ArtistRepository extends ExtendedJpaRepository<Artist> {}
Since the functional repositories extend only the required repository, their consumers will only see methods appropriate for them.
Please see the sample app for this approach.
Upvotes: 4