Using #Query witouht extends from JpaRepository - spring-boot

I am trying to execute system request using #Query. So, I do not have to extends JpaRepository and create an entity for no purpose.
I get this error:
Field myDAO in myPackage.impl.MyService required a bean of type 'myPackage.dao.MyDAO' that could not be found.
At MyService, I autowired MyDAO.
public class MyService implements IMyService {
#Autowired
private MyDAO myDAO;
#Override
public List<String> getAllTablesName() {
return myDAO.getAllTablesName();
}
}
I try to add #Repository but nothing is changed
#Repository
public interface MyService{
#Query(value ="SHOW TABLES FROM :tableName",nativeQuery = true)
public List<String> getAllTablesName(#Param("tableName") String tableName);
}
How can I solve this problem ?

While you do not have to extend JpaRepository you'll at least have to extend Repository
If you really don't have an entity you probably shouldn't use JPA in the first place which is all about mapping entities to database tables.
If you just want to execute statements a better fit might be a simple class with an injected JdbcTemplate or NamedParameterJdbcTemplate.

Related

SpringBoot Bean dependency injection with annotation #Primary and #Secondary

I have a repository interface and two classes implementing it, one is cache repository and the other is MongoDB repository.
public interface Repository {}
#Primary
#Component
public class CacheRepo implement Repository {}
#Component
public class MongoDBRepo implement Repository {}
The ideal process for fetching an item would be to check if it exists in the cache using cache repo and if not, go with MongoDB repo, I have a #Primary on my CacheRepo class, and dependency inject Repository interface in my service, but how could I still use the same injected instance as MongoDBRepo if item not found in Cache? Is there something like #Secondary annotation?
What you are trying to implement is Repository Pattern
Here is a simple way to implement it
public interface MyRepository {
Optional<MyClass> findById(Long id);
}
Then you will have 3 implementations. This is where the logic lies.
#Repository
#Qualifier("db")
public interface MyDbRepository extends MyRepository, CrudRepository<MyClass, Long>{
}
#Component
#Qualifier("cache")
public class MyCacheRepository implements MyRepository {
public Optional<MyClass> findById(Long id){
return Optional.empty();
}
}
// This is the key
#Component
#Primary
public class MyDataSource implements MyRepository {
#Autowire
#Qualifier("db")
private MyRepository dbRepo;
#Autowire
#Qualifier("cache")
private MyRepository cacheRepo;
public Optional<MyClass> findById(Long id){
Optional<MyClass> myResponse = cacheRepo.findById(id);
if(myResponse.isPresent()){
return myResponse;
} else {
myResponse = dbRepo.findById(id);
if(myResponse.isPresent){
// Update your cache here
}
return myResponse;
}
}
}
I would suggest you take a look at #Qualifier. With it, you can specify which Bean you want to inject. For that, the best option is to define a component name for each bean as follows:
public interface Repository {}
#Component("cache")
public class CacheRepo implement Repository {}
#Component("mongodb")
public class MongoDBRepo implement Repository {}
Then, in another Spring-managed bean you can specify the implementation as follows:
#Autowired
#Qualifier("mongodb")
private Repository mongoRepo;
You can read more about it at https://www.baeldung.com/spring-qualifier-annotation.
I think you misunderstood the purpose of #Primary.
As the documentation says:
Indicates that a bean should be given preference when multiple candidates are qualified to autowire a single-valued dependency. If exactly one 'primary' bean exists among the candidates, it will be the autowired value.
You may use #Cacheble annotation on the MongoDBRepo's methods to do what you want and define a custom cache manager to use your CacheRepo
Here is a useful introduction to #Cacheble with some examples https://www.baeldung.com/spring-cache-tutorial

when I create my rest service in spring and mysql generates a table instead of consuming the one I have

I am creating a repository:
#Repository
public interface UserRepository extends JpaRepository<UserRest, String>{
}
and I create a UserResourceTest rest controller:
#RestController
public class UserRestResource {
#Autowired
private UserRepository userRepository;
#GetMapping("/userrest")
public List<UserRest> userAll() {
return userRepository.findAll();
}
}
This generates two classes {user_rest, hibernate_sequence}.
instead of consuming userrest.
Can someone help me what am I doing wrong?
Add in model class UserRest annotation #Table parameter name = userrest
#Entity
#Table(name = "userrest")
public class UserRest
Check out Hibernate: Automatically creating/updating the db tables based on entity classes and How to turn off hbm2ddl?
And change your persistence.xml or config class accordingly! (hibernate.hbm2ddl.auto should be none)

How to autowire SimpleJpaRepository in a spring boot application?

I'm working on a project that uses SpringBoot 2.0.5 version, Spring Data JPA to persists and retrieve records using JPA. I autowired SimpleJpaRepository in the service layer. But while starting my application, it failed with
"NoSuchBeanDefinitionException"- No qualifying bean of type
'org.springframework.data.jpa.repository.support.SimpleJpaRepository<?, ?>'
available: expected at least 1 bean which qualifies as autowire candidate.
My controller, service and DAO are like below
Controller class:
#Controller
public class MyController{
#Autowired
private MyService<Person,PersonPK> service;
Service layer as
public interface MyService<V,K>{
methods defined
}
#Service("service")
public class MyServiceImpl<V,K> implements MyService<V,K>{
#Autowired
private SimpleJpaRepository<V,K> repository; // This dependency is failing
}
Application as :
#SpringBootApplication (exclude = {SecurityAutoConfiguration.class})
#EnableJpaRepositories
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}
Is my approach incorrect? Is that not the correct way of autowiring the SimpleJpaRepository.
There is no need for me to extend SimpleJpaRepository as Spring provided JPARepository is good for me, for now.
Thanks
You still need to create a repository interface that extends JpaRepisitory, or the spring repository type of your choice.
To quote the spring data documentation:
1.2.1 Defining repository interfaces
As a first step you define a domain class-specific repository interface. The interface must extend
Repository and be typed to the domain class and an ID type. If you
want to expose CRUD methods for that domain type, extend
CrudRepository instead of Repository.
Once you do create a new repository type, you will autowire by that type rather than the SimpleJpaRepository.
One way to get an implementation of the SimpleJpaRepository is by using a Configuration class to create an instance as a bean that you will use inside your service.
#Configuration
public class PersistanceConfiguration {
#PersistenceContext
private EntityManager entityManager;
#Bean
public SimpleJpaRepository<YourEntity, Long> getYourEntitySimpleRepository() {
return new SimpleJpaRepository<>(YourEntity.class, entityManager);
}
}
And inject it to your service as you would do with a JpaRepository, for example:
#Service
public class YourEntityServiceImpl<YourEntity, Long> implements YourEntityService {
private JpaRepository<YourEntity, K> repository;
private SimpleJpaRepository<YourEntity, K> simpleRepository;
#Autowired
public YourEntityServiceImpl(YourEntityRepository repository, SimpleJpaRepository<YourEntity, Long> simpleRepository) {
this.repository = repository;
this.simpleRepository = simpleRepository;
}
}
You should create a repository interface that extending JpaRepisitory.
#Repository
public interface MyRepository extends JpaRepisitory<T, ID> {
//
}
And the you should Autowired in your service class.
#Service("service")
public class MyServiceImpl<V,K> implements MyService<V,K>{
#Autowired
private MyRepository myRepository;
}

How to do inheritance in Dao layer?

I am working with SpringMVC+Hibernate, I want to apply Inheritance in DAO layer, I am doing like below:
BaseDao.java
public interface BaseDao
{
public Serializable save(Object object) throws DataAccessException,
HibernateException;
public void merge(Object object) throws DataAccessException,
HibernateException;
public void flush() throws DataAccessException,HibernateException;
}
EmpDao.java
public interface EmpDao extends BaseDao{
}
BaseDaoImpl.java
#Repository
public class BaseDaoImpl implements BaseDao{
// Implementation for baseDao methods
}
EmpDaoImpl .java
#Repository
public class EmpDaoImpl extends BaseDaoImpl implements EmpDao{
// Implementation
}
But I am getting below error:
org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type
[BaseDao] is defined: expected single matching bean but found 2
What am I missing here?
If you really want to have both BaseDaoImpl and EmpDaoImpl as two beans in your Spring container, you need to tell Spring which one to use wherever you have an #Autowired field of type BaseDao using #Qualifier annotation.
Related: Understanding Spring #Autowired usage
It seems like you're trying to inject BaseDao and Spring is complaining there are two candidates.
I think this is actually a design problem. You wanted to use BaseDaoImpl both as a concrete bean that you use directly and also as a base class for other DAOs. This is bad because the sub-classes does not actually extend but simply uses their parent class. The better pattern would be to get rid of the extends and simply inject the BaseDaoImpl into the other DAOs.
Also, the interfaces looks superfluous. If you're working around the proxy problem, just use proxyTargetClass.
You can use generic types like this
BaseDao.java
public interface BaseDao<EntityType extends Object>
{
public Serializable save(EntityType entity) throws DataAccessException,
HibernateException;
public void merge(EntityType entity) throws DataAccessException,
HibernateException;
public void flush() throws DataAccessException,HibernateException;
}
BaseDaoImpl.java
#Repository
public abstract class BaseDaoImpl<EntityType extends Object> implements BaseDao<EntityType>{
// Implementation for baseDao methods
}
EmpDao.java
public interface EmpDao extends BaseDao<Employee>{
}
EmpDaoImpl .java
#Repository
public class EmpDaoImpl extends BaseDaoImpl<Employee> implements EmpDao{
// Implementation
}
You need to add the #NoRepositoryBean on the BaseDao interface so spring would not create a bean for it, as well as for EmpDao I assume

How to access entity manager with spring boot and spring data

How can I get access to the Entity Manager in the repository when using Spring Boot and Spring Data?
Otherwise, I will need to put my big query in an annotation. I would prefer to have something more clear than a long text.
You would define a CustomRepository to handle such scenarios. Consider you have CustomerRepository which extends the default spring data JPA interface JPARepository<Customer,Long>
Create a new interface CustomCustomerRepository with a custom method signature.
public interface CustomCustomerRepository {
public void customMethod();
}
Extend CustomerRepository interface using CustomCustomerRepository
public interface CustomerRepository extends JpaRepository<Customer, Long>, CustomCustomerRepository{
}
Create an implementation class named CustomerRepositoryImpl which implements CustomerRepository. Here you can inject the EntityManager using the #PersistentContext. Naming conventions matter here.
public class CustomCustomerRepositoryImpl implements CustomCustomerRepository {
#PersistenceContext
private EntityManager em;
#Override
public void customMethod() {
}
}
In case you have many repositories to deal with, and your need in EntityManager is not specific for any particular repository, it is possible to implement various EntityManager functionality in a single helper class, maybe something like that:
#Service
public class RepositoryHelper {
#PersistenceContext
private EntityManager em;
#Transactional
public <E, R> R refreshAndUse(
E entity,
Function<E, R> usageFunction) {
em.refresh(entity);
return usageFunction.apply(entity);
}
}
The refreshAndUse method here is a sample method to consume a detached entity instance, perform a refresh for it and return a result of a custom function to be applied to the refreshed entity in a declarative transaction context. And you can add other methods too, including query ones...

Resources