Using a property as a qualifier for Dependency Injection in spring - spring

Is it possible to #Autowire a bean by name (ie. use a #Qualifier) but get the name of the bean from a property set by the BeanFactoryPostProcessor. So in short something like this:
#Autowired
#Qualifier(#Value("${name.of.my.object}"))
private MyObject obj;
Assuming that there are more than one MyObject beans that have been created and there is a property called name.of.my.object=foo in my properties files read by the PropertyPlaceholderConfigurer

That would be nice, but I don't think you can do such a thing.
The closest I can think of is to define a bean alias in XML:
<alias bean="${name.of.my.object}" alias="myAlias"/>
and then refer to the alias in the qualifier:
#Autowired
#Qualifier("myAlias")
private MyObject obj;
Not very elegant, and I haven't actually tried it before, but I think it should work.

Related

ApplicationContext get annotated bean by name

Tried to search for an answer - no luck, so posting a question.
I have
#ConfigurationProperties
class XYZConfig {
int f1....
}
I'm trying later to get this bean by name in my application, but the only one name available is a fully qualified one. I tried to use #Component(value="xyzconfig") no luck either
I wonder if there is a way to set a short name for the bean without going into xml and specifying it explicitly?
I don't fully understand what are you trying but if you class XYZConfig should be configuration class and there will be created beans than you need to annotate this class with #Configuration. Also in your context .xml file you need to add <annotation-driven/> and set <context:component-scan base-package="your.package.wit.classes.for.scanning"></context:component-scan>.
But, if this class really has to be Bean then create simple java class (i.e.: BeanClass) and later in your configuration create method like this:
#Bean
public BeanClass beanClassName(){
BeanClass bc = new BeanClass()
...
return bc;
Later this bean will be visible with id/name beanClassName

Beginner confusion about autowiring in Spring

All:
I just begin the Spring study, there is one concept confused me so much: The Autowiring.
The question I need to be clear is:
What kind of thing can be autowired? Is it only other beans?
If I define a class Bar:
public class Bar {
#Autowired
public String name;
}
I am thinking what if I put a #Autowired annotation to a member variable like String name; and in bean config XML I wrote:
<bean id="bar" class="com.Bar">
<property name="name" value="Bar" />
</bean>
So many ways to do same thing in Spring confused me so much. ToT.
Is there any good trick to clearly remember and tell diff among different ways?
Thanks
Yes, You can only #Autowired Beans. #Autowired is the way of using Dependency Injection in Spring. It is provided for Beans - components wrote once and used many times. There's no sense using DI on String property and I think You get Exception.
You can't autowire in a String value like you have done.
By writing your XML bean declaration, what you have done is created a singleton instance of Bar with the name field set to the value of 'Bar'.
If you wanted to then use this Bar class elsewhere in your application (say in a class called Foo) you could do this:
public class Foo {
#Autowired
private Bar bar;
}
Spring would then inject your instance of Bar into your Foo class.
However because Bar is a singleton by default, no matter how many instances of Bar you autowired into different classes, you would have the same instance of Bar in all of them. So if you try and modify name in one class, it will change for all the other classes.
As a general rule of thumb, if your class has any mutable data (data that will be changed and updated), then your class is not something that you should be declaring for autowiring (because there will only ever be one instance of it inside your Spring application). It works better for things like DAO's and service classes. In answer to your first question, yes you can only autowire instances of classes (beans).
If you need to get a String/Integer/Long/Array/Mutable Data Type value from somewhere, configure a properties file, and read up how to use the org.springframework.beans.factory.config.PropertyPlaceholderConfigurer class with the #Value annotation.

How to override a Spring #Autowire annotation and set a field to null?

I am a Spring neophyte who is working on a large Spring-based project that has extensive coupling between Spring beans. I am trying to write some integration tests that exercise subsets of the total application functionality. To do so, I'd like to override some of the autowiring.
For example, suppose I have a class
public class MyDataServiceImpl implements MyDataService {
#Qualifier("notNeededForMyDataServiceTest")
#Autowired
private NotNeededForMyDataServiceTest notNeededForMyDataServiceTest;
//...
}
and a context file with:
<bean id="myDataService"
class="MyDataServiceImpl">
</bean>
In my test, I have no need to use the notNeededForMyDataServiceTest field. Is there some way I can override the #Autowired annotation and set notNeededForMyDataServiceTest to null, perhaps in the XML file? I don't want to modify any of the Java classes, but I do want to avoid the (problematic) configuration of notNeededForMyDataServiceTest.
I tried doing:
<bean id="myDataService"
class="MyDataServiceImpl">
<property name="notNeededForMyDataServiceTest"><null/></property>
</bean>
That doesn't work. IntelliJ informs me "Cannot resolve property 'notNeededForMyDataServiceTest'", apparently because there are no getters and setters for that field.
I'm using Spring Framework 3.1.3.
The following configuration should work, I took the liberty of mixing in Java configuration
#Configuration
//This will load your beans from whichever xml file you are using
#ImportResource("classpath:/path/beans.xml")
public class TestConfigLoader{
// This will declare the unused bean and inject MyDataServiceImpl with null.
public #Bean(name="notNeededForMyDataServiceTest") NotNeededForMyDataServiceTest getNotNeededForMyDataServiceTest(){
return null;
}
... any other configuration beans if required.
}
And annotate your test class like so:
// In your test class applicationContext will be loaded from TestConfigLoader
#ContextConfiguration(classes = {TestConfigLoader.class})
public class MyTest {
// class body...
}
These could help:
Context configuration with annotated classes
Testing with #Configuration Classes and Profiles
Spring TestContext Framework
and profiles:
beans profile="..."
Introducing #Profile
You could create different beans definition in the XML configuration and then activate them using the -Dspring.profiles.active="profile1,profile2" env.
You're using the #Autowired mechanism wrong. The qualifier is not a property that you need to set. That's actually the name of a bean, so that the container will be able to choose one particular instance in case multiple beans of the same type are defined in the same context.
So the container will look for a bean of type NotNeededForMyDataServiceTest and the name (which would actually be the bean id in XML): notNeededForMyDataServiceTest.
What I think you want is to instruct the container to not inject anything in that field if no bean of type NotNeededForMyDataServiceTest is defined in the application context. That could be achieved simply by setting the required attribute of the annotation to false:
#Autowired(required = false)
NotNeededForMyDataServiceTest someOptionalDependency;
The only drawback of this approach would be that the container will never complain at runtime if there's nothing to inject in that field (and perhaps you would want this sanity check when your code runs in production).
If you don't want to make that dependency optional (or you can't edit that code for some reason), you'll need to provide a mock / null value for that field by setting that explicitly in your context. One option to do that would be to use Java configuration instead of XML (like in #Abe's answer) and another approach would be to make use of a factory bean which returns null (like in this question).

How to make Spring #autowired annotation to pick a certain type without using #Qualifier?

Is there a way to specify the default type for Spring #autowired annotation? For example, I have bean ValidatorA and bean ValidatorB that extends ValidatorA.
The ValidatorA is used in some other places and is injected using #autowired.
Is there a way to force Spring to inject ValidatorB instead of ValidatorA without changing the existing code?
The only solution I found at How to override the behavior of Spring #Autowired suggests to exclude ValidatorA from the context.
Is there any other way?
For example, with Guice I would just bind the ValidatorA.class to ValidatorB.class and that will do exactly what I need.
I have no problem to add #Qualifier to ValidatorB but ValidatorA should stay unchanged.
Guice provides ability to define "Providers", is there something similar in Spring? Maybe with #Configuration annotation?
I think you could use primary indicator there. If your bean is defined through annotation, add #Primary to ValidatorB definition. If you are using xml config add primary="true" to <bean> definition.
Is there a way to force Spring to inject ValidatorB instead of ValidatorA without changing the existing code?
Without changing the code, I doubt it very much. You could change the app context or alter the code something like this :
#Component
#Qualifier("B")
public class ValidatorB extends ValidatorA {
}
and then inject like so (there are other syntactic options as well)
#Resource
#Qualifier("B")
private ValidatorA validatorB;

Why is there a need to specify the class in both the xml file and in the getBean() method in Spring

This might be an obvious but I'm having a hard time understanding why we need to define the class of a bean in two places....
From the spring reference manual...
...
<bean id="petStore"
class="org.springframework.samples.jpetstore.services.PetStoreServiceImpl">
<property name="accountDao" ref="accountDao"/>
<property name="itemDao" ref="itemDao"/>
<!-- additional collaborators and configuration for this bean go here -->
</bean>
// retrieve configured instance
PetStoreServiceImpl service = context.getBean("petStore", PetStoreServiceImpl.class);
Shouldn't the xml fine be enough for the container to know the class of petStore?
You can use the following method:
context.getBean("petStore")
However, as this returns a java.lang.Object, you'd still need to have a cast:
PetStoreServiceImpl petstore = (PetStoreServiceImpl)context.getBean("petStore");
However, this could lead to problems if your "petStore" bean is not actually a PetStoreServiceImpl, and to avoid casts (which since the advent of Generics are being seen as a bit dirty), you can use the above method to infer the type (and let's spring check whether the bean you're expecting is really of the right class, so hence you've got:
PetStoreServiceImpl service = context.getBean("petStore", PetStoreServiceImpl.class);
Hope that helps.
EDIT:
Personally, I would avoid calling context.getBean() to lookup methods as it goes against the idea of dependency injection. Really, the component that uses the petstore bean should have a property, which can then be injected with the correct component.
private PetStoreService petStoreService;
// setter omitted for brevity
public void someotherMethod() {
// no need for calling getBean()
petStoreService.somePetstoreMethod();
}
Then you can hook up the beans in the application context:
You could also do away with the configuration via XML and use annotation to wire up your beans:
#Autowired
private PetStoreService petStoreService;
As long as you've got
in your spring context, the "petStore" bean defined in your application context will automatically be injected. If you've got more than one bean with the type "PetStoreService", then you'd need to add a qualifier:
#Autowired
#Qualifier("petStore")
private PetStoreService petStoreService;
There's no requirement to specify the class in the getBean() method. It's just a question of safety. Note there's also a getBean() that takes only a class so that you can just look up beans by type instead of needing to know the name.

Resources