Close

Spring Data JPA - Using SpEL variable #entityName to create a Generic Repository

[Updated: May 30, 2018, Created: May 30, 2018]

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 Project

Dependencies 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

Spring El, using #entityName to create a Generic Repository Select All Download
  • spring-data-jpa-spel-expression-generic-repo
    • src
      • main
        • java
          • com
            • logicbig
              • example
                • TaskRepository.java
          • resources
            • META-INF

    See Also