Autowire a bean only if it is available - java

#Component
public class Test {
#Autowire
private MyBean myBean;
public void sampleMethod()
{
if(myBean == null) {
myBean = BeanFactory.getDefaultBean();
}
// ...
}
}
Is it possible to autowire MyBean if it is not defined in the spring configuration xml file? I understand that in this case, it would throw No bean found of type MyBean. Can we configure something to ignore that exception and fallback on the BeanFactory to get the DeafultBean.
Something like:
#Autowire(assignNullIfBeanNotFound = true)

Let's look at the javadoc (the annotation is named Autowired, and not Autowire):
public abstract boolean required
Declares whether the annotated dependency is required.
Defaults to true.
Isn't this idea of providing documentation for classes wonderful?

Related

Not able to pass String to a constructor in Java using Spring

I'm trying to pass parameter to one of constructor of my BBFilter component, however it throws the exception that No beans of String type found. I have autowired the constructor as well. Am I doing anything wrong? Please advise
#Bean
public MyBean bbFilter() {
BBBean bbBean = new BBBean();
bbBean.setFilter(new BBFilter("plan1"));
}
BBFilter
#Component
public class BBFilter implements Filter {
private String planType;
#Autowired
public BBFilter(String planType) { --> Could not autowire. No beans of String type found
this.planType = planType;
}
}
I am assuming you are using Spring. The #Component annotation tells spring to automatically create an Instance of BBFilter as a Bean.
You also annotated the constructor with #Autowired. So Spring searches it's beans for fitting types and injects the automatically on construction. Since you probably didn't define any String bean it cannot autowire the String and throws an exception.
But since you want to create the Filter manually anyways you can simply remove both annotations from your BBFilter Class:
public class BBFilter implements Filter {
private String planType;
public BBFilter(String planType) {
this.planType = planType;
}
}
This should fix the exception but you also can no longer inject it anywhere else (per #Autowire) if needed.
Declare bean of BBFilter like
#Bean
public BBFilter bbFilter() {
return new BBFilter("plan1");
}
And use it in BBBean like this
#Bean
public MyBean bbFilter() {
BBBean bbBean = new BBBean();
bbBean.setFilter(bbFilter());
}
And remove #Component and #Autowired from BBFilter

How to use spring #autowired annotation in the class having void methods?

I have an interface and service implements it. It has some void methods.
I am using spring java bean configuration. But unable to create bean object because of void methods.How to handle this problem.
I tried to use #PostConstruct instead of #Bean after reading some blogs, but it didn't work out.
public interface MyInterface {
void someData(List<MyClass> list, String somedata);
}
#Service("myInterface")
public DummyClass implements MyInterface {
public void someData(List<MyClass> list, String somedata){
// my business logic
}
}
public AppConfig {
#Bean
public MyInterface myInterface {
return new DummyClass(); // but gives error void cannot return value
}
}
My Junit looks like this
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(
classes = {AppConfig.class},
loader = AnnotationConfigContextLoader.class
)
public class MyTest {
#Autowired
DummyClass dummyClass;
// If I don't use AppConfig and simply autowire then I get
"Error creating bean name, unsatisfied dependency
}
How do I achieve dependency injection here?
Use #Configuration annotation on AppConfig class, with this all the beans defined on this class will be loaded on spring context.
If you use #Service annotation on DummyClass, you do not need to declare #Bean annotation because you are already saying to spring to detect this class for dependency injection. On the other hand use #Bean annotation to specify the instantiation of the class. Normally I let the #Bean to complex classes for dependency injection or to override configurations.

Autowire Bean with constructor parameters

I've got a bean with constructor parameters which I want to autowire into another bean using annotations. If I define the bean in the main config and pass in the constructor parameters there then it works fine. However, I have no main config but use #Component along with #ComponentScan to register the beans. I've tried using #Value property to define the parameters but then I get the exception No default constructor found;
#Component
public class Bean {
private String a;
private String b;
public Bean(#Value("a") String a, #Value("b") String b)
{
this.a = a;
this.b = b;
}
public void print()
{
System.out.println("printing");
}
}
#Component
public class SecondBean {
private Bean bean;
#Autowired
public SecondBean(Bean bean)
{
this.bean = bean;
}
public void callPrint()
{
bean.print();
}
}
The constructor for Bean needs to be annotated with #Autowired or #Inject, otherwise Spring will try to construct it using the default constructor and you don't have one of those.
The documentation for #Autowired says that it is used to mark a constructor, field, setter method or config method as to be autowired by Spring's dependency injection facilities. In this case you need to tell Spring that the appropriate constructor to use for autowiring the dependency is not the default constructor. In this case you're asking Spring to create SecondBean instance, and to do that it needs to create a Bean instance. In the absence of an annotated constructor, Spring will attempt to use a default constructor.
http://docs.spring.io/spring/docs/current/spring-framework-reference/html/beans.html

How to silently cancel bean creation?

#Component
public class MyBean {
#Autowired
public MyBean(#Value("${optional:#{null}}") String optional) {
if (optional == null) {
// cancel bean creation?
}
}
}
How to silently cancel bean creation? I could throw a RuntimeException, but I don't want this cancellation to be considered as an error: the bean must just not be created, the application initialization must go on.
Here you can make use of #Conditional
Step 1- Implement Condition.matches so as to specify when should the bean be created or not.
public class SomeCondition implements Condition {
#Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
return System.getProperty("optional") != null;
}
}
The condition class is referred as direct class (not as spring bean) so it can't use the #Value property injection. See here for alternative
Step 2 - In the configuration class specify the above class as condition to decide the bean creation
#Configuration
public class SomeAppConfig {
#Bean
#Condition(SomeCondition.class)
public MyBean myBean() {
return new MyBean();
}
}
P.S.: I have assumed that you use Java config.
It's not possible.
If you don't create a bean you can't use it. It's just a simple Java class and the property used/autowired in the bean are just useless.
However, you may configure profile base configuration beans for different kind of environments like 'Dev', 'Test' or 'Production'.
https://spring.io/blog/2011/02/14/spring-3-1-m1-introducing-profile/

Does Spring #Autowired inject beans by name or by type?

I am reading beginning spring (wiley press) book. In chapter 2 there is an example
about Java configuration and #Autowired. It provides this #Configuration class
#Configuration
public class Ch2BeanConfiguration {
#Bean
public AccountService accountService() {
AccountServiceImpl bean = new AccountServiceImpl();
return bean;
}
#Bean
public AccountDao accountDao() {
AccountDaoInMemoryImpl bean = new AccountDaoInMemoryImpl();
//depedencies of accountDao bean will be injected here...
return bean;
}
#Bean
public AccountDao accountDaoJdbc() {
AccountDaoJdbcImpl bean = new AccountDaoJdbcImpl();
return bean;
}
}
and this regular bean class
public class AccountServiceImpl implements AccountService {
#Autowired
private AccountDao accountDao;
public void setAccountDao(AccountDao accountDao) {
this.accountDao = accountDao;
}
...
}
When I run the code, it works. But I expected an exception because I have defined 2 beans with the same type in the configuration.
I realized it works like this:
if Spring encounters multiple beans with same type it checks field name.
if it finds a bean with the name of the target field, it injects that bean into the field.
Isn't this wrong? Is there a bug in Spring's handling of Java configuration?
The documentation explains this
For a fallback match, the bean name is considered a default qualifier
value. Thus you can define the bean with an id "main" instead of the
nested qualifier element, leading to the same matching result.
However, although you can use this convention to refer to specific
beans by name, #Autowired is fundamentally about type-driven injection
with optional semantic qualifiers. This means that qualifier values,
even with the bean name fallback, always have narrowing semantics
within the set of type matches; they do not semantically express a
reference to a unique bean id
So, no, it's not a bug, that is the intended behavior. The bean id (name) will be used as a fallback if a by-type autowiring doesn't find a single matching bean.

Categories