In the last tutorial, we saw a use case for using SpEL variable #entityName. In this example we will see another use case, that is, to create a generic repository, say R, based on an abstract generic type, say T. If we define queries using @Query along with #entityName in such repository, then those queries will be inherited to the repositories extending R and are based on subtypes of T. That way we don't have to repeat the definition of query methods for the subtypes of T. Let's understand that with an example.
Example
Entities
@MappedSuperclass
public abstract class Task {
@Id
@GeneratedValue
private long id;
private String name;
.............
}
@Entity
public class AsyncTask extends Task {
.............
}
@Entity
public class SyncTask extends Task {
.............
}
Repositories
package com.logicbig.example;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.NoRepositoryBean;
import java.util.List;
@NoRepositoryBean
public interface TaskRepository<T extends Task> extends CrudRepository<T, Long> {
@Query("SELECT t FROM #{#entityName} t WHERE t.name = ?1")
public List<T> findTaskByName(String taskName);
}
Note that we used @NoRepositoryBean in above interface. This annotation is used to exclude repository interfaces from being picked up by the framework and getting an instance being created.
package com.logicbig.example;
public interface AsyncTaskRepository extends TaskRepository<AsyncTask> {
}
package com.logicbig.example;
public interface SyncTaskRepository extends TaskRepository<SyncTask> {
}
Example Client
@Component
public class ExampleClient {
@Autowired
private AsyncTaskRepository repoAsync;
@Autowired
private SyncTaskRepository repoSync;
public void run() {
repoAsync.saveAll(Arrays.asList(AsyncTask.of("Scheduling"),
AsyncTask.of("Cleaning")));
repoSync.saveAll(Arrays.asList(SyncTask.of("Downloading"),
SyncTask.of("Reporting")));
System.out.println(" -- finding async task --");
List<AsyncTask> list = repoAsync.findTaskByName("Cleaning");
list.forEach(System.out::println);
System.out.println(" -- finding sync task --");
List<SyncTask> list2 = repoSync.findTaskByName("Reporting");
list2.forEach(System.out::println);
}
}
Main class
public class ExampleMain {
public static void main(String[] args) {
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(AppConfig.class);
ExampleClient exampleClient = context.getBean(ExampleClient.class);
exampleClient.run();
EntityManagerFactory emf = context.getBean(EntityManagerFactory.class);
emf.close();
}
} -- finding async task -- AsyncTask{id=2, name='Cleaning'} -- finding sync task -- SyncTask{id=4, name='Reporting'}
Example ProjectDependencies and Technologies Used: - spring-data-jpa 2.0.7.RELEASE: Spring Data module for JPA repositories.
Uses org.springframework:spring-context version 5.0.6.RELEASE - hibernate-core 5.3.1.Final: Hibernate's core ORM functionality.
Implements javax.persistence:javax.persistence-api version 2.2 - h2 1.4.197: H2 Database Engine.
- JDK 1.8
- Maven 3.3.9
|