Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to implement a Spring Data repository for a @MappedSuperclass

I've got a JPA @MappedSuperClass and an @Entity extending it:

@MappedSuperclass public class BaseClass {      @Id     @GeneratedValue(strategy = GenerationType.AUTO)     private Long id;      @Column     private Boolean active;      //getters & setters  }  @Entity public class Worker extends BaseClass{      @Column     private String name;      //getters & setters  } 

The active field of the base class is a flag for the children entities. Only the active ones should be loaded in the application. Then I've written a generic Spring Data Proxy interface:

public interface Dao<T extends BaseClass, E extends Serializable> extends         CrudRepository<T, E> {      Iterable<T> findByActive(Boolean active);  } 

And this one is the interface that should be for Worker data access, properly extending the previous one:

@Transactional public interface WorkerDao extends Dao<Worker, Long>{} 

Well, now in my logic layer I've implemented an abstract class which will wrap the common code for CRUD operations over my entities. I'll have a service for each of them, but I want just to inherit from the abstract one. I want to wire the specific repository for each of the services and provide it to the superclass using an abstract method. That's how my superclass is implemented:

public abstract class GenericService<E extends BaseClass>{      public abstract Dao<E, Long> getDao();      //Here I've got some common operations for managing      //all my application classes, including Worker  } 

The problem is that the getDao() method uses the E class parameter, which is guaranteed only to be a child of BaseClass and not a javax.persistence.Entity. When I try to access the DAO from my custom service implementation I get this error:

Caused by: java.lang.IllegalArgumentException: Could not create query metamodel for method public abstract java.lang.Iterable com.mycompany.model.daos.interfaces.Dao.findByActive(java.lang.Boolean)! at org.springframework.data.jpa.repository.query.JpaQueryLookupStrategy$CreateQueryLookupStrategy.resolveQuery(JpaQueryLookupStrategy.java:93)

Caused by: java.lang.IllegalArgumentException: Not an entity: class com.mycompany.model.BaseClass at org.hibernate.jpa.internal.metamodel.MetamodelImpl.entity(MetamodelImpl.java:203)

Which makes sense, because E is defined as a child of BaseClass. The compiler allows me to write this too:

public abstract class GenericService<E extends BaseClass && Entity> 

However I get an error in the child Service that says Worker class is not compatible with the signature for E. Does anybody know how to solve this?

like image 209
Xtreme Biker Avatar asked Dec 18 '14 11:12

Xtreme Biker


People also ask

How are Spring data repositories implemented?

In the repository interfaces, we can add the methods like findByCustomerNameAndPhone() (assuming customerName and phone are fields in the domain object). Then, Spring provides the implementation by implementing the above repository interface methods at runtime (during the application run).

What is Spring data repository?

The goal of Spring Data repository abstraction is to significantly reduce the amount of boilerplate code required to implement data access layers for various persistence stores.


1 Answers

It's just a matter of annotating the abstract Repository as @NoRepositoryBean:

@NoRepositoryBean public interface Dao<T extends BaseClass, E extends Serializable> extends         CrudRepository<T, E> {      Iterable<T> findByActive(Boolean active);  } 

This way Spring relies on the underlying repository implementation to execute the findByActive method.

Regarding to the annotation type restriction issue, it's not possible to declare an annotation restricted type. See the referenced answers below.

See also:

  • Generic Spring Data JPA repository implementation to load data by class type
  • Annotations: restrict reference to classes with a annotation
like image 56
Xtreme Biker Avatar answered Sep 24 '22 02:09

Xtreme Biker