I have the below class
@Component
public class MyBean {
private int val1;
public MyBean(int val1) {
this.val1 = val1;
}
public int getVal1() {
return val1;
}
public void setVal1(int val1) {
this.val1 = val1;
}
}
I want to Autowire Mybean
like below
@Service
public class MyService
{
@Autowire
private MyBean myBean;
}
When i run i get the below error
Parameter 0 of constructor MyBean required a bean of type 'int' that could not be found.
CodePudding user response:
There are many ways to achieve it, all of this will lead to inject proper instance of MyBean
to the IOC container.
- Bean definition with annotation processor with
@Configuration
Indicates that a class declares one or more @Bean methods and may be processed by the Spring container to generate bean definitions.
@Configuration
public class Configuration {
@Bean
MyBean beanName() {
return new MyBean('some_value');
}
}
- Using bean aware interfaces from BeanFactory, like InitializingBean
They are many ways to access the IOC container itself, directly via fluent api's or indirectly via implementing bean aware interfaces like InitializingBean
, specifically use this if you have some operations just after creating bean instance.
@Configuration
public class Configuration implements InitializingBean
{
@Bean
public MyBean beanName() {
return new MyBean('some_value');
}
@Override public void afterPropertiesSet() throws Exception
{
//some operations
...
}
}
- Using IOC instance as ConfigurableApplication context
As mentioned in previous approach this workaround is direct accessing to the IOC container, let imagine you want singelton scope and the canonical name of your bean is MyBean
ConfigurableListableBeanFactory beanFactory = ((ConfigurableApplicationContext) applicationContext).getBeanFactory();
beanFactory.registerSingleton(MyBean, new MyBean('some_value'));
- XMl based bean declaration
Before Spring 3.0, XML was the only way to define and configure beans, now days it not used anymore.
<bean >
<property name="val1" value="some_value"/>
</bean>
CodePudding user response:
When autowiring by constructor, Spring considers every parameter as a bean. In other words, and as the trace reads: There is not a @Bean
of type int
available in the project/context, so it can't build MyBean
.
If you need MyBean
initialized with a primitive int
, then you should use @Bean
annotation within a @Configuration
class instead, so you can pass the value.
@Configuration
public class MyConfiguration {
@Bean
public MyBean myBean() { // MyBean must not have @Component annotation
return new MyBean(1);
}
}
Additionally, and given that the property already has getters and setter, you can change the type of val1
to Integer
, remove the constructor or declare it without parameters, and set it's value in MyService
.
@Component
public class MyBean {
private Integer val1;
public MyBean() {
// Empty constructor, might be removed
}
public int getVal1() {
return val1;
}
public void setVal1(int val1) {
this.val1 = val1;
}
}
@Service
public class MyService {
@Autowired private MyBean myBean;
/* This method is called AFTER the constructor and dependency injections */
@PostConstruct
public void initialize() {
myBean.setVal1(1);
}
}
Depending on the use-case, however, MyBean
could be a POJO, if you need to create it with a primitive value. Not every class in a Spring project needs to be a Bean
, after all.
CodePudding user response:
I think your error occurs because spring tells you it doesn't know which integer-value to use in order to instantiate the Bean MyBean
. You could do the following:
a) Set a default value directly in the bean and use a no-args-constructor:
@Component
public class MyBean {
private int val1 = 1; // or...
private int val1; // default initialisation to 0
public MyBean() {}
...
}
b) Provide a default constructor without parameters for MyBean
and inject the value as property from a properties file:
@Component
public class MyBean {
@Value("${my.property.name}")
private int val1;
public MyBean() {}
public MyBean(int val1) {
this.val1 = val1;
}
...
}
Then in your root-resource directory you need to have a properties file:
src/main/resource/application.properties
with the content:
my.property.name=1
Read more about properties in this article: https://www.baeldung.com/properties-with-spring
c) possibly many other options...those will depend on your specific use case. We don't know enough about your class and which int-values are suitable.
CodePudding user response:
No-args Constructor
You can introduce a no-args default constructor in the MyBean
class, Spring would make use of it and val1
would have a value of 0
(since it's a default for int
type).
@Bean
Or you can create a method annotated with @Bean
inside a configuration class and provide through it an instance of MyBean
with whatever value of val1
you need.
Note that if you would choose this option, you would need to remove @Component
annotation from the MyBean
class.
Example:
@Configuration
public class MyConfig {
@Bean
MyBean myBean() {
return new MyBean(1_000);
}
}
Defining multiple Bean of the same type
Also, note that using @Bean
you can define as many flavors of MyBean
as you need. And another advantage is that MyBean
not necessarily should be your domain class (it can come from a third party library or JDK), whilst stereotype annotations can be placed only on top of your custom classes.
Here's an example:
@Configuration
public class BeanConfig {
@Bean
@Qualifier("1000")
MyBean myBean1() {
return new MyBean(1_000);
}
@Bean
@Qualifier("8000")
MyBean myBean2() {
return new MyBean(8_000);
}
}
@Qualifier
annotation is needed to distinguish these beans. It allows using various flavors of your bean in different parts of the application.
Let's make use of the bean with a value of 8000
in the service:
@Service
public class MyService {
private MyBean myBean; // field injection is a not a good practice
public MyService(@Qualifier("8000") MyBean myBean) {
System.out.println(myBean); // would allow to ditermin which bean is used here (don't forget to override toString)
this.myBean = myBean;
}
}
Note using @Autowired
on field is not a recommended practice. The common approach is to use constructor injection, and in case if there's only one constructor in the class using @Autowired
is not required.