Question on Spring 3 autoscan and required annotation - java

I have a class annotated with spring Component e.g:
#Component
public class ImportantClass{
#Autowired
private DependentClassIF otherClass;
//getters setters
#Required
public void setOtherClass(DependentClassIF c){
this.otherClass = c;
}
public interface DependentClassIF {
//methods here
}
#Component
public class DependentClass implements DependentClassIF {
//implementation here
}
I use autoscan to detect beans instead of declaring them all in the bean conf file.
I get
org.springframework.beans.factory.BeanInitializationException:
Property 'otherClass' is required for
bean 'ImportantClass'
My question is the following:
In autoscan, doesn't Spring make sure that all the required properties are injected?
If I remove the #Required it works, but I am not sure I understand Spring's behavior on this.
Any input is welcome.
Thanks

#Autowired has required set to true, so you don't need #Required
You don't need #Requried with annotation-based injection. It is meant to be used with xml configuration, to denote that a property must be set in the xml.

Related

How to properly inject #Autowired between Spring Boot classes?

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.

Autowiring conflict in spring core with the xml configuration

Taking as reference the post Spring #Autowired and #Qualifier
We have this example to fix the autowiring conflict :
public interface Vehicle {
public void start();
public void stop();
}
There are two beans, Car and Bike implements Vehicle interface.
#Component(value="car")
public class Car implements Vehicle {
#Override
public void start() {
System.out.println("Car started");
}
#Override
public void stop() {
System.out.println("Car stopped");
}
}
#Component(value="bike")
public class Bike implements Vehicle {
#Override
public void start() {
System.out.println("Bike started");
}
#Override
public void stop() {
System.out.println("Bike stopped");
}
}
#Component
public class VehicleService {
#Autowired
#Qualifier("bike")
private Vehicle vehicle;
public void service() {
vehicle.start();
vehicle.stop();
}
}
That's a very good example to fix this problem.
But when I have the same problem but without those balises in the application context:
<context:component-scan></context:component-scan>
<context:annotation-config></context:annotation-config>
All the issues are solved by using the #Qualifier annotation, but in my case we don't use the balise that permit to use annotation.
The question is :
How can I fix this issue just using the configuration in application context, that's it, without using annotations?
I searched a lot and I found people talking about autowire attribute in the bean declaration <bean id="dao" class="package.IDao" autowire="byName"></bean> and I need more explanation about it.
How can I fix this issue just using the configuration in application
context?
You could use the qualifier tag like below (see https://docs.spring.io/spring/docs/3.2.x/spring-framework-reference/html/beans.html#beans-autowired-annotation-qualifiers)
<context:annotation-config/>
<beans>
<bean class="your_pkg_route.Vehicle">
<qualifier value="bike"/>
</bean>
</beans>
</context:annotation-config>
I found people talking about autowire attribute in the bean
declaration and I need more explanation about it
Using Annotation
#Autowired used on a bean declaration method injects the defined dependencies by (another) declared beans. Now, if your dependencies are in the same context of your application, you don't need to use the #Autowired annotation at all because Spring is able to figure them out by itself. So, if your dependencies are outside your applicatoin context then you can use it.
For example, take as reference the below code:
#Autowired
#Bean
public MyBean getMybean(Dependency1 depdency1, Dependency2 depdency2) {
return new MyBean(depdency1.getSomeStuff(), depdency2.getSomeOtherStuff());
}
Here, #Autowired will find an instance of Dependency1 and Dependency2 and will provide them for the creation of an instance of MyBean.
Using xml configuration
From Pro Spring 5... Spring supports five modes for autowiring.
byName: When using byName autowiring, Spring attempts to wire each property to a bean of the same name. So, if the target bean has a property named foo and a foo bean is defined in ApplicationContext, the foo bean is assigned to the foo property of the target.
byType: When using byType autowiring, Spring attempts to wire each of the
properties on the target bean by automatically using a bean of the same type in
ApplicationContext.
constructor: This functions just like byType wiring, except that it uses constructors rather than setters to perform the injection. Spring attempts to match the greatest numbers of arguments it can in the constructor. So, if your bean has two constructors, one that accepts a String and one that accepts String and an Integer, and you have both a String and an Integer bean in your ApplicationContext, Spring uses the two-argument constructor.
default: Spring will choose between the constructor and byType modes
automatically. If your bean has a default (no-arguments) constructor, Spring uses
byType; otherwise, it uses constructor.
no: This is the default
So, in your case you would need to do something like this (BUT, I would NOT recommend it. Why?, you would need to declare Vehicle class as a bean and a component which is not correct, see Spring: #Component versus #Bean. On the other hand I'm not sure if you could use it just declaring it as a bean):
// xml config
<context:annotation-config/>
<beans>
// use the primary tag here too! in order to say this the primary bean
// this only works when there are only two implementations of the same interface
<bean id="bike" primary="true" class="your_pkg_route.Bike"/>
<bean id="car" class="your_pkg_route.Car"/>
<bean autowire="byName" class="your_pkg_route.VehicleService"/>
<beans>
</context:annotation-config>
// VehicleService
#Component
public class VehicleService {
private Vehicle bike; // call attribute 'bike' so it is autowired by its name
public void service() {
//...
}
}
As you can see there is a lot of complications trying to do this using xml config, so I would recommend you to use the annotation option if possible.
Related posts:
Why do I not need #Autowired on #Bean methods in a Spring configuration class?
Difference between #Bean and #Autowired
PS: I have not tested any of the posted codes.
You can use #Primary instead of #Qualifier
#Primary
#Component(value="bike")
public class Bike implements Vehicle {
we use #Primary to give higher preference to a bean when there are multiple beans of the same type.
We can use #Primary directly on the beans
You can also set primary attribute in XML:
property has primary attribute:
<bean primary="true|false"/>
If a #Primary-annotated class is declared via XML, #Primary annotation metadata is ignored, and is respected instead.

Better way to register beans in Spring

I am new in Spring. I understand process of Dependency Injection and Inversion Of Control as well. But in few days ago I found one source code which compel me thinking about it.
If I am not wrong, Beans can be registered by Stereotype annotations - #Component, #Service, etc.
In code which I found will be defined class with some logic, but without annotation. Next that same class will be initialized in some #Configuration class as been like that:
#Bean
public Foo fooBean() {
return new Foo();
}
Can you tell me what is different between these options and when they use? Thanks in advice.
The greatest benefit of #Configuration and #Bean is that allows you to create spring beans that are not decorated with #Component or any of its children (#Service, #Repository and those). This is really helpful when you want/need to define spring beans that are defined in an external library that has no direct interaction with Spring (maybe written by you or somebody else).
E.g.
You have a jar created by an external provider that contains this class:
public class EmailSender {
private String config1;
private String config2;
//and on...
public void sendEmail(String from, String to, String title, String body, File[] attachments) {
/* implementation */
}
}
Since the class is in an external jar, you cannot modify it. Still, Spring allows you to create spring beans based on this class (remember, the bean is the object, not the class).
In your project, you'll have something like this:
import thepackage.from.externaljar.EmailSender;
#Configuration
public class EmailSenderConfiguration {
#Bean
public EmailSender emailSender() {
EmailSender emailSender = new EmailSender();
emailSender.setConfig1(...);
emailSender.setConfig2(...);
//and on...
return emailSender;
}
}
And then you can inject the bean as needed:
#Service
public class MyService {
#Autowired
private EmailSender emailSender;
}
#Configuration is used to define your configuration of your application. In the end #Bean, #Service, #Component will all register a bean, but using #Configuration with all beans (services, components) defined in a single place makes your app more organized and easier to troubleshoot.

Spring Boot autowire #ManagedResource

Is it possible in Spring Boot to autowire object that is marked by #ManagedResource. I'm trying to do that but object is null.
For example:
#Component
#ManagedResource(objectName = MyMBean.MBEAN_NAME)
public class MyMBeanImpl implements MyMBean {
private String attribute;
#Override
#ManagedAttribute(description="some attribute")
public void setAttribute(String attribute) {
this.attribute = attribute;
}
}
Spring creates appropriate MBean. But when I try to autowire this object to use its attribute I'm getting null:
#Component
public final class Consumer {
#Autowired
MyMBean mBean; // is null
...
}
The #Autowired objects may not get initialized if your configuration is not properly defined. Spring scans for managed components in specified packages. I assume that you have #ComponentScan annotation on your spring boot main class. If your main application class is in a root package, then #ComponentScan annotation can be used without specifying a basePackage attribute. Otherwise you need to specify the base package attribute. You need to specify the basePackage attribute similar to the below:
#ComponentScan("<your_package_to scan_for beans>")
Also the #EnableAutoConfiguration annotation is often placed on your main spring boot application class. This implicitly defines a base package to search for components.

How to insert property in Autodetected Component in Spring?

I am using #Service annotation of spring, so that my class should be autodetected by spring and made available for autowiring.But in my class, I need a property 'sqlmap'.If I had been using way of creating beans instead of auto-detection, I would have supplied that property using property tag in that bean..
So, is there any way I can inject my property in my class?Because unless that property is made available, spring will not be able to create bean of that class.
Your #Service class can "pull" a bean into a property using #Resource, e.g.
#Service
public class MyService {
#Resource (name="sqlMapClient")
private SqlMapClient sqlMapClient;
}
An alternative to #Resource is #Autowired, which will automatically select the target by type:
#Service
public class MyService {
#Autowired
private SqlMapClient sqlMapClient;
}
Try both, see which works best for you.

Categories