In spring xml config,how to automatically get the current bean's ID value? - spring

I use quartz in spring xml, I have many config like above config~~
I want to known ,automatically get the id value of the current bean
Not every time I hand-written the value of the current bean!!
<bean id="openBaiduTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean">
<property name="jobDetail">
<bean p:targetObject-ref="baiduManager" p:targetMethod="createOpenBaiDu" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean" />
</property>
<property name="cronExpression" value="#{p_schedule['openBaiduTrigger.cronExpression']}" />
</bean>

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 define a PropertyPlaceholderConfigurer local to a specific bean?

I've been using org.springframework.beans.factory.config.PropertyPlaceholderConfigurer and in my experience ("citation needed" LOL) it sets the property values globally.
Is there a way to specify different PropertyPlaceholderConfigurer instances for different beans within the same application context xml?
My current code is similar to
<bean id="a" class="X">
<property name="foo" value="bar"/>
<property name="many" value="more"/>
</bean>
<bean id="b" class="X">
<property name="foo" value="baz"/>
<property name="number_of_properties" value="a zillion"/>
</bean>
I would like to do something like (pseudo-code below):
<bean id="a" class="X">
... parse the contents of "a.properties" here ...
</bean>
<bean id="b" class="X">
... parse the contents of "b.properties" here ...
</bean>
The above is non-working pseudo code to illustrate the concept; the point being, I want a different properties file to feed each bean.
WHY?
I want to have those specific properties in separate properties file and not in XML.
I think the following link can br helpful to you.
Reference Link
where #Value("${my.property.name}") annotation is used to bind the property file to a variable of type Properties which will reside in your bean class where you intend to use that properties file.
and you can define multiplte proprtiesplaceholder as below:
<bean id="myProperties"
class="org.springframework.beans.factory.config.PropertiesFactoryBean">
<property name="locations">
<list>
<value>classpath*:my.properties</value>
</list>
</property>
</bean>
and use the id as reference in your bean variable to initialize properties file to the bean.
And it will be handy to include with placeholder bean.
Kindly refer Importance of Unresolvable Placeholder link for detailed info regarding its usage.
Hope this was helpful.

How to avoid hardcoded names in DelimitedLineTokenizer names?

I am using DelimitedLineTokenizer to read from a txt file using FlatFileItemReader. However, is there a way to avoid hardcoding the "names" property of the fields ? Instead can we use any bean ?
<bean id="employeeReader" class="org.springframework.batch.item.file.FlatFileItemReader"
scope="step">
<property name="resource" value="#{jobParameters['input.file.name']}" />
<property name="lineMapper">
<bean class="org.springframework.batch.item.file.mapping.DefaultLineMapper">
<property name="lineTokenizer">
<bean
class="org.springframework.batch.item.file.transform.DelimitedLineTokenizer">
<property name="names" value="empId,empName,empAge" />
</bean>
</property>
<property name="fieldSetMapper">
<bean
class="org.springframework.batch.item.file.mapping.BeanWrapperFieldSetMapper">
<property name="targetType" value="com.example.Employee" />
</bean>
</property>
</bean>
</property>
</bean>
Currently there is not because the result of the LineTokenizer's work is a FieldSet. A FieldSet is like a ResultSet for a file. So just like in a ResultSet, we need to reference each "column" by something which in this case is the name. The LineTokenizer has no insight into where the data is ending up (what the object looks like) so we have no way to introspect it. If you wanted to take a more dynamic approach, you'd want to implement your own LineMapper that combines the two functions together allowing for that type of introspection.
As always, pull requests are appreciated!
In addition to Michael Minella's answer, here's what you can do :
You can use a value such as #{jobParameter['key']}, #{jobExecutionContext['key']} or #{stepExecutionContext['key']} in the <property name="names"> tag.
This means that you can have a step or a listener which does your business logic and save the result at any time in the ExecutionContext :
stepExecution.getJobExecution().getExecutionContext().put(key, value);
Keep in mind though, that the field names of a DelimitedLineTokenizer needs a String (well not really, but close enough), not a bean.

Spring 3.2 and Quartz Scheduler

I have an Spring application to maintain that has Quartz Scheduler configured in an applicationContex-quartz.xml file. A SchedulerFactoryBean is defined with a list of 4 triggers.
One of the triggers i have to modify is a CronTrigger with a simple schedule where it's ran the 15th of the month at 3AM. I need to take into account of some special holidays. I'm aware i can use the Calendar class. My question really is how do I configure it in the xml file? I only want one of the triggers to use it.
Thanks
If those special holidays can be expressed into a single cron expression you shouldn't have problems.
If those special holidays can't be expressed into a single cron expression and you don't want to modify the following:
<bean id="quartzScheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="triggers">
<list>
<ref bean="cronTrigger1" />
<ref bean="cronTrigger2" />
<ref bean="cronTrigger3" />
<ref bean="cronTrigger4" />
</list>
</property>
I think you can't do what you want because in a CronTriggerBean:
<bean id="cronTrigger1" ="org.springframework.scheduling.quartz.CronTriggerBean">
<property name="jobDetail" ref="quartzSchedulerSpecialHolidays" />
<property name="cronExpression" value="abracadabra" />
</bean>
you can associate only one jobDetail to one cronExpression.

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