need help on understand why my customized repository work - spring-boot

I have customized repository to include query methods and customized method. I get it working as blow.
public interface UserRepository extends ElasticsearchRepository<User, String>{
query_method_A();
query_method_B();
My_customized_method();
}
public class UserRepositoryImpl{
My_customized_method(){
//my real implementation
}
}
I don't need to add any annotation. Spring creates two beans.
userRepository : class com.sun.proxy.$Proxy150
userRepositoryImpl : class com.*.repository.impl.userRepositoryImpl
UserRepositoryImpl can't have implements UserRepository , otherwise it complains that it needs to implement those query methods. It works fine.
I was reading a document about Customizing Individual Repositories https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.single-repository-behavior
It seems that the correct way is to use a fragment repository like below. No annotation is needed. Tested and worked.
public interface UserRepository extends ElasticsearchRepository<User, String>, MyTestRepository
{
query_method_A();
query_method_B();
}
public interface MyTestRepository {
My_customized_method();
}
public class MyTestRepositoryImpl implements MyTestRepository {
My_customized_method(){
//my real implementation
}
}
My question is why does my first custom repository work? It seems more convenient to use though since I only need one Impl class per repository.

Related

How to configure spring JpaRepository to be one of the implementations of an interface

Hello I'm working on a task where based on configuration I need to use either a custom implementation of a repository that uses an api to fetch data or a normal repository that extends a JpaRepository.
So something like this:
public interface PersonRepository {
Person findPersonById(Long id);
}
and the possible implementations for that would be:
public interface PersonDatabaseRepository extends PagingAndSortingRepository<Person, Long>, JpaSpecificationExecutor<Person>{
Person findPersonById(Long id);
}
public class PersonApiRepository extends implements PersonRepository {
public Person findPersonById(Long id) {
return someApiClient.findPersonById(id);
}
}
Is that possible? I know I could add another interface in the upper layer where the implementations would use either PersonDatabaseRepository or PersonApiRepository inside but I was wondering if it would be possible to skip that

Deprecated QuerydslJpaReposiotry does not work anymore

I have a custom repository that needs the functionality of Querydsl as well as PagingAndSortingRepository. Till now my custom repository was like
#NoRepositoryBean
public interface CustomPagingSortingQuerydslRepository<T, ID> extends PagingAndSortingRepository<T, ID>, QuerydslPredicateExecutor<T> {
// Overriden methods
}
public class CustomPagingSortingQuerydslRepositoryImpl<T, ID extends Serializable> extends QuerydslJpaRepository<T, ID> implements CustomPagingSortingQuerydslRepository<T, ID> {
// Overriden implementations of methods defined in the interface
}
The great thing about this was that my custom implementation was not very different from the default implementation provided by QuerydslJpaRepository and thus I would use the super class methods with some modifications in mine like
public class CustomPagingSortingQuerydslRepositoryImpl<T, ID extends Serializable> extends QuerydslJpaRepository<T, ID> implements CustomPagingSortingQuerydslRepository<T, ID> {
#Override
#NonNull
public Optional<T> findOne(#NonNull Predicate predicate) {
return super.findOne(modifierMethod(predicate));
}
#Override
#NonNull
public <U extends T> U save(#NonNull U entity) {
return super.save(otherModifierMethod(entity, false));
}
#Override
#NonNull
public <S extends T> S saveCustom(#NonNull S entity) {
return super.save(otherModifierMethod(entity, false));
}
}
Note that I also have a saveCustom defined by me in the custom interface and I am providing its implementation with the help of the parent class.
This worked great but after Spring Boot 2.1, QuerydslJpaRepository has been deprecated in favour of QuerydslJpaPredicateExecutor. Now this class does not provide implementations of save or delete and thus I cannot use the SimpleJpaRepository methods if my implementation class inherits from QuerydslJpaPredicateExecutor.
In short, I need to reimpelement query and save/delete methods in my custom repository along with some custom methods of mine and I don't want to implement them from scratch. The current deprecation means my implementation can extend either from QuerydslJpaPredicateExecutor which provides implementation of query methods only or from SimpleJpaRepository which means I lose the functionality of querydsl in my implementation.
What I've done till now
To work around this I have created 2 repositories
#NoRepositoryBean
public interface CustomPagingSortingRepository<T, ID> extends PagingAndSortingRepository<T, ID> {
// Only overrides save and delete type of methods and includes my customSave method
#NoRepositoryBean
public interface CustomQuerydslRepository<T, ID> extends QuerydslPredicateExecutor<T> {
// Overrides all methods of the superclass and includes any custom methods of mine
}
and I have implemented them separately like
#NoRepositoryBean
public class CustomPagingSortingRepositoryImpl<T, ID extends Serializable> extends SimpleJpaRepository<T, ID> implements CustomPagingSortingRepository<T, ID> {
// Implements all the methods of the interface using the parent class methods
}
#NoRepositoryBean
public class CustomQuerydslRepositoryImpl<T, ID extends Serializable> extends QuerydslJpaPredicateExecutor<T> implements CustomQuerydslRepository<T, ID> {
// Implements all the methods of the interface using the parent class methods
}
and I inherit these 2 interfaces into my custom interface
#NoRepositoryBean
public interface CustomPagingSortingQuerydslRepository<T, ID> extends CustomPagingSortingRepository<T,ID>,CustomQuerydslRepository<T, ID> {
}
I thought this would work but this throws a type error which on close inspection I found to be because Spring is trying to create an implementation of customSave by itself and since it doesn't understand what this method has to do, it throws an error.
I am really in a fix now since the deprecated way was extremely clean and I don't want to implement half a dozen Beans for this to work.
P.S.
I have been thinking using Composition instead of Inheritance to get a handle to SimpleJpaRepository and QuerydslJpaPredicateExecutor and use the methods in them that way but I have a feeling this is going to be against injection and a bad practice.

Custom delete method in JpaRepository

I'd like to know if there's a way of overriding the delete method for some of my JpaRepository's without having to override the rest of the methods.
Currently I have something like
public interface UserRepo extends JpaRepository<User, Long>
{
findUserById(long id);
findUserByEmail(String email);
// etc...
}
And I'd like to override the delete(T Entity) method in CrudRepository. To do so I've tried implementing the UserRepo but then I have to implement all the findByX and haven't really find anything around on how to properly do that.
Is there any annotation to add to a function in the Entity class so it runs when you call UserRepo.delete(myUser)?
Thanks in advance!
Not sure I understand you clear enough, but lets try:
... I have to implement all the findByX ...
You don't, spring will generate JPQL snippet if you name methods in your interface with suitable convection please take a look at this and this articles
... Is there any annotation to add to a function in the Entity class
so it runs when you call UserRepo.delete(myUser)? ...
You can use #PreRemove / #PostRemove annotation on method in your entity class:
#PreRemove / #PostRemove
public void someMethod() { ... }
In addition to Raheela Aslam post:
Spring-data documentation has an example of how you can override standard repository methods, for example:
interface CustomizedSave<T> {
<S extends T> S save(S entity);
}
class CustomizedSaveImpl<T> implements CustomizedSave<T> {
public <S extends T> S save(S entity) {
// Your custom implementation
}
}
interface UserRepository extends CrudRepository<User, Long>, CustomizedSave<User> {
}
You can read about it there:
https://docs.spring.io/spring-data/jpa/docs/2.1.2.RELEASE/reference/html/#repositories.custom-implementations
UPD:
Read it carefully, because there are some important things, e.g
The most important part of the class name that corresponds to the fragment interface is the Impl postfix.
Also the documentation says:
Custom implementations have a higher priority than the base implementation and repository aspects.
If you want to keep Spring's behavior for deletion, but want to have some logic to be executed either before or after, you may utilize java8's interface default methods, and try the following :
public interface UserRepo extends JpaRepository<User, Long> {
default void customDelete(User user) {
// before logic
// ..
delete(user); // actual call to deletion
// after logic
// ..
}
}
There are several ways to do this depending on what you're trying to do:
Use method naming, and let Spring derive the JPQL query from the naming (https://www.petrikainulainen.net/programming/spring-framework/spring-data-jpa-tutorial-creating-database-queries-from-method-names/)
Use the Query annotation and add the desired JPQL query in the annotation (https://www.petrikainulainen.net/programming/spring-framework/spring-data-jpa-tutorial-creating-database-queries-with-the-query-annotation/)
Use a named query (https://www.petrikainulainen.net/programming/spring-framework/spring-data-jpa-tutorial-creating-database-queries-with-named-queries/)
I prefer to use method naming if possible, the method name gets long, but you know exactly what it does by looking at it.
In your case code will be like as below:
public interface UserRepo extends JpaRepository<User, Long>
{
findUserById(long id);
findUserByEmail(String email);
// etc...
}
public interface UserRepositoryCustom {
void deleteByEmail(String email);
}
public interface UserRepositoryImpl implements UserRepositoryCustom {
public void deleteByEmail(String email) {
//provide your custom implimentation
}
}
Hi you can write your own Interface write implementation with EntityManager and
extend in you interface here is the sample :
https://dzone.com/articles/accessing-the-entitymanager-from-spring-data-jpa
Actually one more way is writing by soemthing like :
User findByUsername(String username) // it will find the user by specific username
spring data will create you an implementation of this method
The same way you can create your own delete method
Here is useful links:
https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.custom-implementations
In this link you can go to part 2.3 QueryMethods:
https://docs.spring.io/spring-data/jpa/docs/1.6.0.RELEASE/reference/html/jpa.repositories.html
You can also define #NameQuery in your entity class:
#Entity
#Table(name = "employee", schema="spring_data_jpa_example")
#NamedQuery(name = "Employee.yourMethodQueryName",
query = "yourQuery"
)
public class Employee {}
#Repository
public interface EmployeeRepository extends JpaRepository<Employee,Long> {
List<Employee> yourMethodQueryName(Your list of params);
}
Here is link with sample:
https://www.logicbig.com/tutorials/spring-framework/spring-data/jpa-named-queries.html
I think this is helpful for you
public interface UserRepo extends JpaRepository<User, Long> {
#Modifying
#Query("delete from User u where u.email = ?1")
void deleteByEmail(String email);
}

Spring Boot detects 2 identical repository beans

I am using Spring Boot with Spring Data JPA, there is only one #SpringBootApplication. And I have also a repository classes, for example:
package com.so;
public interface SORepository {
//methods
}
And impl
#Repository("qualifier")
#Transactional(readOnly = true)
public class SORepositoryImpl implements SORepository {
//methods
}
The proplem is, when I start the application, I get following error:
Parameter 0 of constructor in com.so.SomeComponent required a single bean, but 2 were found:
- qualifier: defined in file [path\to\SORepositoryImpl.class]
- soRepositoryImpl: defined in file [path\to\SORepositoryImpl.class]
So, as you see, somehow 2 beans of one repository class are created. How can I fix this?
You can use Spring Data JPA methods having created Proxy element and than inject it into public class SORepositoryImpl:
public interface Proxy() extends JpaRepository<Element, Long>{
Element saveElement (Element element); //ore other methods if you want}
And than:
#Repository
#Transactional(readOnly = true)
public class SORepositoryImpl implements SORepository {
#Autowired
private Proxy proxy;
//end realisation of methods from interface SORepository
}
Try taking the #Repository annotation off the SORepositoryImpl class
e.g.
#Transactional(readOnly = true)
public class SORepositoryImpl implements SORepository {
//methods
}
The error message is implying you have two beans, one named "qualifier" and one named "soRepositoryImpl", which is probably in a Config class.
I guess you should share your SomeComponent class supposing you have no extra configuration class/xml. My take is that you are injecting as 'soRepositoryImpl' there where you have defined as 'qualifier'. Having two options them. I would say to just remove the annotation parameter 'qualifier' and it should work.
Moreover, unless you want do specify an custom DAO implementation you can avoid #Repository at all (That's an annotation you use to make it injectable for your services). You can just create an interface extending Spring interface and define methods for queries.
For example:
public interface PersonRepository extends Repository<User, Long> {
List<Person> findByEmailAddressAndLastname(EmailAddress emailAddress, String lastname);
Then you can just inject it in your services/controller directly.
private final PersonRepository personRepository;
public PersonController(final PersonRepository personRepository) {
this.personRepository = personRepository;
}
check samples:
https://spring.io/guides/gs/accessing-data-jpa/
http://docs.spring.io/spring-data/data-commons/docs/1.6.1.RELEASE/reference/html/repositories.html
OK, I've found the issue.
I just couldn't understand, how Spring creates the second bean (soRepositoryImpl), because I've never told it, neither explicitly nor in config classes. But I figured out that the second bean us created during the instantiation of my another SORepository (which is in the different package com.another and which extends JpaRepository).
So, when Spring tries to resolve all dependencies of com.another.SORepository it somehow finds my com.so.SORepositoryImpl (which has nothing familiar with com.another.SORepository - not extending\implementing, not jpa stuff, only similar names!).
Well it seems like a Spring bug to me, because it doesn't check the real inheritance of dependent classes of repositories, only name + Impl (even in different package) suits for him.
The only thing that I should do is to rename `com.so.SORepositoryImpl and that it, no 2 beans anymore.
Thanks everyone for answers!

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