injecting beans into spring java config classes - java

I have a configuration class which uses the #Configuration annotation and also extends the RepositoryRestMvcConfiguration.
as part of the extended class, there are overridable methods that allow configuration of the bean recipes. one of which is configuring the conversion services available to the spring component.
I would like to inject some beans into a list that is iterated over and added as a conversion service through this overrided method, My configuration java class is defined below:
#Configuration
#EnableJpaRepositories(basePackages = "com.example.model.repositories")
public class DataConfig extends RepositoryRestMvcConfiguration {
List<Converter<?,?>> converters;
//get
//set
#Override
protected void configureConversionService(ConfigurableConversionService conversionService){
for(Converter converter : converter){
conversionService.addConverter(converter);
}
}
}
The following defines my converters that i wish to inject in the app-context.xml file
<beans>
<bean id="fooToBarConverter" class="com.example.model.converters.FooToBarConverter" />
<bean id="barToFooConverter" class="com.example.model.converters.BarToFooConverter" />
<util:list id="myConverters" value-type="org.springframework.core.convert.converter.Converter">
<ref bean="barToFooConverter"/>
<ref bean="fooToBarConverter" />
</util:list>
</beans>
Is there a better way of providing these converters through spring configuration or do i need to explicitly list them as output of a function contained within my configuration class like:
#Bean
public List<Converter<?,?> myConverters(){
Arrays.asList(new FooToBarConverter(), new BarToFooConverter());
}
Your help is highly appreciated.
P.S. since you are so good at spring, would you mind having a look at my spring-data-rest-mvc related question? please and thank you.

By default, any #Autowired (or #Resource) annotated Collection (or List, Set, etc) of a certain type will contain all beans of that type discovered in the context. You could add an #Autowired in your setter and let Spring injects your controller for you.
If you need a more fine-grained control over which converters should be configured and which one should not, maybe you should configure the ConversionService altogether instead.

Related

Spring #Service annotation with more values

I would like to ask if there is possible in spring to annotate class with #Service with more than 1 value, something like this:
#Service({"ServiceName1","ServiceName2"})
public class ClassName {
}
The reason is i want to get same class when i am calling applicationContext.getBean("ServiceName1"); or applicationContext.getBean("ServiceName2");
Thanks in advance for answers.
You can just declare your bean in a configuration class instead, and specify multiple names in the Bean annotation:
#Bean(name = { "ServiceName1", "ServiceName2" })
public ClassName myService() {
return new ClassName();
}
But if you're getting beans by name, from the application context, you've probably missed the whole point of dependency injection.
I think if we use #Component/ #Service annotations we can create only one bean instance for a class. If we need to create multiple beans for a single class we need to go with xml approach. Define the beans for the single Class in applicationContext.xml
<bean id="ServiceName1" class="<ClassName Path>">
</bean>
<bean id="ServiceName2" class="<ClassName Path>">
</bean>

Understanding spring #Configuration class

Following the question Understanding Spring #Autowired usage I wanted to create a complete knowledge base for the other option of spring wiring, the #Configuration class.
Let's assume I have a spring XML file that looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<import resource="another-application-context.xml"/>
<bean id="someBean" class="stack.overflow.spring.configuration.SomeClassImpl">
<constructor-arg value="${some.interesting.property}" />
</bean>
<bean id="anotherBean" class="stack.overflow.spring.configuration.AnotherClassImpl">
<constructor-arg ref="someBean"/>
<constructor-arg ref="beanFromSomewhereElse"/>
</bean>
</beans>
How can I use #Configuration instead? Does it have any affect on the code itself?
Migrating XML to #Configuration
It is possible to migrate the xml to a #Configuration in a few steps:
Create a #Configuration annotated class:
#Configuration
public class MyApplicationContext {
}
For each <bean> tag create a method annotated with #Bean:
#Configuration
public class MyApplicationContext {
#Bean(name = "someBean")
public SomeClass getSomeClass() {
return new SomeClassImpl(someInterestingProperty); // We still need to inject someInterestingProperty
}
#Bean(name = "anotherBean")
public AnotherClass getAnotherClass() {
return new AnotherClassImpl(getSomeClass(), beanFromSomewhereElse); // We still need to inject beanFromSomewhereElse
}
}
In order to import beanFromSomewhereElse we need to import it's definition. It can be defined in an XML and the we'll use #ImportResource:
#ImportResource("another-application-context.xml")
#Configuration
public class MyApplicationContext {
...
}
If the bean is defined in another #Configuration class we can use the #Import annotation:
#Import(OtherConfiguration.class)
#Configuration
public class MyApplicationContext {
...
}
After we imported other XMLs or #Configuration classes, we can use the beans they declare in our context by declaring a private member to the #Configuration class as follows:
#Autowired
#Qualifier(value = "beanFromSomewhereElse")
private final StrangeBean beanFromSomewhereElse;
Or use it directly as parameter in the method which defines the bean that depends on this beanFromSomewhereElse using #Qualifier as follows:
#Bean(name = "anotherBean")
public AnotherClass getAnotherClass(#Qualifier (value = "beanFromSomewhereElse") final StrangeBean beanFromSomewhereElse) {
return new AnotherClassImpl(getSomeClass(), beanFromSomewhereElse);
}
Importing properties is very similar to importing bean from another xml or #Configuration class. Instead of using #Qualifier we'll use #Value with properties as follows:
#Autowired
#Value("${some.interesting.property}")
private final String someInterestingProperty;
This can be used with SpEL expressions as well.
In order to allow spring to treat such classes as beans containers we need to mark this in our main xml by putting this tag in the context:
<context:annotation-config/>
You can now import #Configuration classes exactly the same as you would create a simple bean:
<bean class="some.package.MyApplicationContext"/>
There are ways to avoid spring XMLs altogether but they are not in the scope of this answer. You can find out one of these options in my blog post on which I'm basing my answer.
The advantages and disadvantages of using this method
Basically I find this method of declaring beans much more comfortable than using XMLs due to a few advantages I see:
Typos - #Configuration classes are compiled and typos just won't allow compilations
Fail fast (compile time) - If you forget to inject a bean you'll fail on compile time and not on run-time as with XMLs
Easier to navigate in IDE - between constructors of beans to understand the dependency tree.
Possible to easily debug configuration startup
The disadvantages are not many as I see them but there are a few which I could think of:
Abuse - Code is easier to abuse than XMLs
With XMLs you can define dependencies based on classes that are not available during compile time but are provided during run-time. With #Configuration classes you must have the classes available at compile time. Usually that's not an issue, but there are cases it may be.
Bottom line: It is perfectly fine to combine XMLs, #Configuration and annotations in your application context. Spring doesn't care about the method a bean was declared with.

Spring: Xml based Autowiring a list of beans by interface type

With Spring it is possible to inject a list of beans by the interface class like:
#Component
public class Service {
#Autowire
private List<InterfaceType> implementingBeans;
...
}
All defined beans that implement this interface will be present in this List.
The annotation based approach is not possible for me, as the Service class is in a module that must not have spring dependencies.
I need to use this mechanism from outside via xml configuration.
<bean id="service" class="...Service">
<property name="implementingBeans">
??? tell spring to create a list bean that resolves all beans of the interfaceType.
</property>
</bean>
Does anyone know how to solve this?
EDIT: Additionally, there are more than one spring applications that use this service. So the best solution would be to handle this szenario completely via xml configuration. I can then copy the xml parts to all spriong applications that need this.
I want to avoid having a kind of initializer bean that gets the service injected and must then be copied to all spring applications.
Kind regards.
An XML-only solution would simply have you declare a <bean> of the "external" type and provide an autowire value of "byType".
Controls whether bean properties are "autowired". This is an
automagical process in which bean references don't need to be coded
explicitly in the XML bean definition file, but rather the Spring
container works out dependencies.
[...]
"byType" Autowiring if there is exactly one bean of the property type in the container. If there is more than one, a fatal error is
raised, and you cannot use byType autowiring for that bean. If there
is none, nothing special happens.
The explanation is a little confusing in that we expect multiple InterfaceType beans, but the actual field is of type List and Spring will be able to dynamically instantiate one and add all the InterfaceType beans to it, then inject it.
Your XML would simply look like
<bean id="service" class="...Service" autowire="byType">
</bean>
My original suggested solution made use of SpEL.
In the module that does have Spring dependencies, create a DTO
#Component(value = "beanDTO")
public class BeanDTO {
#Autowire
private List<InterfaceType> implementingBeans;
public List<InterfaceType> getImplementingBeans() {
return implementingBeans;
}
}
and then use SpEL to retrieve the value of implementingBeans from the beanDTO bean.
<bean id="service" depends-on="beanDTO" class="...Service">
<property name="implementingBeans" value="{beanDTO.implementingBeans}" />
</bean>
Spring will create the BeanTDO bean, inject all the beans that are of type InterfaceType. It will then create the service bean and set its property from beanDTO's implementingBeans property.
Following comments on question:
In an effort to be more JSR 330 compliant, Spring has introduced support for Java EE's javax.inject package. You can now annotate your injection targets with #javax.inject.Inject instead of #Autowired. Similarly, you can use #Named instead of #Component. The documentation has more details.

Declaration of beans in applicationContext.xml

I have a question regarding declaration of classes in applicationContext.xml
In applicationContext.xml do we need to specify all the classes from the application?
E.g.
In my small web application I have a Entity class, Service class and DAO class. So currently it is defined as
<!-- Beans Declaration -->
<bean id="Employees"
class="net.test.model.Employees" />
<!-- User Service Declaration -->
<bean id="
EmployeeService" class="net.test.employees.service.EmployeeService">
<property name="employeesDAO" ref="EmployeeDAOImpl" />
</bean>
<!-- User DAO Declaration -->
<bean id="EmployeeDAO" class="net.test.employee.dao.EmployeeDAOImpl">
<property name="sessionFactory" ref="SessionFactory" />
</bean>
So if I have multiple entity, service and dao classes do I need to mention all those classes in applicationContext.xml?
Any insight into this is highly appreciable.
Regards
Update 1
ManagedBean
#ManagedBean(name="empMB")
#Named
#Scope("request")
public class EmployeesManagedBean implements Serializable {
and I have Inject annotation
#Inject
EmployeesService employeesService;
In EmployeesService I have annotations like
#Named
public class EmployeesService implements IEmployeesService {
#Inject
EmployeesDAO employeesDAO;
#Override
public List<Employees> getEmployees() {
return getEmployeesDAO().getEmployees();
}
and finally in applicationContext.xml I have
<context:component-scan base-package="net.test" />
Now the problem is when I run my application I am getting
java.lang.NullPointerException at
net.test.managed.bean.EmployeesManagedBean.getEmpList(EmployeesManagedBean.java:53)
What am I doing wrongly to get nullpointer exception?
In applicationContext.xml do we need to specify all the classes from
the application?
No. Declaring model classes like your net.test.model.Employees is pointless unless you need a prototype to work with, something like initializing its values, but you can do this directly in the class and just instantiate it.
So if I have multiple entity, service and dao classes do I need to
mention all those classes in applicationContext.xml?
As I explained before, entity classes no. Services and DAOs are ok because most of the time you need DAOs injected to the Services (and that's the point of DI). But of course, if you create 3 DAOs and you want them to be injected in your 3 Services, then mention them in your Spring XML Bean Definition file (what you call applicationContext.xml).
But one thing, you may want to use package scanning autodetection and annotation based config to avoid writing everything in your Bean Definition File.
The bean declaration in the application context is to register the bean in the application container.
If the bean is not registered, the container wouldn't be able to dependency inject any instance of that class, or apply interceptors to the object of the class.
So unless the reference of bean is not required for any task like intercepting it or inject it, or create default singleton object of it, there is no need to declare it in the applicationContext.xml
Hope this helps.
Ideally yes, another way can be using Spring Annotations so that you don't to add multiple entries in xml.

benefit of #Autowired annotation in Java

Maybe, because of my wrong English, I couldn't understand the benefit of using #Autowired annotation.
According to the tutorial we can simplify the first(I.) case to second case(II.) by means of #Autowired.
My question is, what is the meaning of the #Autowired ? Because it doesnt tell any more, since without using #Autowired the compiler can figure out that "EmpDao emDao" and "EmpManager" are closely related according the declaration.
code cited from here
I.
<bean id="empDao" class="EmpDao" />
<bean id="empManager" class="EmpManager">
<property name="empDao" ref="empDao" />
</bean>
public class EmpManager {
private EmpDao empDao;
public EmpDao getEmpDao() {
return empDao;
}
public void setEmpDao(EmpDao empDao) {
this.empDao = empDao;
}
...
}
II.
<context:annotation-config />
<bean id="empManager" class="autowiredexample.EmpManager" />
<bean id="empDao" class="autowiredexample.EmpDao" />
import org.springframework.beans.factory.annotation.Autowired;
public class EmpManager {
#Autowired
private EmpDao empDao;
}
#Autowired is spring-specific. #Inject is the standard equivallent. It is an annotation that tells the context (spring, or in the case of #Inject - any DI framework) to try to set an object into that field.
The compiler has nothing to do with this - it is the DI framework (spring) that instantiates your objects at runtime, and then sets their dependencies at the points you have specified - either via XML or via an annotation.
I agree it is a possible scenario for a DI framework to try to inject dependencies into all fields, even if they are not annotated. (And if you want to exclude a particular field, to annotate it). But they chose the other strategy (configuration-over-convention). By the way:
if using xml config and choose some form of autowiring, the dependencies of the bean will be automatically autowired without the need to specify anything
you can specify per-context autowiring settings.
When the server bootstraps itself. It finds
<context:annotation-config />
in the application context and then goes through the classes defined in the contexts. If there are any beans that are autowired, it injects that into the class by referring the context file.
Basically, it promotes convention over configuration. That's what most frameworks do these days to reduce the development time.
the #Autowired Spring annotation tells Spring to for a bean named 'empDao' and inject it into the EmpManager class, without you having to add the empDao bean as a property in your spring config file.
#Autowired tells Spring to find a bean of the declared type and wire in that bean, rather than requiring an explicit lookup by bean name. It can, under certain circumstances, make configuring applications easier if you only have one implementation of your types in a given Spring context.

Categories

Resources