spring data - get beans in a custom default repository implementation - spring

Im trying to upgrade my project from spring-boot-1.4.3.RELEASE to spring-boot-1.5.9.RELEASE.
In the 1.4.3.RELEASE the way I have used my custom implementation of repositories is as follow:
Made an interface MyCustomRepositroy that extends JpaRepository
Had a class MyCustomRepositoryImpl that implements MyCustomRepositroy and SimpleJpaRepository. In that class I have changed the behavior of
the of save, find and delete methods, because I needed a
ceratin behavior for entitys of certain type (lets say that I need a
custom save for all entitys that implements Special interface)
I made a MyCustomJpaRepositoryFactoryBean that extends JpaRepositoryFactoryBean. In that factory, I've overridden createRepositoryFactory and gave it my MyRepositoryFactory implementation.
In MyRepositoryFactory implementation I've overridden the getTargetRepository, and getRepositoryBaseClass.In these methods, I check if the entity is of type Special, and if so, I return MyCustomRepositoryImpl, otherwise I return SimpleJpaRepository.
Also, I can get the beanFactory in my MyCustomRepositoryImpl class because I call my own constructor of MyCustomRepositoryImpl that has also a beanFactory parameter via getTargetRepositoryViaReflection.
Now, with the new version (that uses spring-data-commons-1.13.9.RELEASE), I cannot override the Factory class, and hence can't decide for each entitiy which implementation to give, and have no way to get the beanFactory.
Is there any way I can get what I want?
Sorry for the mess, but I cannot post my code here.
P.S - my project is a spring based library, so I can't do anything to the entitys because my clients declare them, all I know that some entitys implement the Special interface and some don't

I am trying to figure out what happened in 1.5.9.RELEASE, but in the meantime, just as a fyi - 1.5.6.RELEASE works ok.
I am having the same issue when trying to update from 1.5.6.RELEASE to 1.5.9.RELEASE

Related

Is it possible to override abstract beans in Spring?

I'm trying to override this bean which is provided by standard Hybris (OOTB) framework. I would love to override it so it uses my own custom class. Is this possible?
You can create new extended abstract class but it is not used by existing classes. You can use customize functionality to overwrite class and/or spring config. Bu you must careful during patching or updating system.
How to override hybris platform files other than customize
Do you want to inject a custom implementation for one of the properties mapped to the abstract bean definition or do you want the abstract bean to use a custom class that you provide?
The latter just doesnt work, because you would also break all configurations of implementing beans.
You should seek for all beans that use this abstract bean as a parent and think, which of those you want to change and change that. Most likely, those beans will have an alias defined that you can use to change it. :-)
Best Bechte

where does jpa picks up the method userbyusername as i have not given any implementation and i have checked the inner classes too

In my spring boot project, I am using this starter jpa . i have done all the db related thing in appliction.properties. Project is working fine . I fail to undestand where is this methods defination. We have just defined a abstract method how is this method even working?
public interface UserRepository extends JpaRepository<UserEntity, Integer>{
Optional<UserEntity> getUserByUserName(String user);
}
This is part of the magic of JPA Repositories. I don't actually know the details of how it works either, I just know how to use it.
Ultimately, I think it has to do with how Spring proxies interfaces. Spring will create an instance of an interface at runtime. When the methods are named according to the specs, Spring can generate an appropriate method.
Here is a good article that goes into detail on how you can construct the method names to make the query that you want: https://www.baeldung.com/spring-data-derived-queries.

Adding new DB support in spring data

Currently spring data has multiple db support (mysql, cassandra, mongo.. very big list), however i want to add my custom repository from the scratch like adding custom db support in spring data. I don't want to extend any existing repositories, instead I want to create a parallel repository strutcutre for my custom datasource. Looking at current implementation it looks like tedious task. It would be a great if someone could help me with minimal requirement to do this.
You could create a repository annotated bean where you would inject EntityManager or the proper bean that is acting like that, depending on database type that you are using.
#Repository
public class MyCustomRepositoryImpl implements MyCustomRepository {
#Autowired
private EntityManager entityManager;
//the methods that you are going to create.
}
For more details see:
https://docs.spring.io/spring-data/data-commons/docs/1.6.1.RELEASE/reference/html/repositories.html
Chapter: 1.3 Custom implementations for Spring Data repositories

Spring fallback bean implementation

I'm currently trying to configure Spring Boot (using Java Annotations and ComponentScan) for the following scenario:
Scenario
There's an interface MyService.
I want to provide a default implementation for MyService, let's call it MyDefaultService.
If the component scan detects no other implementation for MyService, Spring should instantiate MyDefaultService as a "fallback".
If there is a different implementation of MyService present, let's say MyCustomService, then that bean should always take precedence over MyDefaultService when autowiring a dependency to MyService. In that regard, MyDefaultService should be recessive (as opposed to #Primary).
Ideally, there should not need to be an additional annotation on MyCustomService to have it "override" MyDefaultService.
Ideally, no explicitly implemented factories or factory methods should be required.
Question
The question is: how do I need to annotate the MyDefaultService class in order to achieve this?
What I tried so far to solve the problem
Annotating MyDefaultService with #ConditionalOnMissingBean(MyService.class). Didn't work because MyDefaultService is never used, even if there is no other implementation of MyService.
There is an annotation called #Primarythat solves the problem. However, it needs to reside on MyCustomService, a class that I try to keep free of additional annotations. Essentially, I need the inverse annotation of #Primary on MyDefaultService. However, I couldn't find such an annotation.
Concrete use case
I am developing a service layer in one project, and a different project will implement a web UI layer on top of it. The UI project has a dependency to the service layer project. However, for certain functionalities implemented at the service layer, I need to know which user is currently logged in at the web context. So I have to define a service interface for that in the service layer project, such that it can be implemented by the UI project. However, for testing purposes in the service-layer project, I need a default implementation of that interface. Also, in case that the UI project team forgets to implement this interface, the app should not crash, but instead instantiate the fallback bean and issue a warning.
Thanks & kind regards,
Alan
I suggest writing an implementation of FactoryBean to do this. Your FactoryBean would scan the bean factory looking for beans that implement MyService, and if it finds one it returns that bean from getObject. If it doesn't, then it can instantiate MyDefaultService directly and return that. Your factory bean then gets annotated with #Primary.
So pieces like this (pseudo-code):
public class MyServiceFactory implements FactoryBean<MyService> {
ListableBeanFactory beanFactory;
public MyService getObject() {
Map beans = beanFactory.getBeansOfType(MyService.class)
if (beans.isEmpty())
return new MyDefaultService(); // plus args, obviously
else
return get_some_bean_from_the_map
}
}
and then
#Primary
#Bean
public MyServiceFactory MyServiceFactory() {
return new MyServiceFactory();
}
Spring will automatically handle the factory bean (i.e. it will make the MyService object available as a bean for injection like normal.
This solution doesn't require any special magic, and it's fairly obvious how it works. You can also handle errant cases such as multiple MyService beans being declared.

Scenario when we may be needing #Configurable in spring?

I have question about the need of using #configurable. I have gone through the blog that explains how to use #configurable. But the question that comes to my mind is, what can be the scenario when we need to use #configurable. I can think of two scenarios where it can be useful
In a legacy project, when we are already making any bean with new operator and we want to make it spring managed.
In a new project, we want to enforce that even if developer makes the bean with new operator, still it is spring managed.
Otherwise for new beans we can always declare them in applicationContext.xml and I do not see any need to declare them #configurable.
Please let me know if above understanding is correct or if I am missing something.
UPDATE:- Basically as per my understanding configurable is generally used to inject dependency when creating the object with new operator. But why would i be creating the object with new operator when i am using spring
#Configurable annotation is meant for injecting dependencies in domain-driven applications. That means, in such applications, the domain objects interact with each other to perform a certain operation.
Take the following example:
In an invoicing application, the Invoice class provides a constructor to create it, then it has methods to validate, and finally persist it. Now, to persist the invoice, you need a DAO implementation available within the invoice. This is a dependency you would like to be injected or located. With Spring's #Configurable, whenever an invoice is created using the new operator, the appropriate DAO implementation will get injected and can be used for all persist operations.
I had a more realtime scenario where I used #Configurable annotation as described here.

Resources