spEL in Bean Definition File : How to get a value in an inline list? - spring

Given an inline list from a properties file:
nameList=john,smith,junior
From the bean definition file, I want to always extract the first item in my list. In this case, I would extract 'john'.
Using Spring Framework 3.0.4.RELEASE, my bean property looks as follows:
<property name="mySingleName" value="${nameList}" />
This obviously gives me the whole list.
I attempted to use the following to get the first item in the name list, but was met with an error:
<property name="mySingleName" value="#{${nameList}[0]}" />
The error was:
BeanExpressionException:Exception parsing failed: After parsing a valid expression, there is still more data in the expression:'comma(,)'
I have looked in the Book "Spring In Action", and have looked at the Spring spEL Documentation on Springs website. I have also googled for a quite a bit. Unfortunately, most of the code examples are done in code and not on the spring definition files. Any assistance in this would be greatly appreciated.

In your example you are reading a "nameList" property as a String ( not as a java.util.List ). You would need to convert it to a list first:
<bean id="listOfNames" class="org.springframework.util.StringUtils" factory-method="commaDelimitedListToSet">
<constructor-arg type="java.lang.String" value="${nameList}"/>
</bean>
and then you can apply SPeL to it:
<property name="mySingleName" value="#{listOfNames[0]}" />
similar problem / solution here: Spring: Reading collections form property files

Related

How to get set elements in the same sequence as in a Spring bean definition

I have a lot of bean definitions that look similar to this
<bean id="TransformationMapOrganization " class="com.artifact_software.adt.plugin.transformation.RemoveColumnsTransformationImpl">
<property name="pluginId" value="Remove Division, Department, and Cost Code" />
<property name="dataStoreName" value="person_data"/>
<property name="columnNames">
<set>
<value>Division</value>
<value>Dept Code</value>
<value>Cost Code</value>
</set>
</property>
</bean>
In the code, the columnNames are defined as:
protected List<String> columnNames;
It appears that erroneous duplicate values are ignored rather causing an error which is good. I hope that I can count on that since it does make life easier!
What set implementation will Spring use?
What is the correct way to iterate through columnNames to get the columnNames in the same sequence as they are specified in the bean?
You can set the implementation class via <set set-class="com.my.SetImpl" />, (see current doc). (com.my.SetImpl must implement java.util.Set)
alternatively: define targetClass on your SetFactoryBean...
If omit, current spring, will use java.util.LinkedHashSet.
More correct, reliable & future-safe it would be to map columnNames as java.util.Set not as a List (+ to use set-class).
If no set-class attribute is supplied, the container chooses a Set implementation.
(in your case,) Obviously spring manages to convert from set to list "smoothly" ("by hand" it's also easy done thx to api design). Spring (seems to) also preserves you distinct entries, LinkedHashSet implementation additionally guarantees/should "preserve order"...
Your Bean definition and field names are different. Change
<property name="ColumnNames">
to
<property name="columnNames">

Mule invoke message processor

I came across "invoke" element (link) that can be used to invoke java methods from inside the flow. It seemed a perfect solutions for me, since I don't want to use Callable and entry points resolvers and I want to pass extra parameter to the method.
<invoke object-ref="yourBean"
method="yourMethod"
methodArguments="#[message.inboundProperties['inboundPropertyName']]" />
<set-property propertyName="outboundPropertyName"
value="#[payload]" />
I did something like the code above. My question is: how should I create "yourBean"?
I tried to create:
<spring:bean name="yourBean" class="class"/>
but got:
org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'yourBean' is defined
I also have other beans defined in my tag, but others seemed to work. Does anyone have similar issue?
EDIT:
When I deleted other beans definitions besides "yourBean" everything started to work, but when I add more beans definitions I got following error when I tried to use "yourBean":
Exception stack is:
1. null (java.lang.NullPointerException)
org.mule.processor.InvokerMessageProcessor:280 (null)
2. null (java.lang.NullPointerException). Message payload is of type: String (org.mule.api.MessagingException)
org.mule.execution.ExceptionToMessagingExceptionExecutionInterceptor:35 (http://www.mulesoft.org/docs/site/current3/apidocs/org/mule/api/MessagingException.ht
ml)
--------------------------------------------------------------------------------
Root Exception stack trace:
java.lang.NullPointerException
at org.mule.processor.InvokerMessageProcessor.transformArgument(InvokerMessageProcessor.java:280)
at org.mule.processor.InvokerMessageProcessor.evaluateArguments(InvokerMessageProcessor.java:200)
at org.mule.processor.InvokerMessageProcessor.process(InvokerMessageProcessor.java:164)
+ 3 more (set debug level logging or '-Dmule.verbose.exceptions=true' for everything)
********************************************************************************
Which for me seems like the "yourBean" is not instantiated. But why?
My bean definitions:
<bean id="yourBean" class="com.example.BpmService"/>
<bean id="StatusUpdateContext" class="javax.xml.bind.JAXBContext" factory-method="newInstance">
<constructor-arg>
<array>
<value type="java.lang.Class">
com.example.OrderStatusUpdate
</value>
</array>
</constructor-arg>
</bean>
EDIT: Ok, id/name both some to work for Mule invoke. I have had no problems using invoke with multiple bean definitions. This sounds more like an issue with your beans, which you are not sharing, and/or Spring than Mule invoke.

When to use <ref bean> and when to use <ref local> in Spring?

When to use <ref bean="service" /> and when to use <ref local="service" /> in Spring?
Specifying the target bean by using the bean attribute of the ref tag is the most general form, and will allow creating a reference to any bean in the same BeanFactory/ApplicationContext (whether or not in the same XML file), or parent BeanFactory/ApplicationContext. The value of the bean attribute may be the same as either the id attribute of the target bean, or one of the values in the name attribute of the target bean.
<ref bean="someBean"/>
Specifying the target bean by using the local attribute leverages the ability of the XML parser to validate XML id references within the same file. The value of the local attribute must be the same as the id attribute of the target bean. The XML parser will issue an error if no matching element is found in the same file. As such, using the local variant is the best choice (in order to know about errors are early as possible) if the target bean is in the same XML file.
<ref local="someBean"/>
This is from the Spring source reference here
The local attribute on the ref element is no longer supported in the 4.0 beans xsd since it does not provide value over a regular bean reference anymore. Simply change your existing ref local references to ref bean when upgrading to the 4.0 schema.
<ref local="someBeanId"> should be used when you have a duplicate id in your parent-child config files and you want to distinguish between the two in either config file.
<ref parent="someBeanId"> should be used in the child config file to reference the parent id.
<ref bean="someBeanId"> should be used when you do not have a duplicate id in your parent-child config files.
<ref local=".."> requires that the bean being referenced is in the same config file.
<ref bean="..."> requires only it to be in the same context, or in a parent context.
The difference is primarily one of documentation. If you see <ref local="...">, then you know you need only look in the same file to find it. Other than that, there's not much difference. I would generally use <ref bean="..."> in most cases.
In spring 4.1
the local attribute is not valid.
i used in the parent xml a name attribute for the
and in the child file a referenced the bean by the alias i gave already.

Dynamically configuring java beans based on property file in Spring

Wondering if there is a way to dynamically instantiate beans based on set of values in your property file using PropertyPlaceholderConfigurer class.
I have a java bean say Student with two attributes: "name" and "subject"
I have a property file with:
student.1.name=student1name
student.1.subject=student1subject
student.2.name=student2name
student.2.name=student2subject
Now I have a Classroom object that can take a list of students.
I am wondering if there is a way we could do this using Spring. The challenge here is that the number of students could vary.
If there was only one student object then:
<bean id="student" class="com.abc.Student">
<property name="name" value="${student.1.name}" />
<property name="subject"
value="${student.1.subject}" />
</bean>
<bean id="classRoom" class="com.abc.ClassRoom">
<property name="student" ref="student" />
</bean>
would have worked. But in this case we have a list of n Students. And the value of n could vary depending on the number of entries in the properties file.
I'm with Kevin--IMO you're going about this the wrong way.
One possible workaround would be to create a bean that takes the property file as an argument, reads it in, and exposes a list of students (which would need to be indexed on something, like the n in the existing property file).
The classroom bean could then use that list of students.
But it sure looks like you're trying to duplicate the functionality of a DB, without a DB, in an awkward way.
I don't think there's a way to do that with PropertyPlaceholderConfigurer. Usually when I have a situation like that I choose a configuration format of either JSON or XML and use GSON/Jackson/JAXB to unmarshall the data into objects.

Can I use a property placeholder with Spring EL?

Before upgrading to Spring 3 I had this in my applicationContext.xml file:
<bean class="com.northgateis.pole.ws.PolePayloadValidatingInterceptor">
<property name="validateRequest" value="${validateRequest}" />
<property name="validateResponse" value="${validateResponse}" />
</bean>
where ${validateRequest) and ${validateRequest) refer to properties that may or may not be defined in my properties file.
In Spring 2, if these proeprties were not present in the properties file the setters on the bean were not called and so the defaults hard-coded in PolePayloadValidatingInterceptor were used.
After upgrading to Spring 3, it seems the behaviour is different: If the properties are not present in the properties file I get the following exception:
SEVERE: Exception sending context initialized event to listener instance of class org.springframework.web.context.ContextLoaderListener
org.springframework.beans.factory.BeanDefinitionStoreException: Invalid bean definition with name 'annotationMapping' defined in class path resource [com/northgateis/pole/ws/applicationContext-ws.xml]: Could not resolve placeholder 'validateRequest'
at org.springframework.beans.factory.config.PropertyPlaceholderConfigurer.processProperties(PropertyPlaceholderConfigurer.java:272)
at org.springframework.beans.factory.config.PropertyResourceConfigurer.postProcessBeanFactory(PropertyResourceConfigurer.java:75)
at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:640)
at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:615)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:405)
at org.springframework.web.context.ContextLoader.createWebApplicationContext(ContextLoader.java:272)
I tried dabbling with Spring EL but the following doesn't seem to work:
<bean class="com.northgateis.pole.ws.PolePayloadValidatingInterceptor">
<property name="validateRequest" value="${validateRequest?:true}" />
<property name="validateResponse" value="${validateResponse?:false}" />
</bean>
The value after the Elvis operator is always used, even when the properties are defined in the proeprties file. Interesting that the syntax is accepted.
Any suggestions?
It looks like Spring 3's handling of default values with the Elvis operator was rather broken. This has apparently been fixed (see SPR-7209) in the fresh-out-of-the-oven Spring 3.0.3, and the correct syntax should be the rather baroque:
#{${validateRequest}?:true}
There's no need for Spring EL for setting a default value for a missing property when resolving it with a placeholder configurer. Simply use ${validateRequest:true}. The "Elvis operator" is not concerned with resolving placeholders, it just relies on whatever input the placeholder configurer provides.
See SPR-4785.

Resources