Create bean in xml from method - java

I have a class MyFactory which can create MyClass:
package com.mypackage
#Component
public class MyFactory{
#Bean
public MyClass createMyClass() {
return // magic class creation... ;
}
}
How to use that method to create a bean with xml?
<bean id="myClass" factory-method="com.mypackage.MyFactory.createMyClass"/>
doesn't work...

Remove the #Bean annotation from the factory method:
package com.mypackage;
#Component
public class MyFactory{
public MyClass createMyClass() {
return // magic class creation... ;
}
}
And then in XML:
<bean id="myClass" factory-bean="myFactory" factory-method="createMyClass"/>
If you also want the factory to be configured via XML, then remove the #Component annotation from class MyFactory and create it in XML as well:
<bean id="myFactory" class="com.mypackage.MyFactory"/>
<bean id="myClass" factory-bean="myFactory" factory-method="createMyClass"/>
See the documentation: Instantiation by Using an Instance Factory Method

Related

How to specify sub-dependency for AutoWired Beans

I have a Spring component defined like this:
#Component
public class SearchIndexImpl implements SearchIndex {
IndexUpdater indexUpdater;
#Autowired
public SearchIndexImpl(final IndexUpdater indexUpdater) {
Preconditions.checkNotNull(indexUpdater);
this.indexUpdater = indexUpdater;
}
}
along with two implementations of the IndexUpdater interface, like:
#Component
public class IndexDirectUpdater implements IndexUpdater, DisposableBean, InitializingBean {
}
#Component
public class IndexQueueUpdater implements IndexUpdater, DisposableBean, InitializingBean {
}
If I try to auto-wire SearchIndexImpl like this:
#Autowired
private SearchIndex searchIndex;
I get the following exception:
org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'IndexUpdater' available: expected single matching bean but found 2: indexDirectUpdater,indexQueueUpdater
which is expected since Spring cannot tell which IndexUpdater implementation to auto-wire for the indexUpdater parameter in the constructor of SearchIndexImpl. How do I guide Spring to the bean that it should use? I understand I can use the #Qualifier annotation, but that will hard-code the index updater to one of the implementation, while I want the user to be able to specify what index updater to use. In XML, I can do something like:
<bean id="searchIndexWithDirectUpdater" class="SearchIndexImpl">
<constructor-arg index="0" ref="indexDirectUpdater"/>
</bean>
How do I do the same using Spring's Java annotations?
Use the #Qualifier annotation to specify the dependency to use :
public SearchIndexImpl(#Qualifier("indexDirectUpdater") IndexUpdater indexUpdater) {
Preconditions.checkNotNull(indexUpdater);
this.indexUpdater = indexUpdater;
}
Note that #Autowired is not needed to autowire the arg constructor of a bean since Spring 4.
To answer to your comment.
To let the class that will use the bean to define the dependency to use you could allow it to define the IndexUpdater instance to inject in the container such as :
// #Component not required any longer
public class IndexDirectUpdater implements IndexUpdater, DisposableBean, InitializingBean {
}
// #Component not required any longer
public class IndexQueueUpdater implements IndexUpdater, DisposableBean, InitializingBean {
}
Declare the bean in a #Configuration class :
#Configuration
public class MyConfiguration{
#Bean
public IndexUpdater getIndexUpdater(){
return new IndexDirectUpdater();
}
The SearchIndexImpl bean will now resolve the dependency thanks to IndexUpdater getIndexUpdater().
Here we use #Component for one bean and #Bean for its dependency.
But we could also allow a full control on the beans to instantiate by using only #Bean and by removing #Component on the 3 classes :
#Configuration
public class MyConfiguration{
#Bean
public IndexUpdater getIndexUpdater(){
return new IndexDirectUpdater();
}
#Bean
public SearchIndexImpl getSearchIndexFoo(){
return new SearchIndexImpl(getIndexUpdater());
}

#scope - spring - setting scope "prototype" using annotations, behaves like singleton. Where am i going wrong?

When i try to use #scope("prototype") over a class, I see it behaves similar to "singleton" I am not sure where I am wrong. Any help on this is much appreciated.
Employee class - setting scope - prototype
import org.springframework.context.annotation.Scope;
#Scope("prototype")
public class Employee {
private String emp_name;
public String getEmp_name() {
return emp_name;
}
public void setEmp_name(String emp_name) {
this.emp_name = emp_name;
}
}
Department class- setting scope - singleton
import org.springframework.context.annotation.Scope;
#Scope("singleton")
public class Department {
private String dep_name;
public String getDep_name() {
return dep_name;
}
public void setDep_name(String dep_name) {
this.dep_name = dep_name;
}
}
Beans.xml
<context:component-scan base-package="com"/>
<!-- Scope Annotations -->
<bean id="dep_scope" class="com.scope.annotation.Department" >
</bean>
<bean id="emp_scope" class="com.scope.annotation.Employee" >
</bean>
Main App
public class MainApp {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
Employee emp = (Employee) context.getBean("emp_scope");
emp.setEmp_name("Saro");
System.out.println("first"+emp.getEmp_name());
Employee emp2 = (Employee) context.getBean("emp_scope");
System.out.println("second"+emp2.getEmp_name());
Department dep = (Department) context.getBean("dep_scope");
dep.setDep_name("Maths");
System.out.println("first"+dep.getDep_name());
Department dep2 = (Department) context.getBean("dep_scope");
System.out.println("second"+dep2.getDep_name());
}
}
Output :
firstSaro
secondSaro
firstMaths
secondMaths
I expected secondnull instead of secondSaro
Just try to define scope in beans.xml file in bean tag.... you are using both annotation and xml ... just use either..
Or you can try to define bean using annotation ...
for that you can use #Bean annotation.
#Configuration
public class Config {
#Bean(scope=DefaultScopes.PROTOTYPE)
public TestBean testBean(){
return new TestBean();
}
}
And In your main logic you can use bellow code
TestBean testBean = ctx.getBean(TestBean.class);
It behaves as a singleton because this is the ways it is defined in the your xml conf. Default scope is singleton, prototype should be declares like follows
<bean id="dep_scope" class="com.scope.annotation.Department" scope="prototype">
</bean>
If you want to use annotations, javadoc states that #Scope should be used in conjunction with #Component, like this
#Component
#Scope("prototype")
public class Employee {
//...
}
public class ExampleUsingEmployee {
#Inject
private Employee enployee; //will be automatically injected by spring
// ... do other stuff
}
You should avoid (if possible) using both xml and annotations.
You have put
context:component-scan base-package="com"
which will try to instantiate beans if they are annotated with #Component or the other bean annotations like #Service, etc. But this does not make spring process the other annotations configuration.
if you want to process the other spring annotations you must register
context:annotation-config> .
too in order to ask spring to look for the annotations in the defined beans.
in summary
context:component-scan : will instantiate beans within the package if they are annotated with suitable annotation
context:annotation-config : will process the annotations in the configured beans irrespective of whether they are defined via annotations or xml.

How to create a bean as instance of Interface Class

I have three classes 1)an Interface 2) A class which implements the interface 3) a static factory which return an instance second class as an instance Interface Class
public Interface MyInterface {
}
public class Myclass implements MyInterface {
}
public Class MyStaticFactory {
public static MyInterface getInstance() {
MyInterface myClassInstance = new Myclass();
return myClassInstance;
}
}
I want to create a bean of MyClass as an instance MyInterface. Mycode for that is
<bean id="staticFactory" class="MyStaticFactory">
</bean>
<bean id="myclass" class="MyInterface" factory-bean="staticFactory" factory-method="getInstance">
</bean>
But with the above code I am getting an exception
org.springframework.beans.factory.BeanCreationException: Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private MyInterface ; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [MyInterface] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
at com.amazon.coral.reflect.instantiate.SpringInstantiatorFactory$1.newInstance(SpringInstantiatorFactory.java:175)
I am trying to access bean using the following code
#Autowired
private MyInterface MyclassInstance
Is It a valid thing to create a bean as as instance of InterfaceClass ? How can we load an instance of MyClass in a class variable of MyInterface using spring ?
You dont need to autowire any field as you have your own factory that will instantiate bean for you. Also you dont need to instantiate your factory class with static method in it. Instead you just can stay with:
<bean id="staticFactory" class="MyStaticFactory" factory-method="getInstance" />
Now let's say you have multiple implementation of MyInterface, you could do so by passing a parameter like:
<bean id="staticFactory" class="MyStaticFactory" factory-method="getInstance" scope="prototype">
<constructor-arg value="MyClass" />
</bean>
And in your factory class you could either use switch (from JDK 7) or if else ladder to check what's requested in parameter to method getInstance method and instantiate proper bean.
You could then do the following:
public static void main(String args[]) {
Application context = new ......
MyInterface myIface = context.getBean("staticFactory", MyInterface.class);
//myIface.mymethod();
}
My view on this is depending on the context, whether using XML based bean creation or using Java based "config"bean creation, the logic is pretty much the same.
You need to have a Class annotated with #Configuration if using Java configuration for you to create your beans, secondly, the Configuration class needs to be registered as a bean creator, i.e. the application context needs to be able to create and initialize the beans depending on their type (either Singleton or Prototype).
My configuration would look like this:
public Interface MyInterface {
void executeSomeMethod();
}
public class Myclass implements MyInterface {
#override
void executeSomeMethod(){
//some code executed here
}
}
The Configuration class would look something like this:
#Configuration
public MyConfigurationClass {
#Bean(name="someBeanName")
public MyInterface createBean() {
MyInterface bean = new Myclass();
return bean;
}
}
Assuming the MyConfigurationClass is registered in the application context, then using the bean would look something like:
#Component
public class SomeClassUsingTheBean {
#Autowired
MyInterface someBeanName;
public SomType method() {
someBeanName.executeSomeMethod();
}
}

Spring injection tricks

I have: injecting MyClass and String objects into Utils at constructor.
Questions:
How does it works when in Utils bean definition (look at beans definition section) I mentioned only the second argument of Utils constructor?
How to pass MyClass mock into Utils object in unit tests? I mean how to redefine the bean definition?
Utils.java
public class Utils {
#Inject
public Utils(MyClass obj, String val) {
this.obj = obj;
this.val = val;
}
Beans definition:
<bean class="com.mypack.MyClass"/>
<bean id="utils" class="com.mypack.Utils">
<constructor-arg value="bucket" />
</bean>
You can define define another(test) context for the unit tests:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = { "my-test-context.xml",
"some-other-context.xml" })
public class SkipSampleFunctionalTests {
#Autowired
private SomeBean bean;
...
}
If you want to override only one bean, you can import your main(core) context int the test context and change only the desired bean:
<import resource="main-context.xml"/>
<bean id="x" class="com.asd.MyClass">
<property name="y" ref="y"/>
</bean>

How to Autowire a 1-arg Object Constructor with Previously Autowired Object?

Given the following MyConstructorClass:
#Component
public class MyConstructorClass{
MyObj var;
public MyConstructorClass( MyObj constrArg ){
this.var = var;
}
...
}
How can I autowire a field that requires a constructor argument from a previously #Autowired field? Below is an example.
Note - this question, I believe, is similar to this one, except that my constructor argument is not a String. This code sample is slightly modified from this question.
#Service
public class MyBeanService{
#Autowired
CustomObject customObj; // no arguments to constructor
#Autowired
MyConstructorClass myConstructorClass; // requires `customObj` as an argument
....
}
How can I modify MyBeanService to properly construct myConstructorClass with customObj?
You just need to annotated the constructor of MyConstructorClass with #Autowired:
#Component
public class MyConstructorClass {
final private CustomObject customObj;
#Autowired
public MyConstructorClass(CustomObject customObj) {
this.customObj = customObj;
}
}
Another alternative, (without adding the #Autowired constructor to MyConstructorClass) is to use a #Configuration bean:
#Configuration
public class MyConfiguration {
#Bean
public CustomObject customObj() {
return customObj;
}
#Bean
public MyConstructorClass myConstructorClass() {
return new MyConstructorClass(customObj());
}
#Bean
public MyBeanService myBeanService() {
return new MyBeanService();
}
}
you can use the <constructor-arg> in your servlet
<bean id="myConstructorClass" class="package.MyConstructorClass">
<constructor-arg>
<bean class="package.CustomObject"/>
</constructor-arg>
</bean>
If this is the only place you need to use that class could use #PostConstruct to instantiate itself. I think there is a better solution, but this is off the top of my head.
#Service
public class MyBeanService{
#Autowired
CustomObject customObj;
MyConstructorClass myConstructorClass;
#PostConstruct
public void construct()
{
myConstructorClass = new MyConstructorClass(customObj);
}
}
In the constructor, you can refer to other beans defined in Spring.
<bean id="myConstructorClass" class="package.MyConstructorClass">
<constructor-arg index="0" ref="customObj"/>
</bean>

Categories

Resources