MethodInvokingBean question - spring

I have a method invoking bean which calls a method to perform some sort of initialization on a targetBean and another bean who needs a twitter class albeit initialized.
<bean id="twitter" class="twitter4j.Twitter"></bean>
<bean id="twitterInjector"
class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="targetObject" ref="twitter"/>
<property name="targetMethod">
<value>setOAuthConsumer</value>
</property>
<property name="arguments">
<list>
<value>consumerKey</value>
<value>consumerSecret</value>
</list>
</property>
</bean>
<bean id="MyPageController"
class="com.hardwire.controller.MyPageController">
<property name="twitter" ref="What should I put here? twitter or
twitterInjector?/>
.
.
.
</bean>
What should I inject into the MyPageController, twitterInjector or twitter?

MethodInvokingFactoryBean - like all other factory beans in Spring - is primarily intended to produce a new bean; in this particular case by invoking a method of some other bean (or class). Your setOAuthConsumer method doesn't seem like it would return a bean, so using MethodInvokingFactoryBean may not be the best approach in these circumstances.
If I am mistaken and it does return a bean (in which case consider renaming it) and that's the bean you want injected in your controller then you should use twitterInjector as ref value. If you really want twitter in your controller, then you should use twitter.

Related

MethodInvokingFactoryBean returns itself instead of desired object

I am trying to use a MethodInvokingFactoryBean to get an instance of a com.amazonaws.regions.Region for use in configuring a com.amazonaws.services.kinesis.AmazonKinesisClient. I am doing this in Blueprint, Camel, Karaf.
<bean id="awsRegion" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="targetClass" value="com.amazonaws.regions.RegionUtils"/>
<property name="targetMethod" value="getRegion"/>
<property name="arguments">
<list>
<value>EU-WEST-1</value>
</list>
</property>
</bean>
<bean id="kinesisClient" class="com.amazonaws.services.kinesis.AmazonKinesisClient">
<property name="region" ref="awsRegion"/>
</bean>
This seems like it should work, with the first bean creating a Region, and the second bean using it.
However, I get an error that makes it seem like the MethodInvokingFactoryBean is just returning an instance of itself instead of Region.
org.osgi.service.blueprint.container.ComponentDefinitionException: Error setting property: PropertyDescriptor <name: region, getter: null, setter: [class com.amazonaws.AmazonWebServiceClient.setRegion(class com.amazonaws.regions.Region)]
...
Caused by: java.lang.Exception: Unable to convert value org.springframework.beans.factory.config.MethodInvokingFactoryBean#2289c050 to type com.amazonaws.regions.Region
The method I'm invoking in RegionUtils should return a Region
https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/regions/RegionUtils.html#getRegion-java.lang.String-
I came upon this way of getting the Region in the Client in this question, where the solution seemed to work for the asker.
Bind aws sqs region camel
At first , apache-camel tag is excess here. As second, you missed that asker is using spring context and you are using blueprint context. Try something like this:
<bean id="awsRegion" class="com.amazonaws.regions.RegionUtils" factory-method="getRegion">
<argument value="EU-WEST-1"/>
</bean>
<bean id="kinesisClient" class="com.amazonaws.services.kinesis.AmazonKinesisClient">
<property name="region" ref="awsRegion"/>
</bean>
EDIT: just tested this example with latest aws-java-sdk and it is worked

how to initialize static data member using spring with out creating object of it

<bean name="staticHubInitializer" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="staticMethod" value="very.public.api.StaticHub.setInstance"/>
<property name="arguments">
<list>
<ref bean="myPrecious"/>
</list>
</property>
</bean>
as i know spring ioc container create a bean MethodInvokingFactoryBean then it calls the setInstance() with parameter myPrecious just want a clarification is there any way we can suggest that dont create a object of it call directly ???
or is there any other way we can invoke the data member and assign the value to it directly.

Spring injecting one reference bean into another reference bean

In the below spring configuration snippet, injecting reference of "SomeManager" into bean "SomeWorker" and "SomeLocal". The reference of "SomeLocal" is also injected into "SomeWorker".
My doubt is is it possible to inject the same reference of "SomeManager" injected into "SomeWorker" into another bean, like here in "SomeLocal".
Problem is if i inject it separately into "SomeWorker" and "SomeLocal" than unnecessarily there will be two instances of "SomeManager" which is basically not required in this scenario as "SomeLocal" is referred only within the "SomeWorker"
<bean id="SomeWorker" class="com.test.worker.SomeWorker">
<property name="someManager" ref="SomeManager" />
<property name="someLocal" ref="SomeLocal"/>
<bean id="SomeLocal" class="com.test.local.SomeLocal">
<property name="someManager" ref="SomeManager" />
</bean>
<bean id="SomeManager" class="com.test.manager.SomeManager"/>

Difference b/w primary and autowire-candidate attribute of bean tag in spring

I am new to spring. When i am going through auto wiring byType i came to know about these attributes primary and autowire-candidate.
I didn't get the exact difference b/w these two as setting these parameter to false will make the other bean a candidate for autowiring.
Can anybody help me in understanding these two.
Thanks
Let say there is interface
interface Translator { String translate(String word);}
Your application use the translator widely to translate from English to Polish. However, is some specific case you want to use dedicated translator, because vocabulary is specific. For example, string always means "sequence of characters" but never "underwear".
Sample configuration:
<bean class="EnglishToPolishTranslator" />
<bean class="ComputerScienceEnglishToPolishTranslator" autowire-candidate="false"/>
Everywhere EnglishToPolishTranslator will be autowired except some concrete place where ComputerScienceEnglishToPolishTranslator will be injected by reference.
Some day next customer arrive with requirement: use simpler words. The requirement is achieved by class SimpleEnglishToPolishTranslator. But computer science translator should remain unchanged: it is too costly to modify it.
Your company want keep product easy to maintain. Base application will not be modified, but for the customer the product will extended with extra library configured:
<bean class="SimpleEnglishToPolishTranslator" primary="true"/>
In result, everywhere SimpleEnglishToPolishTranslator will be used except computer science area.
Maybe it is overcomplicated, but shows a difference I found between autowire-candidate and primary
BTW, "autowire-candidate" doesn't have corresponding annotation. It looks to me that "autowire-candidate" is dead end in Spring evolution
if we configure bean for more than one time with different ids then IOC will throw an Exception. To overcome this duplicate beans problem, we can use autowire-candidate=”false” or primanry="true"
Example: i have two classes Mobile and Processor
Case -1: autowire-candidate=”false”
<bean id="mobile" class="com.Mobile" autowire="byType">
<property name="mobileName" value="Redmi"></property>
<property name="mobileModel" value="Note 5"></property>
</bean>
<bean id="process1" class="com.Processor"
autowire-candidate="false">
<property name="process" value="2GHz"></property>
<property name="ram" value="4GB"></property>
</bean>
<bean id="process2" class="com.Processor">
<property name="process" value="1GHz"></property>
<property name="ram" value="3GB"></property>
</bean>
As per above configuration, process1 bean will be ignored and process2 bean will be injected.
Case -2: primanry="true"
<bean id="mobile" class="com.Mobile" autowire="byType">
<property name="mobileName" value="Redmi"></property>
<property name="mobileModel" value="Note 5"></property>
</bean>
<bean id="process1" class="com.Processor" primary="true">
<property name="process" value="2GHz"></property>
<property name="ram" value="4GB"></property>
</bean>
<bean id="process2" class="com.Processor">
<property name="process" value="1GHz"></property>
<property name="ram" value="3GB"></property>
</bean>
As per above configuration, process2 bean will be ignored and process1 bean will be injected.

injecting a spring bean property different values according to its context

I have a spring bean my_bean with a property my_map, and I want to inject it with the value "X" or with the value "Y". The bean:
<bean id="my_bean">
<property name="my_map">
<map>
<entry key="p" value="X" />
</map>
</property>
</bean>
It's referenced in a very deep hierarchy by the bean root_a:
<bean id="root_a">
<ref bean="root_a_a"/>
</bean>
<bean id="root_a_a">
<ref bean="root_a_a_a"/>
</bean>
<bean id="root_a_a_a">
<ref bean="my_bean"/>
</bean>
and this entire deep hierarchy is referenced again from the bean root_b. In the ref of my_bean from this hierarchy I would the property to be injected with the value "Y", but I would not like to duplicate the entire hierarchy twice.
<bean id="root_b">
<ref bean="root_a_a"/>
</bean>
How do I do this in the spring XML? can you think of a clever spring EL solution? something else? I prefer all my configuration to be done in the XML and no Java code...
By default Spring beans are singletons, which means that once bean="my_bean" is created it is shared between other components e.g. shared between A => bean id="root_a_a_a" and B => bean id="root_b_b_b"
The answer to your question depends on what exactly you are trying to achieve.
Two Beans
If bean="my_bean" does not need to be shared between A and B, then create two beans:
inject this one to A
<bean id="myBeanX" class="My">
<property name="culprit" value="X"/>
</bean>
and this one to B
<bean id="myBeanY" class="My">
<property name="culprit" value="Y"/>
</bean>
notice they both are instances of the same class.
You can also inline them into collaborators (A / B) if you don't need them for anything else:
<bean id="root_a_a_a">
<constructor-arg>
<bean class="My">
<property name="culprit" value="X"/>
</bean>
</constructor-arg>
</bean>
You can also have a factory bean that creates root_a_a_a given the property for a class My, but that would be an overkill.
Single Bean
In case A and B needs to share the exact same reference to bean="my_bean", the question is: are you ok with A and B changing my_bean's state after my_bean is created? Probably not.
If you are, which would be 0.41172% chance, you can change my_bean's value to whatever you need in A's or B's constructors => would not recommend
Hence you either would go with the Two Bean approach (which is most likely what you want), or you would need to refactor a property for "X" and "Y" into another e.g. myConfig component.
EDIT after the question was edited
If root_a and root_b will not be used together in the same instance of the context,you can use Spring Profiles (example), or SpEL / Property Based solutions (example)
e.g.
<bean id="my_bean">
<property name="my_map">
<map>
<entry key="p" value="${ENV_SYSTEM:X}" />
</map>
</property>
</bean>
It will set it to X by default, unless a ENV_SYSTEM system variable is set (e.g. to Y).

Resources