I have the following field called someMap in which I need to inject a map at runtime depending upon the inputs I have received.
I have tried using the #Resource annotaion but it is tightly coupled to the beanId specified in the xml file.
#Resource(name="someMap")
private final Map<String,String> someMap;
<bean id="someMap" class="java.util.HashMap">
<constructor-arg>
<map>
<entry key="Engraving1" value="#Engraving1" />
<entry key="Engraving2" value="#Engraving2" />
<entry key="Engraving3" value="#Engraving3" />
<entry key="LeaveBlank" value="#LeaveBlank" />
</map>
</constructor-arg>
</bean>
<bean id="someOtherMap" class="java.util.HashMap">
<constructor-arg>
<map>
<entry key="Descirption" value="#Desc" />
<entry key="Engraving2" value="#Engraving2" />
<entry key="Engraving3" value="#Engraving3" />
<entry key="UniqueId" value="$60034" />
</map>
</constructor-arg>
</bean>
What I want is to get rid of this tight coupling & initialize the someMap field to a differnt flavour of the Map defined in spring xml let's say someOtherMap
You can't change the annotation dynamic without using Reflection , so you can't change the name of reousece.
#Resource(name="NAME")
But it is very easy to define two bean with different property or constrctor-arg.
<bean id="boss" class="***">
<property name="mydata">
<bean class="HashMap">
</bean>
</property>
</bean>
if you just want one bean definition with different data, XML and Annotation should not work. factory-method or setMethod will work for it, you need some java code.
Related
I am using a Soap WS and I have to customize timeout configuration per operation. The customization is actually done with cxf and its http-conf:conduit, which cannot be customized to the operation level.
My actual configuration is :
<bean id="proxyFactory" class="org.apache.cxf.jaxws.JaxWsProxyFactoryBean">
<property name="serviceClass" value="com.package.PortType" />
<property name="address" ref="URL_WS" />
</bean>
<bean id="URL_WS" class="java.lang.String">
<constructor-arg value="http://serveraddress/Service"/>
</bean>
<http-conf:conduit name="http://serveraddress/Service.*">
<http-conf:client ConnectionTimeout="10000" ReceiveTimeout="10000"/>
</http-conf:conduit>
With this configuration, all the timeout of this WS are up to 10000ms.
As explained above, I would like to customize it to the operation level, I have found this link and tried to follow the process, but I'm in front of a problem of implementation, but I only com.ibm.wsdl.util.xml.QNameUtils in my classpath which has for the factory-method :
public static QName newQName(Node paramNode), method which takes a org.w3c.dom.Node.
I tried to change the code with this implementation coming to:
<bean id="proxyFactory" class="org.apache.cxf.jaxws.JaxWsProxyFactoryBean">
<property name="delegate">
<jaxws:client serviceClass="com.package.PortType" address="URL_WS" >
<jaxws:outInterceptors>
<bean class="com.package.CustomTimeoutInterceptor">
<property name="receiveTimeoutByOperationName">
<map key-type="javax.xml.namespace.QName" value-type="java.lang.Long">
<entry value="10">
<key>
<bean class="com.ibm.wsdl.util.xml.QNameUtils" factory-method="newQName">
<!-- I don't know what to put here -->
</bean>
</key>
</entry>
</map>
</property>
</bean>
</jaxws:outInterceptors>
</jaxws:client>
</property>
</bean>
The Node's implementation I have is com.sun.org.apache.xerces.internal.dom.NodeImpl. I don't know which NodeImpl' subclass I have to use and how to create it to make it working in a bean way, I'm kinda losing myself in the documentation with these different implementations and these different dom Levels.
I just would like to create an Object subClass of Node which would work in this QNameUtils method
OR
find a different way to customize my configuration
I finally solved this problem, here is the working solution:
I kept the CustomTimeoutInterceptor of the link, mixed the solution with the help of this link.
I also kept my initial configuration, and I found that the javax.xml.namespace.QName had a factory method. I just added this part to my configuration:
<!-- Creation of the bean for the interceptor -->
<bean id="timeoutSetter" class="com.package.CustomTimeoutInterceptor">
<property name="receiveTimeoutByOperationName">
<map key-type="javax.xml.namespace.QName" value-type="java.lang.Long">
<entry value="20000">
<key>
<bean class="javax.xml.namespace.QName" factory-method="valueOf">
<constructor-arg value="{http://serveraddress/Service}Operation1" />
</bean>
</key>
</entry>
</map>
</property>
</bean>
<!-- I had the interceptor the list of outInterceptors -->
<cxf:bus>
<cxf:outInterceptors>
<ref bean="timeoutSetter"/>
</cxf:outInterceptors>
</cxf:bus>
In a Java app which uses Spring (Spring version 3.2.3),
I have something like this:
<bean id="pm" class="com.test.PropertyManager">
<property name="targets">
<map>
<entry key="key01" value-ref="obj01" />
<entry key="key02" value-ref="obj02" />
<entry key="key03" value-ref="obj03" />
<entry key="key04" value-ref="obj04" />
<entry key="key05" value-ref="obj05" />
<entry key="key06" value-ref="obj06" />
</map>
</property>
</bean>
Is there any way to tell Spring to not put all entries in this map
but only some of them based on some property whose value can be
different for different environments the app is built for, and running in.
I mean, I am looking for something like:
<bean id="pm" class="com.test.PropertyManager">
<property name="targets">
<map>
<entry key="key01" value-ref="obj01" if="${env1}"/>
<entry key="key02" value-ref="obj02" if="${env1}"/>
<entry key="key03" value-ref="obj03" unless="${env1}"/>
<entry key="key04" value-ref="obj04" unless="${env1}"/>
<entry key="key05" value-ref="obj05" />
<entry key="key06" value-ref="obj06" />
</map>
</property>
</bean>
So e.g. I want two entries to be added when the app is in environment env1, two other entries to be added when the app is running in another env2, and yet two others to be always added.
Is that possible and if not, what are my alternatives?
There are different options:
If you need a different bean configuration per environment you could use profiles:
<beans profile="dev">
<bean id="pm" class="com.test.PropertyManager">
<property name="targets">
...
</property>
</bean>
</beans>
<beans profile="production">
<bean id="pm" class="com.test.PropertyManager">
<property name="targets">
...
</property>
</bean>
</beans>
More on XML profiles: http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#beans-definition-profiles-xml
If you need more flexibility use a factory (with Java config, that's straightforward):
public class PropertyManagerFactory {
public static PropertyManager getInstance() {
// Your initialization code (check env vars to build the map...)
}
}
Bean definition (notice the factory-method):
<bean id="propertyManager" class="com.test.PropertyManagerFactory" factory-method="getInstance" />
Usage (what's returned by the getInstance method will be injected here):
<bean id="accountService" class="com.test.AccountServiceImpl">
<property name="propertyManager" ref="propertyManager"/>
</bean>
More info on using factory methods: http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#beans-factory-class-static-factory-method
trying to instantiate a Map in Spring I found an odd (to me) behaviour.
I am using the following piece of XML to create the Map:
<bean id="fooBean" class="it.arch.fe.util.Foo">
<property name="prop1" value="val1"></property>
<property name="prop2" value="val2"></property>
</bean>
<bean id="barBean" class="it.arch.fe.util.Foo">
<property name="prop1" value="val3"></property>
<property name="prop2" value="val4"></property>
</bean>
<bean id="mapOfFoos" class="org.springframework.beans.factory.config.MapFactoryBean">
<property name="targetMapClass">
<value>java.util.HashMap</value>
</property>
<property name="sourceMap">
<map>
<entry key="foo" value-ref="fooBean" />
<entry key="bar" value-ref="barBean" />
</map>
</property>
</bean>
I manage to instantiate and Autowire this Map in my code, but I am having an issue with the keys:
I wanted a map with keys "foo" and "bar", but they appear to be "fooBean" and "barBean".
Is this supposed to happen?
Is there a way to use the "key" properties as keys, as it would seem the obvious behaviour?
(I don't want to change the names of the beans to foo and bar, because I already declared two beans with these names and the logic I would like to follow needs the keys to be "foo" and "bar")
EDIT: Starting from Trever Shick's answer I found a way to resolve the practical problem, but I'm still trying to understand why this happened.
just use a map, don't use a MapFactoryBean for your mapOfFoos
<beans xmlns:util="http://www.springframework.org/schema/"
xsi:schemaLocation="http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-2.0.xsd">
<util:map id="mapOfFoos">
<entry key="foo" value-ref="fooBean" />
<entry key="bar" value-ref="barBean" />
</util:map>
Since I found I can't instantiate a Map by itself as a bean without a MapFactoryBean or as a property inside another bean, I resolved in another way:
I made another class, InnerFoo with attributes prop1 and prop2, where I put the properties I had in the previous Foo, so now my Map<String,InnerFoo> is the only attribute of Foo, this is my xml snippet:
<bean id="fooBean" class="it.arch.fe.util.InnerFoo">
<property name="prop1" value="val1"></property>
<property name="prop2" value="val2"></property>
</bean>
<bean id="barBean" class="it.arch.fe.util.InnerFoo">
<property name="prop1" value="val3"></property>
<property name="prop2" value="val4"></property>
</bean>
<bean id="mapOfFoos" class="it.arch.fe.util.Foo">
<property name="mapping">
<map>
<entry key="foo" value-ref="fooBean" />
<entry key="bar" value-ref="barBean" />
</map>
</property>
</bean>
I am having trouble creating a "freemarker.template.Configuration" bean and setting global shared variables in this instance of the Configuration. Something like:
<bean id="conf" class="freemarker.template.Configuraton">
<property name="sharedVariable" >
**??**
</property>
</bean>
Is this possible?
I can't use FreeMarkerConfigurer instead of Configurer because I am using servlets (full stack of Spring MVC) as controllers in my project. Is there any way to convert a FreemarkerConfigurer into a Configurer?
The problem stems from that shared variables is not a JavaBean property... but, accidentally, Configuration has a setAllSharedVariables(TemplateHashModelEx) method, that's technically a property, so something like this should work (I haven't tried it and my Spring XML is rusty... tell me if there are typos in it):
<bean id="conf" class="freemarker.template.Configuraton">
<property name="allSharedVariables">
<bean class="freemarker.template.SimpleHash">
<constructor-arg>
<map>
<entry key='someVarName' value='someValue' />
<entry key='otherVarName' value-ref='valueBeanId' />
</map>
</constructor-arg>
</bean>
</property>
</bean>
We are trying to build some RESTful services with Spring MVC. We will be providing several representations: XML, HTML, & JSON. We would like to use JiBX as the OXM technology.
We are currently having difficulty figuring out how to wire up Spring with JiBX. If we want to wire up a single class, for example Customer, we simply define a JibxMarshaller, an XML MarshallingView, and add it too our ContentNegotiatingViewResolver. This works great.
The problem is we aren't sure how to wire up marshalling of multiple classes, for example, Customer and User. Each JibxMarshaller can support only one class (unlike the Jaxb2Marshaller which can support many). We tried declaring a marshaller for each class, but the MarshallingView only support one marshaller. Declaring multiple MarshallingViews does not work (it appears only the first one works).
Your advice is appreciated. Thanks.
<bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
<property name="mediaTypes">
<util:map>
<entry key="xml" value="application/xml"/>
</util:map>
</property>
<property name="defaultViews">
<util:list>
<bean class="org.springframework.web.servlet.view.xml.MarshallingView">
<property name="marshaller" ref="userMarshaller"/>
</bean>
<bean class="org.springframework.web.servlet.view.xml.MarshallingView">
<property name="marshaller" ref="customerMarshaller"/>
</bean>
</util:list>
</property>
</bean>
<bean id="userMarshaller" class="org.springframework.oxm.jibx.JibxMarshaller">
<property name="targetClass" value="com.mycompany.User"/>
</bean>
<bean id="customerMarshaller" class="org.springframework.oxm.jibx.JibxMarshaller">
<property name="targetClass" value="com.mycompany.Customer"/>
</bean>
Update based on Ritesh's answer below:
It turns out that I was thrown off by the targetClass property of the JibxMarshaller. I thought it meant the marshaller would only work for a single class, however, it appears to just uses the target class as a way of finding all related bindings. So, the solution is to use just a single marshaller, using an arbitrary target class from your set of classes you have bindings for. For example:
<bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
<property name="mediaTypes">
<util:map>
<entry key="xml" value="application/xml"/>
</util:map>
</property>
<property name="defaultViews">
<util:list>
<bean class="org.springframework.web.servlet.view.xml.MarshallingView">
<property name="marshaller" ref="jibxMarshaller"/>
</bean>
</util:list>
</property>
</bean>
<bean id="jibxMarshaller" class="org.springframework.oxm.jibx.JibxMarshaller">
<property name="targetClass" value="com.mycompany.User"/>
</bean>
JiBX binding compiler adds JiBX_bindingList field to class files. At run time, the 'targetClass' (any compiled class with JiBX_bindingList field) is used to build a BindingFactory. It is the getMappedClasses() of IBindingFactory which is used by JibxMarshaller
in supports() method to check if marshaller can marshal a class.
Please also see JiBX runtime usage.