Spring Boot Common JPA repository class - java

I have a number of JPA repositories classes and I want to create one common class where I will create a getter method of a respective repository and I will use that common class in the service layer.
So Can you please guide me with best practices that how can I achieve this?
Here I am sharing my idea by using sample code,
JPA repository
#Repository
public interface IConfigRepository extends JpaRepository<Config, Integer> {
}
public interface IBusinessRepository extends JpaRepository<Business, Integer> {
}
Repo Factory (Common Class for all repositories)
public class RepoFactory {
#Autowired
private IConfigRepository configRepo;
#Autowired
private IBusinessRepository businessRepo;
public IConfigRepository getConfigRepository() {
return configRepo;
}
public IBusinessRepository getBusinessRepository() {
return businessRepo;
}
}
Service Class
#Service
public class ServiceA {
public final RepoFactory repoFactory;
public ServiceA(RepoFactory repoFactory) {
this.repoFactory = repoFactory
}
#Transactional(rollbackOn = Exception.class)
public void saveOrUpdate(Config config) {
repoFactory.getConfigRepository().save(config);
}
}
#Service
public class ServiceB {
public final RepoFactory repoFactory;
public ServiceB(RepoFactory repoFactory) {
this.repoFactory = repoFactory
}
#Transactional(rollbackOn = Exception.class)
public void saveOrUpdate(Business reqBusiness) {
repoFactory.getBusinessRepository().save(reqBusiness);
}
}
Thanks, everyone for helping me in advance.

It looks like, you're trying to do something the #Profile annotation can help you with. If I were you, I would keep a common interface (not class) and make the IConfigRepository extend it. Then you can mark IConfigRepository with the #Profile annotation. If in the future, you have to write an analogue interface, you should also mark it with the #Profile annotation and you can switch between these interfaces anytime you want by setting the appropriate profile to active.
#Repository
#Profile("config")
public interface IConfigRepository extends CommonRepository, JpaRepository<Config,Integer> {
}
public interface CommonRepository {
}
#Service
public class ServiceA {
public final CommonRepository commonRepository;
public ServiceA(CommonRepository commonRepository) {
this.commonRepository = commonRepository
}
...
}

Related

How to automatically inject implementation based on Generics

I have a Service class defined like this,
#RequiredArgsConstructor
class SomeService<T extends AbstractResponse> {
private final ValidationService<T> validationService;
....
}
And I have two kinds of AbstractResponse, ResponseA and ResponseB and have a validation service defined for both of them.
#Service("aValidationService");
class AValidationService<ResponseA> implements ValidationService<ResponseA> {
....
}
and
#Service("ValidationService");
class BValidationService<ResponseB> implements ValidationService<ResponseB> {
....
}
Right now spring is throwing an error because it's not able to deduce the implementation of ValidationService to use in SomeService as there are two implementations of it. How do I make spring deduce the correct implementation based on the type of AbstractResponse?
Hope that I understood your requirements.
You can not automatically inject, when you have (2) of the same kind. In this case ValidationService.
You could inject #ValidationServiceA, or #ValidationServiceB, or a List<ValidationServiceI> and then return the one you want based on a <T> type you care about:
The solution below highlights that.
The method getGenericParameter() is used to return the <T> parameter. This is to avoid the use of Reflection.
The method methodWhichDeterminesWhichServiceToUseBasedOnResponseType to used to determine which ValidationService to use based on the input that you require.
You can find the complete solution below, including a verification Test.
import org.springframework.stereotype.Service;
#Service
public class ValidationServiceA implements ValidationServiceI<ResponseA>{
#Override public Class<ResponseA> getGenericParameter() {
return ResponseA.class;
}
public void print(){
System.out.println("Service A");
}
}
#Service
public class ValidationServiceB implements ValidationServiceI<ResponseB>{
#Override public Class<ResponseB> getGenericParameter() {
return ResponseB.class;
}
public void print(){
System.out.println("Service B");
}
}
public interface ValidationServiceI<T>{
Class<T> getGenericParameter();
void print();
}
#Service
public class ServiceWhichCallsOthers {
#Autowired
private List<ValidationServiceI> validationServices;
public <T> ValidationServiceI<T> methodWhichDeterminesWhichServiceToUseBasedOnResponseType(T responseType){
Optional<ValidationServiceI> validationServiceSupportingResponse = validationServices.stream().filter(validationServiceI -> validationServiceI.getGenericParameter().equals(responseType)).findFirst();
return validationServiceSupportingResponse.get();
}
public void callValidationServiceA(){
methodWhichDeterminesWhichServiceToUseBasedOnResponseType(ResponseA.class).print();
}
public void callValidationServiceB(){
methodWhichDeterminesWhichServiceToUseBasedOnResponseType(ResponseB.class).print();
}
}
#SpringBootTest
public class ServiceWhichCallsOthersIT {
#Autowired
private ServiceWhichCallsOthers serviceWhichCallsOthers;
#Test
public void validateBasedOnResponseType(){
Assertions.assertEquals(ValidationServiceA.class, serviceWhichCallsOthers.methodWhichDeterminesWhichServiceToUseBasedOnResponseType(ResponseA.class).getClass());
Assertions.assertEquals(ValidationServiceB.class, serviceWhichCallsOthers.methodWhichDeterminesWhichServiceToUseBasedOnResponseType(ResponseB.class).getClass());
serviceWhichCallsOthers.callValidationServiceA();
serviceWhichCallsOthers.callValidationServiceB();
}
}

Alternative to #Qualifier in spring boot

I have this scenario
team A is implementing an interface Vehicle as ClassAVehicle
team B is implementing a dashboard service in which it uses vehicle implementation
Now team A have new implementation of Vehicle as ClassBVehicle. And team B wants to use it. One way I know is that use of #Qualifier annotation. But for this I require to change team B's code.
So do I have tight coupling here? Can I have some XML based configuration so that team B's code resolves new ClassBVehicle instance automatically?
interface Vehicle{
int getNoTyre();
}
class ClassAVehicle{
int getNoTyre(){
return 1;
}
}
class ClassBVehicle{
int getNoTyre(){
return 2;
}
}
class Dashboard{
// Here everything is fine until classBVehicle is not there
// Now I want to use new classBVehicle.
// One way I see is that using #Qualifier but will it not be tight coupling?
#Autowired
Vehicle oldAInstance;
}
If you use xml to define bean, your way is good to decouple. Another way is that you can use ApplicationContext to get bean dynamically in annotation program. There are two way to getBean with beanName or beanClass. The below is sample:
#Service
public class BService {
private Vehicle vo;
#Autowired
ApplicationContext context;
public void getVehicle(String beanName){
this.vo = (Vehicle) context.getBean(beanName);
}
public void getVehicle(Class beanClz){
this.vo = (Vehicle) context.getBean(beanClz);
}
public void print(){
System.out.println("---class is "+vo.getClass());
}
}
public interface Vehicle {
}
#Component
public class OneVehicle implements Vehicle{
}
#Component
public class TwoVehicle implements Vehicle{
}
#SpringBootApplication
public class SpringDependenciesExampleApplication implements ApplicationRunner {
#Autowired
BService bService;
public static void main(String[] args) {
SpringApplication.run(SpringDependenciesExampleApplication.class, args);
}
#Override
public void run(ApplicationArguments applicationArguments) throws Exception {
bService.getVehicle("oneVehicle");
bService.print();
}
}
// output is ---class is class OneVehicle

Get a List of Beans for a certain type

I have a certain type of class that can provide data and a registry where the different data providers are registered. I am looking for an elegant way to implement this in spring boot.
My current implementation looks like this (code is shortened for brevity):
public interface DataProvider{
Data getSomeData();
}
public class Registry{
public register(DataProvider provider){
//add to internal list
};
public List<DataProvider> getProviders(){
//return providers
}
public Data someAggregatedOperation(){ ... }
}
public class Provider1 implements DataProvider { ... }
public class Provider2 implements DataProvider { ... }
Now for the wiring part, and this is the part I want to change to something more elegant:
#Configuration
public class MyAppConfiguration{
#Bean
public Registry providerRegistry(){
Registry reg = new Registry();
reg.register(new Provider1());
reg.register(new Provider2());
return reg;
}
}
Then I can inject the registry into other classes that need to operate on the services.
I know that DI is for providing different implementation for a single type but one at a time. So DI most probably is not the right tool, my question is more about spring if there's a good way I don't know to achieve this.
As example Annotate them with a Qualifier and then resolve all Beans with that qualifier in the registry.
The way I would not want to take is using a custom Annotation and then resolving all the classes via reflection, instantiate them and put them in the registry. But at the moment it's the only way I can see so I don't have to modify the config and handwire the services.
If you want all of them to be autowired, you can just autowire a list of your interface implementations.
#Bean
public class Provider1 implements DataProvider { ... }
#Bean
public class Provider2 implements DataProvider { ... }
#Bean
public class Registry{
#Autowired
private List<DataProvider> providers;
public List<DataProvider> getProviders(){
//return providers
}
public Data someAggregatedOperation(){ ... }
}
In case you want to keep using a configuration class you could do something like:
#Bean
public class Provider1 implements DataProvider { ... }
#Bean
public class Provider2 implements DataProvider { ... }
public class Registry{
private List<DataProvider> providers;
public Registry(final List<DataProvider> providers) {
this.providers = providers;
}
public List<DataProvider> getProviders(){
//return providers
}
public Data someAggregatedOperation(){ ... }
}
#Configuration
public class MyAppConfiguration{
#Bean
#Autowired
public Registry providerRegistry(final List<DataProvider> providers){
return new Registry(providers);
}
}

Spring choose bean implementation at runtime

I'm using Spring Beans with annotations and I need to choose different implementation at runtime.
#Service
public class MyService {
public void test(){...}
}
For example for windows's platform I need MyServiceWin extending MyService, for linux platform I need MyServiceLnx extending MyService.
For now I know only one horrible solution:
#Service
public class MyService {
private MyService impl;
#PostInit
public void init(){
if(windows) impl=new MyServiceWin();
else impl=new MyServiceLnx();
}
public void test(){
impl.test();
}
}
Please consider that I'm using annotation only and not XML config.
1. Implement a custom Condition
public class LinuxCondition implements Condition {
#Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
return context.getEnvironment().getProperty("os.name").contains("Linux"); }
}
Same for Windows.
2. Use #Conditional in your Configuration class
#Configuration
public class MyConfiguration {
#Bean
#Conditional(LinuxCondition.class)
public MyService getMyLinuxService() {
return new LinuxService();
}
#Bean
#Conditional(WindowsCondition.class)
public MyService getMyWindowsService() {
return new WindowsService();
}
}
3. Use #Autowired as usual
#Service
public class SomeOtherServiceUsingMyService {
#Autowired
private MyService impl;
// ...
}
Let's create beautiful config.
Imagine that we have Animal interface and we have Dog and Cat implementation. We want to write write:
#Autowired
Animal animal;
but which implementation should we return?
So what is solution? There are many ways to solve problem. I will write how to use #Qualifier and Custom Conditions together.
So First off all let's create our custom annotation:
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.METHOD, ElementType.FIELD, ElementType.TYPE})
public #interface AnimalType {
String value() default "";
}
and config:
#Configuration
#EnableAutoConfiguration
#ComponentScan
public class AnimalFactoryConfig {
#Bean(name = "AnimalBean")
#AnimalType("Dog")
#Conditional(AnimalCondition.class)
public Animal getDog() {
return new Dog();
}
#Bean(name = "AnimalBean")
#AnimalType("Cat")
#Conditional(AnimalCondition.class)
public Animal getCat() {
return new Cat();
}
}
Note our bean name is AnimalBean. why do we need this bean? because when we inject Animal interface we will write just #Qualifier("AnimalBean")
Also we crated custom annotation to pass the value to our custom Condition.
Now our conditions look like this (imagine that "Dog" name comes from config file or JVM parameter or...)
public class AnimalCondition implements Condition {
#Override
public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
if (annotatedTypeMetadata.isAnnotated(AnimalType.class.getCanonicalName())){
return annotatedTypeMetadata.getAnnotationAttributes(AnimalType.class.getCanonicalName())
.entrySet().stream().anyMatch(f -> f.getValue().equals("Dog"));
}
return false;
}
}
and finally injection:
#Qualifier("AnimalBean")
#Autowired
Animal animal;
You can move the bean injection into the configuration, as:
#Configuration
public class AppConfig {
#Bean
public MyService getMyService() {
if(windows) return new MyServiceWin();
else return new MyServiceLnx();
}
}
Alternatively, you may use profiles windows and linux, then annotate your service implementations with the #Profile annotation, like #Profile("linux") or #Profile("windows"), and provide one of this profiles for your application.
Autowire all your implementations into a factory with #Qualifier annotations, then return the service class you need from the factory.
public class MyService {
private void doStuff();
}
My Windows Service:
#Service("myWindowsService")
public class MyWindowsService implements MyService {
#Override
private void doStuff() {
//Windows specific stuff happens here.
}
}
My Mac Service:
#Service("myMacService")
public class MyMacService implements MyService {
#Override
private void doStuff() {
//Mac specific stuff happens here
}
}
My factory:
#Component
public class MyFactory {
#Autowired
#Qualifier("myWindowsService")
private MyService windowsService;
#Autowired
#Qualifier("myMacService")
private MyService macService;
public MyService getService(String serviceNeeded){
//This logic is ugly
if(serviceNeeded == "Windows"){
return windowsService;
} else {
return macService;
}
}
}
If you want to get really tricky you can use an enum to store your implementation class types, and then use the enum value to choose which implementation you want to return.
public enum ServiceStore {
MAC("myMacService", MyMacService.class),
WINDOWS("myWindowsService", MyWindowsService.class);
private String serviceName;
private Class<?> clazz;
private static final Map<Class<?>, ServiceStore> mapOfClassTypes = new HashMap<Class<?>, ServiceStore>();
static {
//This little bit of black magic, basically sets up your
//static map and allows you to get an enum value based on a classtype
ServiceStore[] namesArray = ServiceStore.values();
for(ServiceStore name : namesArray){
mapOfClassTypes.put(name.getClassType, name);
}
}
private ServiceStore(String serviceName, Class<?> clazz){
this.serviceName = serviceName;
this.clazz = clazz;
}
public String getServiceBeanName() {
return serviceName;
}
public static <T> ServiceStore getOrdinalFromValue(Class<?> clazz) {
return mapOfClassTypes.get(clazz);
}
}
Then your factory can tap into the Application context and pull instances into it's own map. When you add a new service class, just add another entry to the enum, and that's all you have to do.
public class ServiceFactory implements ApplicationContextAware {
private final Map<String, MyService> myServices = new Hashmap<String, MyService>();
public MyService getInstance(Class<?> clazz) {
return myServices.get(ServiceStore.getOrdinalFromValue(clazz).getServiceName());
}
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
myServices.putAll(applicationContext.getBeansofType(MyService.class));
}
}
Now you can just pass the class type you want into the factory, and it will provide you back the instance you need. Very helpful especially if you want to the make the services generic.
Simply make the #Service annotated classes conditional:
That's all. No need for other explicit #Bean methods.
public enum Implementation {
FOO, BAR
}
#Configuration
public class FooCondition implements Condition {
#Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
Implementation implementation = Implementation.valueOf(context.getEnvironment().getProperty("implementation"));
return Implementation.FOO == implementation;
}
}
#Configuration
public class BarCondition implements Condition {
#Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
Implementation implementation = Implementation.valueOf(context.getEnvironment().getProperty("implementation"));
return Implementation.BAR == implementation;
}
}
Here happens the magic.
The condition is right where it belongs: At the implementating classes.
#Conditional(FooCondition.class)
#Service
class MyServiceFooImpl implements MyService {
// ...
}
#Conditional(BarCondition.class)
#Service
class MyServiceBarImpl implements MyService {
// ...
}
You can then use Dependency Injection as usual, e.g. via Lombok's #RequiredArgsConstructor or #Autowired.
#Service
#RequiredArgsConstructor
public class MyApp {
private final MyService myService;
// ...
}
Put this in your application.yml:
implementation: FOO
👍 Only the implementations annotated with the FooCondition will be instantiated. No phantom instantiations. 👍
Just adding my 2 cents to this question. Note that one doesn't have to implement so many java classes as the other answers are showing. One can simply use the #ConditionalOnProperty. Example:
#Service
#ConditionalOnProperty(
value="property.my.service",
havingValue = "foo",
matchIfMissing = true)
class MyServiceFooImpl implements MyService {
// ...
}
#ConditionalOnProperty(
value="property.my.service",
havingValue = "bar")
class MyServiceBarImpl implements MyService {
// ...
}
Put this in your application.yml:
property.my.service: foo
MyService.java:
public interface MyService {
String message();
}
MyServiceConfig.java:
#Configuration
public class MyServiceConfig {
#Value("${service-type}")
MyServiceTypes myServiceType;
#Bean
public MyService getMyService() {
if (myServiceType == MyServiceTypes.One) {
return new MyServiceImp1();
} else {
return new MyServiceImp2();
}
}
}
application.properties:
service-type=one
MyServiceTypes.java
public enum MyServiceTypes {
One,
Two
}
Use in any Bean/Component/Service/etc. like:
#Autowired
MyService myService;
...
String message = myService.message()

Is it common to have dependency between facade layer?

My application have the follow layer:
- Facade
- Business Object
- Repository (Spring JPA Data)
Let's suppose the follow classes:
#Component
public class MessageFacade implements MessageService {
#Autowired
private GarageBO garageBO;
#Autowired
private MessageBO messageBO;
public void createFeedbackMessage(...) {
messageBO.createFeedbackMessage(...);
garageBO.createFeedback(...);
}
}
#Component
public class ServiceOrderFacade implements ServiceOrderService {
#Autowired
private ServiceOrderBO serviceOrderBO;
#Autowired
private MessageBO messageBO;
#Autowired
private GarageBO garageBO;
public void createServiceOrder(...) {
serviceOrderBO.createServiceOrder(...);
messageBO.createFeedbackMessage(...);
garageBO.createFeedback(...);
}
}
Observing the createFeedbackMessage method in MessageFacade i have:
1) The createFeedbackMessage method in MessageBO it's responsible to create an email with the feedback survey LINK;
2) The createFeedbackMessage method in garageBO creates the Feedback ENTITY with the questions and responses;
On createServiceOrder method in ServiceOrderFacade i need to call an method of ServiceOrderBO and after i need to have the same behavior of createFeedbackMessage method in MessageFacade.
Is it a bad idea to create a dependency between ServiceOrderFacade -> MessageFacade ?
The code would be:
#Component
public class ServiceOrderFacade implements ServiceOrderService {
#Autowired
private ServiceOrderBO serviceOrderBO;
#Autowired
private MessageBO messageBO;
#Autowired
private GarageBO garageBO;
public void createServiceOrder(...) {
serviceOrderBO.createServiceOrder(...);
getMessageService().createFeedbackMessage(...);
}
}
If you think in DRY(don't repeat yourself) you have an problem. You can create another layer like a common that is dependency of Business Object layer and will be created once and will be used in your entire BO if U want

Categories

Resources