calling a Spring bean from java class explicitly - java

I have a file named abc.xml i which the below bean is defined , request you to please advise how can i call this bean in my java class explicitly , i want to call this bean as reference of this bean is there in my class so i want to call this bean from my java class explicitly
below is the spring bean defined in abc.xml
<bean id="springJobExecutor" class="com.scheduler.autosys.core.SpringBeanJobExecutor" singleton="false"/>
and i want to call this bean from java class explicitly please advise

Do you mean simple injection? You have to create ApplicationContext object and get an instance from it:
ApplicationContext context = new ClassPathXmlApplicationContext("abc.xml");
SpringBeanJobExecutor springJobExecutor =
context.getBean("springJobExecutor", SpringBeanJobExecutor.class);
Or if you mean dependency injection using constructor...
<bean id="springJobExecutor"
class="com.scheduler.autosys.core.SpringBeanJobExecutor" singleton="false"/>
<bean id="myObject" class="myClass" >
<constructor-arg index="[argument_index]" ref="springJobExecutor"/>
</bean>
or using setter...
<bean id="springJobExecutor"
class="com.scheduler.autosys.core.SpringBeanJobExecutor" singleton="false"/>
<bean id="myObject" class="myClass" >
<property name="[name]" ref="springJobExecutor"/>
</bean>
and finally getting the object in main...
MyClass myObject = context.getBean("myObject", MyClass.class);

Related

Creating 2 beans of the same class with different constructor-args and using autowiring

Hi I working on a project, in which I need to create 2 instances of bean of same class but different constructor-args. Right now have functionality only for "production environment", so I have xml file like:
<context:component-scan base-package="com.xxx.yyy" />
<bean id="id1" class="someCompanySpecificURLForTheClass" scope="singleton"/>
<bean name="name1" factory-bean="id1" factory-method="createFullClient">
<constructor-arg index="0">
<ref bean="someJSONBean"/>
</constructor-arg>
<constructor-arg value="productionEnv" index="1"/>
</bean>
</beans>
Now I need to include functionality for testing environment also. So I changed the xml file to:
<context:component-scan base-package="com.xxx.yyy" />
<context:component-scan base-package="com.zzz.yyy" />
<bean id="id1" class="someCompanySpecificURLForTheClass" scope="prototype"/>
<bean name="name1" factory-bean="id1" factory-method="createFullClient">
<constructor-arg index="0">
<ref bean="someJSONBean"/>
</constructor-arg>
<constructor-arg value="${value.name}" index="1"/>
</bean>
In the 2 Java files, I use #Autowired annotations on the method of setClients() and on creating object of someJSONBean.
But I am receiving errors:
BeanCreationException: could not autowire method: public void com.zzz.yyy.sometthing.setClients(someCompanySpecificURLForTheClass) throws IllegalArgumentException and UnsupportedEncodingException.
nested exception is defined: NoSuchBeanDefinitionException: no unique bean of type(someCompanySpecificURLForTheClass) is defined: expected single matching bean, found 2(name1, name2).
I am new to spring framework. can anyone tell whats happening wrong, is the autowiring that i am doing wrong? how can i solve this?
Edit:
Here someCompanySpecificURLForTheClass is the same class and beans(name1 and name2) use this bean as a factory bean with different constructor-arguments.
I am using spring 3.1.
After searching a lot, I think I can use placeholder for the constructor-args value right?
The above is the edited xml file being used.
Updated code in the Java classes:
1.
#ConfigAdapter
class class1{
#Autowired
private someJSONBean obj;
#Autowired
#Value("${value.name:thisismyvalue}")
public void setClients(){}
}
#ConfigAdapter
class class2{
#Autowired
private someJSONBean obj;
#Autowired
#Value("${value.name:thisismyvalue}")
public void setClients(){}
}
But I get the following error:
ConversionNotSupportedException: failed to convert 'java.lang.string' to 'someCompanySpecificURLForTheClass'.
nested execption is IllegalStateException
Cannot convert 'java.lang.string' to 'someCompanySpecificURLForTheClass' of required type: no matching editors or conversion strategy found.
Am I specifying the annotation value wrongly?
Why is this happening?
You have to use #Qualifier Annotation along withe #Autowired. Since your are creating two beans of the same class, spring does not know which one to autowire. You can give a hint using #Qualifer("id/name") annotation.
#Autowired
#Qualifier("name1")
//yourProperty
or
#Autowired
#Qualifier("name2")
//yourProperty
Check out this link .
If you want to inject both the beans into your class, then your have two create two different properties, each pointing to a different instance.
#Autowired
#Qualifer("name1")
//property1
#Autowired
#Qualifer("name2")
//property2

Injecting a reference bean from jar file, No bean named *** is defined exception is thrown

<bean id="org.sakaiproject.vidyayug.tool.SakaiStyleSelectorInterceptor"
class="org.sakaiproject.vidyayug.tool.SakaiStyleSelectorInterceptor">
<property name="worksiteManager">
<ref bean="org.sakaiproject.metaobj.worksite.mgt.WorksiteManager"/>
</property>
</bean>
I am injecting ref bean from a jar file..
Exception is:
Cannot resolve reference to bean 'org.sakaiproject.metaobj.worksite.mgt.WorksiteManager' while setting bean property 'worksiteManager';
nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'org.sakaiproject.metaobj.worksite.mgt.WorksiteManager' is defined
You must add a
<bean id="org.sakaiproject.metaobj.worksite.mgt.WorksiteManager" class="org.sakaiproject.metaobj.worksite.mgt.WorksiteManager"/>
in your application context.
Bean id and class name are not the same thing, even if you're giving them the same value.
The bean id should be a "handy" name you use to refer to a bean isntance, while the class is the actual fully qualified class name to load the bean from the classpath (jar or your class folder or whatever).
do like that, give a bean id, and then call the reference by calling that id.
<bean id="Order" class="com.classes.OrderPizza">
<property name="pizzaTemp" ref="ChickenPizza"></property>
</bean>
<bean id="ChickenPizza" class="com.classes.ChickenPizza"></bean>
<bean id="PaneerPizza" class="com.classes.PaneerPizza"></bean>
The problem is that you are referencing a bean without instantiating it. Correct your code this way:
<bean id="org.sakaiproject.vidyayug.tool.SakaiStyleSelectorInterceptor" class="org.sakaiproject.vidyayug.tool.SakaiStyleSelectorInterceptor">
<property name="worksiteManager">
<bean class="org.sakaiproject.metaobj.worksite.mgt.WorksiteManager"/>
</property>
</bean>
NOTE You also have to be sure the jar is deployed in your project binaries.

Spring and passing parameters to factory-method in runtime

The documentation of method context.getBean(name, user) says
Allows for specifying explicit constructor arguments / factory method
arguments
but no matter what I do (tried everything), with the most logical setting I get this when the beans are being loaded up during initialization:
org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'fileValidator' defined in
PortletContext resource
[/WEB-INF/classes/context/customer-form-portlet.xml]: Unsatisfied
dependency expressed through constructor argument with index 0 of type
[com.liferay.portal.model.User]: Ambiguous factory method argument
types - did you specify the correct bean references as factory method
arguments?
org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'fileValidator' defined in
PortletContext resource
[/WEB-INF/classes/context/customer-form-portlet.xml]: Unsatisfied
dependency expressed through constructor argument with index 0 of type
[com.liferay.portal.model.User]: Ambiguous factory method argument
types - did you specify the correct bean references as factory method
arguments?
<bean id="fileValidator"
class="cz.instance.transl.validation.file.FileValidator"
factory-method="createInstance" />
private FileValidator(User user) {
this.user = user;
}
public static FileValidator createInstance(User user) {
return new FileValidator(user);
}
The commentary says you can do it, but if you specify constructor arguments in xml definiton of that bean or not, it fails.
The javadoc says:
args - arguments to use if creating a prototype using explicit arguments to a static factory method.
So the bean definition must be a prototype-scoped bean, i.e.
<bean id="fileValidator"
scope="prototype"
class="cz.instance.transl.validation.file.FileValidator"
factory-method="createInstance" />
Reading across 20 posts, I found that it was not apparent how to get a custom factory method to take parameters at run-time, especially since we are forced to use the constructor-arg tags and refer to an existing bean in the context as setup below and the class in question acting as a static factory method.
<bean id="user" class="something.something.User" />
<bean id="fileValidator"
class="cz.instance.transl.validation.file.FileValidator"
factory-method="createInstance" >
<constructor-args ref="user" />
</bean>
I got it working by fetching an instance of the bean used in the constructor-arg out of the context and then populating it with the values that you are working with at run-time. This bean will then be used as the parameter when you get your factory-generated bean.
public class X {
public void callFactoryAndGetNewInstance() {
User user = context.getBean("user");
user.setSomethingUsefull(...);
FileValidator validator = (FileValidator)context.getBean("fileValidator");
...
}
}
Note this doesn't solve the problem asked of using context.getBean(arg1, arg2) as that method isn't relevant in this scenario. The reason it isn't is because all these beans are singleton and at this point the constructor isn't invoked. Not a problem and not anything to care about if you are working in a single-user system as you only have 1 User bean in your context at any time anyhow!
However, For a multi-user system you will need to make sure that you have a unique User bean for each real user and that you use the correct User bean in the factory method invocation.
In order to do this in a multi-user system, you will need to change the bean types to be prototype AND you should create a bean of your FileValidator that represents the factory (if you plan to dependency injection into the factory) and another bean FileValidator that represents your new instance. They will both be of the same class type but you must give each one a unique name. See below:
<bean id="user" scope="prototype" class="something.something.User" />
<bean id="validatorFactory"
class="cz.instance.transl.validation.file.FileValidator">
<constructor-arg value="something" />
</bean>
<bean id="fileValidatorBean"
class="cz.instance.transl.validation.file.FileValidator"
scope="prototype"
factory-method="createInstance" >
<constructor-arg ref="user" />
</bean>
and in the class where you would like to get this new FileValidator bean from the factory, you can use the technique below:
public void someMethod() {
...
User user = context.getBean("user");
user.setSomethingUsefull(...);
FileValidator fileValidator =
(FileValidator)context.getBean("fileValidatorBean",
user);
...
}
In order to call your factory method Spring needs access to a user instance to pass to createInstance. In this case I am just creating a bean and passing it in:
<bean id="user" class="something.something.User">
</bean>
<bean id="validator" class="cz.instance.transl.validation.file.FileValidator" factory-method="createInstance">
<constructor-arg ref="user"/>
</bean>
You can use an abstract factory too setting the factory-bean attribute. Here we have an ActionFactory which create actions.
<bean id="actions_factory" class="com.imagina.control.actions.impl.ActionFactoryImpl"/>
<bean id="load_person_action" class="com.imagina.control.actions.impl.LoadPersonAction"
factory-bean="actions_factory" factory-method="create">
<constructor-arg value="load_person_action"/>
</bean>
To use this configuration you have to take this points in account:
create method is not static. Now belongs to an instance
constructor-arg is the parameter of factory method

Spring beans with scope prototype

Suppose have following beach definition:
<bean id="singletonBean" class="...">
<property name="instanceBean" ref="instanceBean"/>
</bean>
<bean id="instanceBean" class="..." scope="prototype"/>
When I call:
singletonBean = context.getBean("singletonBean");
...some code...
singletonBean = context.getBean("singletonBean");
Would property instanceBean of singletonBean be initialized again or it would just use already created singleton?
Would just use already created singleton.
A prototyped inner bean of a singleton won't be recreated each time you get the singleton from context. The singleton and all is references are created one for all.
But context.getBean("instanceBean"); would give you a new since scope is 'prototype'.
instanceBean is set only once on startup, so you can get the instanceBean by singletonBean.getInstanceBean() if you like.
When invoked context.getBean("singletonBean") always it contains the same instance of instanceBean, though the scope is prototype in the bean definition.
On the contrary if the container bean is of scope prototype and it refers to a bean which is defined with scope singleton, always the inner bean would be singleton. Eg:-
<bean id="outer" class="OuterBean" scope="prototype">
<property name="innerBean" ref="inner" />
</bean>
<bean id="inner" class="InnerBean" scope="singleton"/>
OuterBean outer1 = (OuterBean) context.getBean("outer");
OuterBean outer2 = (OuterBean) context.getBean("outer");
Here both outer1 and outer2 will contain same instance of InnerBean.
In a multitheaded environment, if innerBean holds any shared data, it can lead to race condition.

problem in Spring session scope bean with AOP

I want to inject currentUser instance in HomeController class. so for every request, HomeController will have currentUser object.
My configuration:
<bean id="homeController" class="com.xxxxx.actions.HomeController">
<property name="serviceExecutor" ref="serviceExecutorApi"/>
<property name="currentUser" ref="currentUser"/>
</bean>
<bean id="userProviderFactoryBean" class="com.xxxxx.UserProvider">
<property name="userDao" ref="userDao"/>
</bean>
<bean id="currentUser" factory-bean="userProviderFactoryBean" scope="session">
<aop:scoped-proxy/>
</bean>
But I am getting following error.
Caused by: java.lang.IllegalStateException: Cannot create scoped proxy for bean 'scopedTarget.currentUser': Target type could not be determined at the time of proxy creation.
at org.springframework.aop.scope.ScopedProxyFactoryBean.setBeanFactory(ScopedProxyFactoryBean.java:94)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1350)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:540)
What is the problem? and Is there any better/simple alternative?
Cheers.
With scoped-proxies, Spring still needs to know the type of the bean when the context is initialized, and in this case it's failing to do so. You need to try and give it more information.
I notice that you're only specifying factory-bean in your definition of currentUser, with no factory-method specified. I'm actually rather surprised that that's a valid definition, since the two are normally used together. So try adding the factory-method attribute to currentUser, which specifies the method on userProviderFactoryBean which creates the user bean. That method needs to have a return type of your User class, which Spring will use to infer the type of currentUser.
Edit: OK, after your comment below, it seems you've misunderstood how to use factory beans in Spring. When you have a bean of type FactoryBean, you don't need to use the factory-bean attribute as well. So instead of this:
<bean id="userProviderFactoryBean" class="com.xxxxx.UserProvider">
<property name="userDao" ref="userDao"/>
</bean>
<bean id="currentUser" factory-bean="userProviderFactoryBean" scope="session">
<aop:scoped-proxy/>
</bean>
You just need this:
<bean id="currentUser" class="com.xxxxx.UserProvider" scope="session">
<aop:scoped-proxy/>
<property name="userDao" ref="userDao"/>
</bean>
Here, UserProvider is a FactoryBean, and Spring knows how to handle that. The end result will be that the currentUser bean will be whatever UserProvider generates, rather than an instance of UserProvider itself.
The factory-bean attribute is used when the factory is not a FactoryBean implementation, but just a POJO, and it allows you to tell Spring explicitly how to use the factory. But because you're using FactoryBean, there's no need for this attribute.

Categories

Resources