Alternative to #Qualifier in spring boot - java

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

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();
}
}

Getting Bean instance as null using Strategy Design Pattern and #Autowired

Hi I am trying to use Strategy Design pattern. I am getting ReEncryptionOperation bean as null in my TestServiceImpl class.
this is my interface
public interface ReEncryptionOperation {
void performOperation (String name);
}
These are my implementation classes
public class Test1 implements ReEncryptionOperation {
#Override
public void performOperation(String name){
return ....;
}
}
public class Test2 implements ReEncryptionOperation {
#Override
public void performOperation(String name) {
return ....;
}
}
This is my configuration class where I am defining as a bean
#Configuration
#Slf4j
public class TestConfiguration
{
#Bean("reEncryptionOperation")
public ReEncryptionOperation getReEncryptionOperation () throws ReEncryptionException {
if (annotationSupport) {
return new Test1();
}
return new Test2();
}
}
this is my service class where i am trying to use ReEncryptionOperation using #Autowired. But I am getting null.
#Component
#Slf4j
public class TestServiceImpl
{
#Autowired
private ReEncryptionOperation reEncryptionOperation;
public ReEncryptionResponse submitJob (
final ReEncryptionRequest reEncryptionRequest) throws ReEncryptionException
{
reEncryptionOperation.performOperation(test);
}
}
Your configuration seems ok.
Check that TestConfiguration is located in a package scanned by spring.
To be sure your bean is created on runtime, place a breakpoint in the method getReEncryptionOperation

Spring Boot Common JPA repository class

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
}
...
}

Spring Boot not recognizing Interface

I have an interface like so:
public interface Animal {
void setName(String animal);
String getName();
}
and I have a Class that implements the interface:
#Component
public class Dog implements Animal {
private String name;
public void setName(String name) {
this.name= name;
}
public String getName() {
return this.name;
}
}
In another class (ProcessAnimal), I AutoWire the interface:
public class ProcessAnimal {
#Autowired
public Animal animal;
public void processAnimals() {
animal.setName("Fido");
}
}
I only have one class that implements Animal so this should work, however, I get a NullPointerException when it hits the animal.setName("Fido"); line. IntelliJ is complaining that Autowired members must be defined in valid Spring bean (#Component|#Service...) which I have... I don't understand what I'm doing wrong. I've tried to add a #Qualifier, but still it didn't work and it shouldn't be necessary since I only have one implementation.
-java
-com.example.com.AnimalProcessing
-Animal
-Animal.java
-Dog.java
-ProcessAnimal.java
-AnimalProcessingApplication.java
AnimalProcessingApplication.java
#SpringBootApplication
public class AnimalProcessingApplication {
public static void main(String[] args) {
SpringApplication.run(AnimalProcessingApplication.class, args);
run();
}
public static void run() {
ProcessAnimal processAnimal = new ProcessAnimal();
processAnimal.processAnimals();
}
}
AnimalProcessingApplication class should be one level above all other classes.
Also you are using new for creation of object instead of using Dependency Injection (autowiring).
Replace below -
ProcessAnimal processAnimal = new ProcessAnimal();
with
#Autowired
ProcessAnimal processAnimal;
Also make sure that ProcessAnimal is a bean and Animal is injected in this class using autowiring.
Animal Processing Application.java must be on root folder of all classes.
Then all components in child folders are recognized automatically.
Update:
Create a config class with #Bean method to create an instance with a Dog. Also then you can get rid of the #Component annotation of the class.
The problem here is the constructor String name which cannot be injected.
Update 2:
Don't create the instances by yourself. Let spring container create them. Remove the run method.
Following are to be done to make this program work.
1.ProcessAnimal should be made a component . Annotating the class with #Component will mark the class to be autodetected during component scan.
#Component
public class ProcessAnimal {
#Autowired
public Animal animal;
public void processAnimals() {
animal.setName("Fido");
}
}
Obtain the ProcessAnimal class from the application context. The spring will prepare the ProcessAnimal bean with all its dependencies set.
You may do this in multiple ways and following is one of those
#Component
public class CheckRedRunner implements ApplicationRunner {
#Autowired
ProcessAnimal process;
#Override
public void run(ApplicationArguments args) throws Exception {
process.processAnimals();
}
}
A bean implementing ApplicationRunner will be run when the application starts.
or else
public static void main(String[] args) {
ApplicationContext ctx = SpringApplication.run(AnimalProcessingApplication.class, args);
ProcessAnimal process = ctx.getBean(ProcessAnimal.class);
process.processAnimals();
}
Couple of observations
the package names by convention uses lower case letters
example : com.example.process.entity
Please go through the official documentation to learn the expected way of writing Spring boot application.

Dagger2 Basics - Field Injection - Not working

I am trying to do Field Injection using Dagger2. I realize I need to call inject manually in case of method injection. I am primarily trying to inject an Engine for a Car. The Engine is decided at runtime, and injected.
The data goes like this
CarInterface
import dagger.Binds;
public interface Car {
public void run();
}
Car Implementation
public class Volkswagen implements Car {
#Inject
public Engine engine;
public void run() {
System.out.println("About to Run");
engine.start();
}
}
Engine Interface
public interface Engine {
public String start();
}
Engine Implementation
public class Ferrari4Cylinder implements Engine {
#Override
public String start() {
return "Ignition----Vroom-- Vroom-- Sweet Purring Sound";
}
}
Car Module
public class CarModule{
#Provides #Singleton
Car provideCar(){
return new Volkswagen();
}
}
Engine Module
#Module
public class EngineModule {
#Provides #Singleton
public Engine provideEngine(){
return new Ferrari4Cylinder();
}
}
Component Class
#Singleton
#Component(modules = {CarModule.class, EngineModule.class})
public interface MyCarComponent {
public Car provideCar();
void inject(Car car);
}
Main Method
public class Main {
public static void main(String[] args) {
MyCarComponent carComponent= DaggerMyCarComponent.builder().build();
Car car = carComponent.provideCar();
carComponent.inject(car);
car.run();
}
}
For some reason :
The Car.run() Method always returns null, as the Engine is never Injected.
Exception in thread "main" java.lang.NullPointerException
Can anybody help out on what is happenning here?
Update 9/02/2016 :
I figured out that the following changing the component to point to the actual implementation works as shown below. Not sure why the other one does not, but it helped me move forward on the issue.
#Singleton
#Component(modules = {CarModule.class, EngineModule.class})
public interface MyCarComponent {
public Volkswagen provideCar();
void inject(Volkswagen car);
}
Hope this helps folks trying to solve the Field Injection issues in Dagger.
You need to annotate your Engine field with #Inject. I also believe you'll
need to provide the implemented class (Volkswagen as opposed to just Car) to your inject method.
public class Volkswagen implements Car {
#Inject public Engine engine;
public void run() {
System.out.println("About to Run");
engine.start();
}
}
--
#Singleton
#Component(modules = {CarModule.class, EngineModule.class})
public interface MyCarComponent {
public Car provideCar();
void inject(Volkswagen car);
}
It seems you forgot to add the EngineModule to the MyCarComponent.
In order to do field injection you should add the #Inject annotation on the Engine in the Car class. But it is encouraged to avoid field injection if possible. Instead consider doing this:
public class Volkswagen implements Car {
private final Engine engine;
public Volkswagen(Engine engine) {
this.engine = engine;
}
}
Then in CarModule
#Provides
#Singleton
static Car provideCar(Engine engine) {
return new Volkswagen(engine);
}
Also, this way you don't need the inject method on the component interface.
Remember to add the EngineModule to the component, so that dagger can provide an Engine.

Categories

Resources