Keys of Spring beans as Map<String,Foo> - java

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>

Related

Dynamically Injecting a Map

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.

Is it possible call a properties file to instance a user and password in Apache CXF Blueprint for a Web Service?

I'm relative new with Fuse and WebServices.
I did a SOAP WebService with a BasicAuthAuthorizationInterceptor, this is the actual context and it's working:
<cxf:cxfEndpoint address="/SampleEp" id="insertSomethingToDB" serviceClass="com.example.sample_ep.SampleEp" wsdlURL="wsdl/SampleEP.wsdl">
<cxf:inInterceptors>
<ref component-id="securityInterceptor"/>
</cxf:inInterceptors>
</cxf:cxfEndpoint>
<bean
class="com.example.middleware.BasicAuthAuthorizationInterceptor" id="securityInterceptor">
<property name="users">
<map>
<entry key="user" value="password"/>
</map>
</property>
</bean>
So, to add more security, I'll tried to put the users in a properties file outside the project, this is the idea:
<cxf:cxfEndpoint address="/SampleEp" id="insertSomethingToDB" serviceClass="com.example.sample_ep.SampleEp" wsdlURL="wsdl/SampleEP.wsdl">
<cxf:inInterceptors>
<ref component-id="securityInterceptor"/>
</cxf:inInterceptors>
</cxf:cxfEndpoint>
<bean
class="com.example.middleware.BasicAuthAuthorizationInterceptor" id="securityInterceptor">
<property name="users">
<map>
<entry key="${cxf.user}" value="${cxf.password}"/>
</map>
</property>
</bean>
<bean> add some code to add a *.properties file outside the project </bean>
It is that possible?
Or I'm really bad with this?
Ok, I tried a few of things with Jasypt, JAAS and get the solution:
<ext:property-placeholder>
<ext:location>file:/this/is/your/path/to/your/propertie/file/cxf.properties
</ext:location>
</ext:property-placeholder>
<cxf:cxfEndpoint address="/SampleEp" id="insertSomethingToDB"
serviceClass="com.example.sample_ep.SampleEp" wsdlURL="wsdl/SampleEP.wsdl">
<cxf:inInterceptors>
<ref component-id="securityInterceptor" />
</cxf:inInterceptors>
</cxf:cxfEndpoint>
<bean class="com.example.middleware.BasicAuthAuthorizationInterceptor"
id="securityInterceptor">
<property name="users">
<map>
<entry key="${cxf.user}" value="${cxf.password}" />
</map>
</property>
</bean>
Just only add to your Blueprint header:
xmlns:ext="http://aries.apache.org/blueprint/xmlns/blueprint-ext/v1.0.0"
And voilĂ , it's working with a secure user/pass validation outside your project :D
And the most important thing, the properties file needs this format:
#cxf.properties
cxf.user=administrator
cxf.password=password

Java - Spring - put entries in map based on some condition

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

Issue in NOT being able to supply HashMap as "value" for a given key in applicationContext.xml

I want to use a Hashmap as a value for a key in my applicationContext.xml file.
That is, both the keys and the values for the key that we specify (as given below) would be supplied at runtime ,in the xml file.
<beans>
<bean id="movieDetails" class="org.gis.gvb.MovieDetails">
<property name="name" value="Sri Raghavendra Mahatyam"/>
<property name="censorRating" value="U"/>
<property name="userRating" value="*****"/>
<property name="language" value="Telugu"/>
<property name="twoD3DND" value="2D"/>
<property name="releaseYear" value="1986"/>
<property name="genre" value="Devotional"/>
<property name="castNCrew" value="Director=Trivikram Srinivas,Producer=Suresh
Productions,Music=Devisri Prasad,Hero=Venkatesh,Heroine=Katrina Kaif"/>
</bean>
</beans>
Please help me achieve this.
When tried,I am getting error saying cannot convert from String to HashMap.
Thanks a lot,
Bhaskar Gundu.
You have achieve like this
<bean id="movieDetails" class="org.gis.gvb.MovieDetails">
<property name="youMapName">
<map>
<entry key="name" value="Sri Raghavendra Mahatyam"/>
<entry key=="censorRating" value="U"/>
</map>
</property>
</bean>
Define a Map like this first inside your applicationContext.xml:
<util:map id="myMap" value-type="java.lang.String">
<entry key="entry1" value="value1" />
<entry key="entry2" value="value2" />
...
</util:map>
Then use this Map in any bean of yours like this:
<bean id="myBean" class="com.sample.beans">
<property name="myMap" ref="myMap" />
</bean>

Marshalling Different Classes with Spring MVC and JIBX

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.

Categories

Resources