Autowired not working as expected - spring

I'm using Spring Roo and want to access a bean within of Controller class which has following configuration in applicationContext.xml:
<bean class="com.reservation.jobs.Configuration" id="jobsConfiguration" autowire="byType">
<property name="skipWeeks" value="4" />
</bean>
The configuration class itself is:
package com.reservation.jobs;
public class Configuration {
private int skipWeeks;
public void setSkipWeeks(int value) {
System.out.println("SkipWeeks set auf: " + value);
this.skipWeeks = value;
}
public int getSkipWeeks() {
return this.skipWeeks;
}
}
In my Controller I thought that a simple Autowired annotation should do the job
public class SomeController extends Controller {
#Autowired
private com.reservation.jobs.Configuration config;
}
During startup Spring prints the message within the setSkipWeeks method. Unfortunately whenever I call config.getSkipWeeks() within the controller it returns 0.
Have I to use the getBean method of the ApplicationContext instance or is there some better way?

autowire="byType" is redundant. It indicates that fields of the Configuration class should be autowired, and you have just one primitive. So remove that attribute.
Apart from that, config.getSkipWeeks() must return 4 unless:
you are using a different instance (made by you with new)
you have called the setter somewhere with a value of 0

Related

how to load spring bean from another class

I have loaded "myspring.xml" in web.xml using context-param
in "myspring.xml" I have written bean to which I have passed arguments as constructor argument
<bean id="abc" class="com.Hello">
<constructor-arg ref="dataSource"/>
<constructor-arg value= “dummy data”/>
</bean>
in Hello bean I have initialized constructor as ,
public class Hello{
public Hello(datasource,dummydata){
}
public void methodFromHelloBean(){
// use here dummydata from constructor
}
}
Here , 'Hello' bean is getting initialized at server startup, as I defined in web.xml and it is working fine.
My question is -
I am working on exisitng applciation.
I want to call methodFromHelloBean() inside my another class say MyService class.
How I can call the method in MyService class.
One way i know is using applicationContext.
But in my existing application I have not seen any bean loaded using application-context path.
what is other way , how I can initialize 'Hello' bean from 'MyService' class.
Do I need to pass parameters to constructors while initializing & how.
Thanks in advance.
Let's suppose we have MyService a class whose bean instance consumes some method methodFromHelloBean from abc, the Hello bean.
public class Hello {
private boolean cacheInitialized;
public void methodFromHelloBean(Object param) {
if (!cacheInitialized) {
initializeCache(param);
cacheInitialized = true;
}
// do whatever you please with cache.
}
private void initializeCache(Object param) {
// TODO
}
}
public class MyService {
#Autowired
private Hello abc;
public void someMethod() {
// determine which parameters to pass to abc
Object param = ...
abc.methodFromHelloBean(param);
}
}

autowire byType according to Spring 4.1.6 to Documentation

Allows a property to be autowired if exactly one bean of the property type exists in the container. If more than one exists, a fatal exception is thrown, which indicates that you may not use byType autowiring for that bean. If there are no matching beans, nothing happens; the property is not set. - FROM SPRING REFERENCE GUID 4.1.6
<bean id="person" class="autowire.Person" autowire="byType" />
<bean id="invisible" class="autowire.Ability" >
<property name="skill" value="Invisible" />
</bean>
<bean id="invisible2" class="autowire.Ability" >
<property name="skill" value="Invisible" />
</bean>
Class Definitions:
package autowire;
public class Person
{
private Ability ability;
//...
}
package autowire;
public class Ability {
private String skill;
public String getSkill() {
return skill;
}
public void setSkill(String skill) {
this.skill = skill;
}
}
I was able to define 2 beans of same type of class "autowire.Ability". I didnt get the Fatal exception. Is my understanding correct ?
You're almost there (to get the error). You need to tell spring which class attributes need to be autowired. Annotate Person.ability with #Autowired and you should get the error.
import org.springframework.beans.factory.annotation.Autowired;
public class Person
{
#Autowired
private Ability ability;
//...
}
Or even better create a constructor and autowire it, as injecting attributes is considered a bad practice.
public class Person
{
private Ability ability;
#Autowired
public Person(Ability ability) {
this.ability = ability;
}
//...
}
Spring doesn't assume which attributes need to be injected (autowired) so you need to specify which ones you want to inject.
The behavior you're seeing is correct, you can define as many beans of the same type as you want, problem arises when an Autowired bean(Component, Service, etc), expects a dependency of certain type and it cannot resolved because there are many that matches the field definition, for example:
If Person is declared as a #Component and declare an #Autowired field of type Ability, for example:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
#Component
public class Person {
#Autowired
private Ability ability;
}
Having the two beans invisible and invisible2 would cause the expected exception because Spring won't be able to know which of the two beans need to be injected in Person.
To run this example you will need to enable a Scan application context.
Hope this helps,
José Luis

#Autowired on setter function does not look at the property name (like autowired in XML does)

I am moving from XML to annotations.
I have the interface types House and My , and class types HouseImpl and MyImpl. Spring injects an MyImpl instance into and MouseImpl instance,
public class HouseImpl implements House
private My my;
public My getMy2() {
return my;
}
#Autowired
public void setMy2(My my) {
this.my = my;
}
So the property in HouseImpl is called my2.
In the Spring configuration file,
<context:annotation-config></context:annotation-config>
<bean
id="house"
class="....HouseImpl"
>
...
</bean>
<bean
id="my"
class="my.test.own.spring_book_annotations.MyImpl"
>
</bean>
<bean
id="my2"
class="my.test.own.spring_book_annotations.MyImpl2"
>
</bean>
If the configuation is in XML, so there is autowired="byName" in the house configuration, and no #Autowired annotation, then bean my2 is injected, because the property name is my2 (setMy2 is the method). But when we use annotations bean my is injected, because the name of the argument of setMy2 is my.
My question is why #Autowired on the setter function does not look at the property name.
When #Autowired is used on a setter and there are multiple matching types, the container will look at the parameter name to find the bean to inject. In your case, the parameter is My my, so the my bean will be injected. You can change the parameter to My my2, or use #Qualifier("my2") to inject the my2 bean.
If you want to use the field name, place #Autowired on the field itself to use field-injection.
Your code is like this
#Autowired
public void setMy2(My my) {
this.my = my;
}
When you write annotation #Autowired, it will take the bean with setXXX name....here XXX is My2.
Hence your bean with my2 id is injected.
In order to specify the bean with id as my user #Qualifier annotation.
#Autowired
#Qualifier("my")
public void setMy2(My my) {
this.my = my;
}

Injecting property using #Value to abstract class

I have an abstract class in which I am trying to use the #Value annotation to inject value from a property file
public abstract class Parent {
#Value ("${shared.val}")
private String sharedVal;
public Parent() {
//perform common action using sharedVal
}
}
#Component
public class ChildA extends Parent {
Param a1;
#Autowired
public ChildA (Param a1) {
super();
this.a1 = a1;
}
}
I am getting NullPointerException since sharedVal is not set. I tried adding #Component stereotype on the abstract class and still the same thing.
Can I inject value into abstract class this way? If not how can accomplish this?
I think you'll find the sharedVal is being set, but you're trying to use it too soon in the constructor. The constructor is being called (must be called) before Spring injects the value using the #Value annotation.
Instead of processing the value in the constructor, try a #PostContruct method instead, eg:
#PostConstruct
void init() {
//perform common action using sharedVal
}
(or alternatively, implement Spring's InitializingBean interface).
Can I inject value into abstract class this way?
Abstract classes cannot be instantiated, so nothing can be injected into the abstract class. Instead , you should inject the value to its concrete subclass.
Make sure your concrete subclass is marked as #Component stereotype and being "component scanning" by Spring . #Component on the abstract class is not needed as it cannot be instantiated.
Update : I finally figure out that you are trying to access the injected value inside the constructor but found that the value is not set. It is because Spring will inject the value after the bean is instantiated . So if constructor injection is not used , the injected value cannot be accessed inside the constructor . You can use #PostContruct or implementing InitializingBean as suggested by Matt.
Following shows if XML configuration is used :
<context:property-placeholder location="classpath:xxxxx.properties" ignore-unresolvable="true" />
<bean id="parent" class="pkg.Parent" abstract="true" init-method="postConstruct">
<property name="sharedVal" value="${shared.val}" />
</bean>
<bean id="child" class="pkg.ChildA" parent="parent">
Perform your common action using sharedVal inside Parent#postConstruct()

Accessing a session-scoped bean inside a controller

I'm experimenting with session-scoped beans in Spring 3. I have the following bean definition:
<bean id="userInfo" class="net.sandbox.sessionbeans.UserInfo" scope="session" />
Here is net.sandbox.controllers.RegistrationController, a controller class that needs access to this bean. I've taken out the imports for brevity's sake.
#Controller
#RequestMapping("/register")
public class RegistrationController {
private UserInfo userInfo; // This should reference the session-scoped bean
#RequestMapping(method = RequestMethod.GET)
public String showRegForm(Model model) {
RegistrationForm regForm = new RegistrationForm();
model.addAttribute("regform", regForm);
return "regform";
}
#RequestMapping(method = RequestMethod.POST)
public String validateForm(#Valid RegistrationForm regForm, BindingResult result, Model model) {
if (result.hasErrors()) {
return "regform";
}
userInfo.setUserName(regForm.getFirstName());
model.addAttribute("regform", regForm);
return "regsuccess";
}
}
Is there a way to automatically tie the session-scoped bean I defined to the member variable private UserInfo userInfo in RegistrationController?
Yes - see section 3.4.5.4 of the Spring manual, "Scoped beans as dependencies".
Briefly, you can ask Spring to wrap your session-scoped bean in a singleton proxy, which looks up the correct session when you invoke a method on the scoped bean. This is called a "scoped proxy", and uses the <aop:scoped-proxy> config macro. You can then inject the reference as you would any other (e.g. <property>, or #Autowired). See the above link for details.
By default, Spring creates a proxy by implementing an interface at run-time. So, the only methods available on the proxy are those defined in any interfaces UserInfo implements (if any). You may have to create a suitable interface that includes the setUserName() method.
Alternatively, you will need to force a CGI based proxy (the proxy is a sub-class of your class created at run-time so it doesn't need an interface). Specify:
<bean id="userInfo" class="net.sandbox.sessionbeans.UserInfo" scope="session" >
<aop:scoped-proxy proxy-target-class="true"/>
</bean>
About this comment:
I tried applying this technique. I put
inside the bean
definition and I #Autowired'd private
UserInfo userInfo. It seems to work,
but for some reason the bean's setter
function isn't executed properly...
i.imgur.com/zkxVA.png – Pieter 1 hour
ago
If you use interface-based proxies, the setter method is not available on the Proxy unless the interface has the setter method.
If you don't like XML, you can also use ObjectFactory<T> like this :
#RestController
public class MyController {
private final ObjectFactory<MySessionScopedComponent> OFSession;
#Autowired
public MyController(ObjectFactory<MySessionScopedComponent> OFSession) {
this.OFSession = OFSession;
}
#RequestMapping(path = "/path", method = RequestMethod.GET)
public String myMethod () {
MySessionScopedComponent sessionBean = OFSession.getObject();
// Do some stuff
return bean.myValue();
}
}
Note: Tested with Spring Boot 1.5.6 (Spring 4.3)

Resources