How to properly inject #Autowired between Spring Boot classes? - java

I have a classA which implements an interfaceA, with a methodA, then I have a classB in which I call classA with an #Autowired to be able to use methodA, but it gives me a warning that I must create a method for classA. Why is this happening? Doesn't #Autowired work like this in this case? Should I just instantiate classA? Thank you very much for your answers.
ClassA
#RequiredArgsConstructor
public class RepositoryImpl implements IRepository {
#Autowired
private final TransactionDataMapper transactionDataMapper;
#Autowired
private SpringDataColminvoice springDataColminvoice;
#Override
public <S extends TransactionDto> S save(S s) {
Colm colm = transactionDataMapper.toEntity(s);
//methodA
springDataColminvoice.save(colm);
return null;
}
}
InterfaceA
public interface IRepository extends IRepository<TransactionDto, Integer> {}
ClassB
#Service
#RequiredArgsConstructor
public class ServiceImpl implements IInvoiceService {
#Autowired
private RepositoryImpl repositoryImpl;
#Override
public void save(CMessage cMessage) throws HandlerException {
try {
TransactionDto transactionDto = cMessage.getTransaction();
// methodA
repositoryImpl.save(transactionDto);
} catch (Exception e) {
throw new HandlerException(e.getMessage());
}
}
}
Exception
Action:
***************************
APPLICATION FAILED TO START
***************************
Description:
Field RepositoryImpl in com.st.ms.yyu.d.binvoce.infraestructure.rest.spring.services.impl.InvoiceServiceImpl required a bean of type 'com.st.ms.yyu.d.binvoce.infraestructure.db.springdata.repository.impl.ServiceImpl' that could not be found.
The injection point has the following annotations:
- #org.springframework.beans.factory.annotation.Autowired(required=true)
Action:
Consider defining a bean of type 'com.st.ms.yyu.d.binvoce.infraestructure.db.springdata.repository.impl.RepositoryImpl' in your configuration.

(posting this as an answer since I do not have enough reputation to comment)
As others have pointed out already, a code sample would help tremendously.
That being said, though, it sounds like you're missing implementation for "ClassA".
If you have an interface that "ClassA" implements, you have to implement the interface's methods in "ClassA" before you can use them.
I assume your code currently looks somewhat like this?
public interface InterfaceA {
void methodA();
}
public class ClassA implements InterfaceA {
}
public class ClassB {
#Autowired
ClassA classA; // Cannot use {#link InterfaceA#methodA} because the class does not implement the function
}
If this is your code, make sure you add an implementation for your "methodA()" function in "ClassA". Somewhat like so:
public class ClassA implements InterfaceA {
#Override
public void methodA() {
}
}
Additionally, in order to autowire in Spring (Boot), you need to ensure that the class you'd like to autowire is marked as such. You can autowire beans.
To make "ClassA" in the example eligible for autowiring, make sure to instantiate it either as:
A bean (using the #Bean annotation).
A component (using the #Component annotation).
A service (using the #Service annotation).
Any of the other annotations that may match your use case the best.
In our example, this would look somewhat like this:
#Component // Or #Service / whatever you may need
public class ClassA implements InterfaceA {
#Override
public void methodA() {
}
}
Hope you've found any of this helpful. All the best!
-T

As what I have understood, #Autowire means injecting the value/instance of the specific property where you put the annotation #Autowire. In this case, #Autowire only happens when there is defined/created Bean within your basePackage of your Spring Boot project that can match it, i.e. where your #Autowire referred to (meaning there is no conflict issue like ambiguity, etc. and the DataType(Class) can be implicitly casted). In your example, first you treat the IRepository and/or RepositoryImpl as Repository without using the #Repository annotation to inform the Spring Boot default configuration that this is a Repository bean. As you didn't put the POM.xml or posted the related code, I presumed you are creating your own repository class. I think it's much better to post your dependencies here.
But as what others pointed out. You need to create a bean that can match the #Autowired you've put on TransactDataManager & SpringDataColminvoice. You need also to inform the Spring Boot or register it that your class A is a Bean by annotating
#Bean - defining a regular bean,
#Component - a Component in the Project,
#Service - a Service in the Project,
#Repository - a Repository (if you're using Spring JPA), etc.
#<Other Annotations depending of what other Spring Project/Dependencies your using>
Since newer versions of Spring is moving to annotation based from XML mapping, we need to put proper annotation for each class/object that we want to be auto injected/instantiated from #Autowired using the above sample annotations depending on the role/purpose of your class/object is.
I suggest if you're not sure. Then create a typical bean using common annotation #Bean. So your class A might be
#Component //Insert proper Annotation for your class if necessary. This is just a sample
#RequiredArgsConstructor
public class RepositoryImpl implements IRepository {
#Autowired
private final TransactionDataMapper transactionDataMapper;
#Autowired
private SpringDataColminvoice
springDataColminvoice;//segunda
#Override
public <S extends TransactionDto> S save(S s) {
//Some implementation
}
#Bean
private TransactionDataMapper getTransactionDataMapper(<Some parameters if needed>){
return <an instance for TransactionDataManager>;
}
#Bean
private SpringDataColminvoice getSpringDataColmInvoice(<Some parameters if needed>){
return <an instance for SpringDataColminvoice>;
}
}
Note that 2 beans definition are optional if there are already a Beans define on outside class or if it was marked by other annotation like #Service, #Component or other proper annotations and the other one bean is just a reference parameter for the other bean in order to properly instantiated.
In your class B is the following:
public class ClassB {
#Autowired
ClassA classA;
/*Note: ignore this Bean definition if Class A is annotated with #Component,
#Service, or other proper #Annotation for Class A.
*/
#Bean
private ClassA getClassA(<Some Parameters if Needed>){
return <Instance of Class A>
}
}
Take note that, you don't need to put a Bean definition inside the Class B if you put a proper annotation for your Class A like #Component, #Service, etc.

Related

Spring different beans for different consumers

Suppose I have several components that depend on one service:
public interface MyService { ... }
// in package1
#Component
public class Package1Component1 {
#Autowired
private final MyService myService;
}
public class Package1Component2 {
#Autowired
private final MyService myService;
}
// in package 2
public class Package2Component1 {
#Autowired
private final MyService myService;
}
public class Package2Component2 {
#Autowired
private final MyService myService;
}
And I have two implementations of MyService:
#Service
public class MyServiceImpl1 implements MyService { ... }
#Service
public class MyServiceImpl2 implements MyService { ... }
And I want MyServiceImpl2 to be injected into all components in package2 and MyServiceImpl1 everywhere else
I don't want to use #Qualifier to resolve ambiguity as it will require to always specify it when you need to inject MyService and to change a lot of files when I need to switch to single implementation everywhere (MyServiceImpl2 is temporary implementation that should be used only in specific scope).
Is there any way to specify bean for scope (java package?), like in Angular I can override module providers (AuthService in this case):
#NgModule({
declarations: [LoginComponent, UserInfoComponent],
providers: [
{
provide: AuthService,
useClass: FacebookAuthService,
},
],
})
export class AuthModule {}
You can introduce your meta-annotation annotated with #Qualifier and use it.
Once you are ready to change, just change Qualifier on your meta annotation.
I think it's not really correct to co-relate Angular specificities with Spring, as they are simply two radically different infrastructures, in all aspects.
Why don't you want to use #Qualifier? for what reason? because, the problem you describe is exactly why people came up with #Qualifier implementation.
I don't want to use #Qualifier to resolve ambiguity as it will require to always specify it when you need to inject MyService and to change a lot of files when I need to switch to single implementation everywhere.
Not really. You can provide ID for your bean definition, and disregarding of what implementation you'll use later, same bean, with that same ID, will be injected wherever you'll qualify it to be injected. You will only swap the implementation class.
Also, package in Java, is not a scope for Beans. Package is facility for grouping a logically similar classes, and it can be considered as a scope, but for class and its members' accessibility/visibility, not for the beans.
Bean scopes have a different semantics, and you can read about them here.
The is another way to specify, that the bean should qualify as a candidate, if there are more than one implementations of a type you're injecting. It's #Primary; however, this #Primary will always override any other candidates, while with #Qualifier you can leverage more fine-grained control on what to inject where.

IoC / DI especially Spring: Autowire properties without setter/constructor

I have a question that I can't answer myself - at least not well.
Imagine following code:
#Service
public class ServiceA {
public void doService() {
System.out.println("Doing ServiceA");
}
}
#Service
public class ServiceB {
#Autowired
ServiceA serviceA;
public void doService() {
serviceA.doService();
}
}
It works, but is it considered bad practice? If you want to decouple these classes or test them, you have no way to ever manually set the dependencies.
Also, how exactly is Spring handling it? Is there created a proxy class with an added constructor for the property?
If it is a bad practice or not depends for the era in which you write this code. In the era of EJB it is a best practice, the container provide you all the feature of the lifecycle and even in Spring it is good even if some time even in Spring this is quite rigid model java config or xml is a more flexible solution.
However in the 20xx era especially in a TDD and Agile model, I can say that it is a real BAD PRACTICE. Those beans are not testable out of the Spring container and the annotation couple you at Spring even in compile time. a more best solution may be a code like below
class ServiceA {
public void doService() {
System.out.println("Doing ServiceA");
}
}
class ServiceB {
private final ServiceA serviceA;
ServiceB(ServiceA serviceA) {
this.serviceA = serviceA;
}
public void doService() {
serviceA.doService();
}
}
#Configuration
class ServiceConfig{
#Bean
public ServiceA serviceA(){
return new ServiceA();
}
#Bean
public ServiceB serviceB(ServiceA serviceA){
return new ServiceB(serviceA);
}
}
In this way ServiceA and ServiceB classes are two totally Spring free bean and especially for the business logic it is a best practice, the bean are testable because the our dependencies are explicit.
Imagine of provide a test of the ServiceB class writing the code in this way you can stub or mock the serviceA dependency and the ServiceB bean can be tested in isolation.
For the proxy story do not worry about it since that we provide a configuration class ServiceA and ServiceB are two beans like the annotated class, Spring manage a java config bean like an annotated bean. The difference is that now we can benefit of an explicit composition and we can provide a more flexible configuration scenario. we can benefit again of the magic aop of Spring because like said before an Spring bean configured in Java config is totally equivalent respect to an annotated bean.
I suggest you to use java config like the example.
I hope that it can help you
update:
to reply to:
Also, how exactly is Spring handling it? Is there created a proxy class with an added constructor for the property?
I can say: with the component-scan feature let's say #ComponentScan, spring find all the bean that are annotated with a sterotype annotation like #Component, #Service, #Repository and so on some of this annotation are useful because trigger some feature, for example #Repository if we implement a JPA repository and register a PersistanceExceptionTraslatorPostProcessor that translate the SQL native exception in an Exception of DataAccessException hierarchy, but other annotation are just a way for register a spring bean with annotation #Component, #Service are example.
Spring by relfection create the bean and inject the field annotated with #Autowired, if you use #Autowired on field by reflection set directly the field otherwise use the setter, in xml for instance the setter or the constructor are required.
In case of two constructor for you it is transparent, Spring will use the empty constructor and then will provide the #Autowired property by reflection, you can even do like below:
#Service
class ServiceA {
public void doService() {
System.out.println("Doing ServiceA");
}
}
#Service
class ServiceB {
private ServiceA serviceA;
public ServiceB() {
}
#Autowired
public ServiceB(ServiceA serviceA) {
this.serviceA = serviceA;
}
public void doService() {
serviceA.doService();
}
}
In this case spring recognize that it have use the annotated constructor with #Autowired in order to create the bean and provide the dependency. In any case the best practice is definitely the first snippet of code in my answer. It is explicit in the dependencies, clean and Spring Free in your business code base
If you dont like autowired (me either). You can used Constructor Dependency Injection.
You should not used depencendy for class byt for interface and spring will server correct implementation (decoupling)
public interface ServiceA {
public void doService();
}
#Service
public class ServiceAImpl implement ServiceA {
public void doService() {
System.out.println("Doing ServiceA");
}
}
#Service
public class ServiceBImpl implements ServiceB {
private final ServiceA serviceA;
public ServiceBImpl(ServiceA serviceA) {
this.serviceA = serviceA;
}
public void doService() {
serviceA.doService();
}
}

How Can I Override an Autowired Spring Bean With an External/3rd Party Bean

I have a situation where I want to enable clients to inject their own bean implementing a common interface into my class but otherwise use a default bean.
As an example:
public class TestClass {
// Clients can inject this, otherwise use a default...
#Autowired
private ConfigInjector configInjector;
}
My defined interface and default implementation:
public interface ConfigInjector {
String getConfig();
}
#Component
public class DefaultConfigInjector implements ConfigInjector {
public String getConfig() {
return "DEFAULT CONFIG"
}
}
An external client wants to inject this implementation of my ConfigInjector interface:
#Component
public class ExternalConfigInjector implements ConfigInjector {
public String getConfig() {
return "EXTERNAL CONFIG"
}
}
Using #Autowired in TestClass, if the client attempts to use TestClass with his own ConfigInjector implementation (ExternalConfigInjector), then more than one ConfigInjector implementation will exist, resulting in a NoUniqueBeanDefinitionException exception.
So, how can I share my TestClass with clients allowing them to use their own ConfigInjector to override my default?
you may use #ConditionalOnProperty annotation
according to the name of the variable/argument
using the #primary annotation
using #Qualifier annotation
a recommended free course (1.5 h)
name "Spring Framework And Dependency Injection For Beginners" at www.udemy.com
explains all main issues and use cases.

How to Autowire a Spring-annotated service class in a #Configuration class?

I'm trying to inject a service-annotated class into a configuration class in a Spring Boot application, but it doesn't get injected (is set to null), which I assume is due to the Spring lifeycle.
Also, this service has an overloaded constructor that uses constructor injection, and I guess this is also a problem, as autowiring acts upon a default constructor. However, the service needs to be Spring-configured, so I don't think one can create a new instance in a Bean annotated method.
How can one solve this?
#Configuration
#Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Autowired
private SessionService sessionService;
#Bean
public SessionService sessionService() {
return sessionService;
}
}
public interface SessionService extends BaseCacheService<Session> {
void extendExpiration(String key);
String getSessionId(String key);
}
#Service
public class SessionServiceImpl implements SessionService {
private Environment environment;
private UserService userService;
#Autowired
public SessionServiceImpl(Environment environment, UserService userService) {
this.environment = environment;
this.userService = userService;
}
}
If I exclude the #Bean method, then I get a compilation error:
Your error is the following (you are returning a null value):
#Bean
public SessionService sessionService() {
return sessionService;
}
Solution
Since your SessionServiceImpl is annotated with #Service, you can just remove the #Bean method and let spring create it. Spring already makes it available for you.
Or, If your SessionServiceImpl wasn't annotated with #Service, you would need the following :
#Bean
public SessionService sessionService() {
return new SessionService();
}
If this doesn't work, it may just be that your SessionServiceImpl is in a package not being scanned by spring (as suggested by #Miloš Milivojević)
You may add #ComponentScan to your Configuration class
#Configuration
#Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
#ComponentScan("com.package.to.sessionServiceImpl-or-higher")
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
Expanding on #Alex's answer, when you annotate a method with #Bean, it tells Spring that this method will produce that type. So, you essentially told Spring to give you the null reference you already had for all Beans of type SessionService.
If you are using Annotation-based context configuration, you can Autowire any #Component Bean (not just #Service) that can be constructed without runtime parameters (e.g. has a default constructor or an Autowired Constructor). If you need to do something to create the bean (e.g. runtime configuration required), you would either create a method as #Alex suggested, or you can use getBean and pass in the Type and Constructor arguments. The former is generally preferred.
I was facing similar issue while writing an integration test class for a spring boot application. RestTemplate class and CounterService of metrics API are autowired in my service class. I could use #ContextConfiguration(Classes={RestTemplate.class}) for injecting RestTemplate to my service, but adding CounterService.class to above annotation does not help, maybe because CounterService is an interface not a concrete class, Hence I was getting "No bean of type CounterService found" issue.
Thanks to answer by Milos, I included #EnableAutoConfiguration to my integration test class, issue was resolved!
If Alex's answer does not work (removing the #Bean method), you're probably not using #EnableAutoConfiguration or your Application is not in the root-hierarchy package so it's not scanning the whole classpath. Try adding #ComponentScan("service.class.package") to your configuration (in addition to removing the sessionService method) and see if it helps.

Handling several implementations of one Spring bean/interface

Say I need to rely on several implementations of a Spring bean. I have one AccountService interface and two implementations: DefaultAccountServiceImpl and SpecializedAccountServiceImpl.
How is this possible (injecting one or the other implementation) in Spring?
Which implementation will the following injection use?
#Autowired
private AccountService accountService;
Ad. 1: you can use #Qualifier annotation or autowire using #Resource as opposed to #Autowired which defaults to field name rather than type.
Ad. 2: It will fail at runtime saying that two beans are implementing this interface. If one of your beans is additionally annotated with #Primary, it will be preferred when autowiring by type.
#Autowired
#Qualifier("impl1")
BaseInterface impl1;
#Autowired
#Qualifier("impl2")
BaseInterface impl2;
#Component(value="impl1")
public class Implementation1 implements BaseInterface {
}
#Component(value = "impl2")
public class Implementation2 implements BaseInterface {
}
For full code: https://github.com/rsingla/springautowire/

Categories