Is it possible to customize Jpa Repository with inheritance? - java

Let's say that i have two Classes: Subject and Client, Subject is base-class.
#Entity
public class Client extends Subject
Now i want to add customized Jpa base interface, so methods will be accessible in subinterfaces:
#NoRepositoryBean
public interface SubjectRepository <T extends Subject> extends
JpaRepository<T, Long>, CustomSubjectRepository<T> {}
CustomSubjectRepository looks like:
public interface CustomSubjectRepository<T extends Subject> {
void saveEncrypted(T subject);
}
I need implementation so i declare class:
#Repository
#Transactional
public class CustomSubjectRepositoryImpl<T extends Subject> implements
CustomSubjectRepository<T> {
#PersistenceContext
private EntityManager entityManager;
#Override
public void saveEncrypted(T subject) {
//implementation
}
}
Then wanted to create ClientRepository and inherit from SubjectRepository to have access to saveEncrypted method.
#Repository
public interface ClientRepository extends SubjectRepository<Client> {
}
But when it comes to compile i get:
Error creating bean with name 'clientRepository': Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: Failed to create query for method public abstract void com.path.repositories.CustomSubjectRepository.saveEncrypted(com.path.models.Subject)! No property saveEncrypted found for type Client!

You are extending the interface, this way Spring will try to create a query named saveEncrypted instead of using the customized method.
I believe the best solution is to extend the class CustomSubjectRepositoryImpl.
#Repository
public class ClientRepository extends CustomSubjectRepositoryImpl<Client> {
}

Related

How to get TypeLiteral binding or can say instance from injector [Google Guice]

I have Dao<T> interface which is implemented by BaseDao<T> class & BaseDao<T> later extended by many of subclass like UserDao class.
interface Dao<T>{}
abstract class BaseDao<T> implements Dao<T>{}
class UserDao extends BaseDao<User>{}
Following is the guice binding
bind(new TypeLiteral<Dao<User>>() {
}).annotatedWith(Names.named("UserDao")).toProvider(UserDaoProvider.class);
Provider looks like..
public class UserDaoProvider implements Provider<UserDao> {
#Override
public UserDao get() {
return new UserDao();
}
}
Now i am trying to get it from guice injector
injector.getInstance(Key.get(new TypeLiteral<Dao<User>>() {
}, Names.named("UserDao")));
But i am getting null
Please help to resolve the issue.
We can get instance of UserDao as follows
injector.getInstance(UserDao.class);

Custom generic spring data repository

Using spring data, I have two tables that shares the same structure.
The two tables are represented by two different entities, that inherit from the same class :
#MappedSuperclass
public abstract class SuperEntity<T extends SuperEntity> {
// ...
}
#Table(name = "FOO")
#Entity
public class Foo extends SuperEntity<Foo> {
// ...
}
#Table(name = "BAR")
#Entity
public class Bar extends SuperEntity<Bar> {
// ...
}
I also have a generic repository, that I would like to use to factorize to requesting logic, and two sub-repository : one for each table.
public interface GenericEvtRepository <T extends SuperEntity<?>> extends JpaRepository<T, String> { }
public interface FooRepository extends GenericEvtRepository<Foo> {}
public interface BarRepository extends GenericEvtRepository<Bar> {}
I would like to add an actual query implementation to this repository (i.e. using EntityManager / Criteria).
Therefore I tried to adapt the custom repository strategy to my generic case
#Repository
public class GenericEvtRepositoryImpl<T extends SuperEntity<?>> extends SimpleJpaRepository<T, String> implements GenericEvtRepository<T> {
#PersistenceContext
EntityManager entityManager;
// Some logic using entityManager
public SuperEntity myCustomRequest() { /*...*/ }
}
However my application doesn't start, with the exception :
org.springframework.data.mapping.PropertyReferenceException: No property myCustomRequest found for type Foo!
Not sure what I'm doing wrong, but Spring seems to think that myCustomRequest is an attribute from my entities, instead of a method.
I'm using spring-boot 1.5.6 and spring-data-jpa 1.11.6.
Minimal reproductible exemple
Luckily I was able to reproduce your issue,
How spring recommends custom repository implementation is specified here in spring docs.
So, you can do something like below,
public interface CustomEntityRepository<T extends SuperTag<?>>
public interface FooRepository extends JpaRepository<Foo, Integer>, CustomEntityRepository<Foo>
public interface BarRepository extends JpaRepository<Bar, Integer>, CustomEntityRepository<Bar>
And define common implementation for CustomEntityRepository<T extends SuperTag<?>> as below,
#Repository
// NOTE: Implementation name must follow convension as InterfaceName + 'Impl'
public class CustomEntityRepositoryImpl<T extends SuperTag<?>> implements
CustomEntityRepository<T> {
#PersistenceContext
private EntityManager entityManager;
// Generic custom implementation here
}
Spring automatically detects implementation of Custom Interface CustomEntityRepository based on implementation class naming convention.

No qualifying bean of type AbstractRepository<?>' available: expected single matching bean but found 2

I am using spring-boot to implement some rest-endpoint. I have implements an AbstractRepository and an AbstractEnpoint with is #Autowired. Both are then extended by the really 2 Endpoints: ClientEndpoint and HospitalReservationListEndpoint.
But I get the following error in the Browser when I try to call methods in Endpoints that neccessite the repository:
"org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'org.parcaune.reservationmanagerservices.core.AbstractRepository<?>' available: expected single matching bean but found 2: clientRepository,hospitalReservationListRepository"
My Classes:
My AbstractRepository
/*
#NoRepositoryBean
Annotation to exclude repository interfaces from being picked up
and thus in consequence getting an instance being created
*/
#NoRepositoryBean
public interface AbstractRepository<T> extends JpaRepository<T, String>
{
}
My AbstractEndpoint
public abstract class AbstractEndpoint<T> {
#Autowired
protected AbstractRepository<T> repository;
#GET
#Path("/ping")
#Produces(MediaType.TEXT_PLAIN)
public String ping() {
return "Endpoint works!";
}
#GET
#Produces(MediaType.APPLICATION_JSON)
public List<T> getAll() {
List<T> list = new ArrayList<>();
list = repository.findAll();
return list;
}
}
My Client-Classes:
public interface ClientRepository extends AbstractRepository<Client> {
}
and
#Component
#Path("/clients")
public class ClientEndpoint extends AbstractEndpoint<Client> {
}
My Hospital-Classes
public interface HospitalReservationListRepository extends
AbstractRepository<HospitalReservationList> {
}
and
#Component
#Path("/hospitalreservationlist")
public class HospitalReservationListEndpoint extends
AbstractEndpoint<HospitalReservationList> {
}
The easy way is to add Repository as a Generic parameter like this:
public abstract class AbstractEndpoint<T,R extends AbstractRepository<T>> {
#Autowired
protected R repository;
...
I hope there is a better way to do this, if you can find one please comment it here.

Dynamically create Spring beans that extend an abstract class with parameterized types

I would like to take advantage of Spring 4.0's support for autowiring of generic types but I would like to avoid having to create explicit concrete or anonymous classes for each type. To use an example, lets say I have an interface:
public interface Cache<T extends Entity>
And an abstract implementation of the interface:
public abstract class AbstractCache<T extends Entity> implements Cache<T>
{
#Autowired
private EntityDao<T> dao;
#Autowired
private List<CacheListener<T>> listeners;
...
}
And entity classes A to Z that implement Entity (e.g):
public class A implements Entity
public class B implements Entity
...
public class Z implements Entity
Is there a way I can create instances of Cache<A> through Cache<Z> such that I can autowire these generic types in other classes? E.g.
#Autowire
private Cache<Z> zCache;
I know I can achieve this by individually defining each bean, E.g.
#Bean
public Cache<Z> cacheZ() {
return new AbstractCache<Z> () {};
}
But I have been unable to come up with a way to do this for all Entity classes in a particular package. E.g.
public void registerEntityCaches (BeanFactory beanFactory) {
for (Class<? extends Entity> cls : entityPackage.getAllClasses()) {
beanFactory.registerBean(new AbstractCache<cls>() {});
}
}
Is something like this possible or do I have to define them individually?

Injection of autowired dependencies failed for abstract class

I am using Spring 3 and Hibernate 4
I have the following class structure
public interface GenericDAO<T> {
public void create(T entity);
public void update(T entity);
public void delete(T entity);
}
DAO class
public interface EmployeeDAO extends GenericDAO<Employee> {
public void findEmployee(EmployeeQueryData data);
}
DAO Implementation class
#Repository("employeeDAO")
public abstract class EmployeeDAOImpl implements EmployeeDAO {
protected EntityManager entityManager;
#Override
public void findEmployee(EmployeeQueryData data) {
...... code
}
The problem I am facing is when I try to deploy, I am getting the following exception.
If I remove abstract from EmployeeDAOImpl and remove extends GenericDAO<Employee> from EmployeeDAO then application gets deployed without errors. So it is not possible to have abstract class for EmployeeDAOImpl or I have need to implement all methods of GenericDAO in DAO implementation without abstract?
Error creating bean with
name 'employeeService': Injection of autowired dependencies failed; \
nested exception is org.springframework.beans.factory.BeanCreationException:
Could not autowire field: test.dao.EmployeeDAO
test.service.EmployeeServiceImpl.employeeDAO; nested exception is
org.springframework.beans.factory.NoSuchBeanDefinitionException:
No matching bean of type [test.dao.EmployeeDAO] found for dependency:
expected at least 1 bean which qualifies as autowire candidate for
this dependency. Dependency annotations:
{#javax.inject.Inject()}.
Edit 1
GenericDAOImpl
public class GenericDAOImpl<T> implements GenericDAO<T> {
public void create(T entity) {
}
public void update(T entity) {
}
public void delete(T entity) {
}
EmployeeDAOImpl
public class EmployeeDAOImpl extends GenericDAOImpl<Employee> implements EmployeeDAO {
Java (and consequently Spring) cannot create instances of abstract classes: every method must have an implementation before Java will let you create an instance, otherwise you would get a runtime error when you tried to call the method. You need to remove "abstract" from EmployeeDAOImpl and implement the methods inherited from GenericDAO.
Why do you want to declare a class implementation as abstract? Conceptually it's a contradiction. Obviously Spring cannot instantiate it and fails.
Confirm if your EmployeeDAOImpl or other annotated class packages are mentioned in spring context xml in following tag. Unless this is done, annotations won't get read and will not be initialized.
<context:component-scan base-package="com.app.service" />

Categories