Let say I have such class:
public class MyClass {
...
private Map<String, Class> eventsMapping = new HashMap<String, Class>();
...
}
public void setEventsMapping(Map<String, Class> mappings){
this.eventsMapping = mappings;
}
How to create bean of such class with filled in eventsMapping? I mean XML definition of bean. The problem is that HashMap contains Classes and not objects.
I assume that it should be something like:
<bean id="myBean" class="com.my.MyClass" >
<property name="eventsMapping">
<map>
<entry key="ABC">
<bean class="java.lang.Class">
???
</bean>
</entry>
</map>
</property>
</bean>
How to pass there particular Class (not an object)
If you are looking for your map to have java.lang.Class instances as values, then simply use
<bean id="myBean" class="com.my.MyClass">
<property name="eventsMapping">
<map>
<entry key="ABC" value="java.lang.Class" ></entry>
</map>
</property>
</bean>
Spring will use a conversion service to change the String value java.lang.Class to a Class instance for java.lang.Class.
Similarly you can put the value in a <value> element.
<bean id="myBean" class="com.my.MyClass">
<property name="eventsMapping">
<map>
<entry key="ABC">
<value>
java.lang.Class
</value>
</entry>
<entry key="DEF">
<value>
java.util.List
</value>
</entry>
</map>
</property>
</bean>
You cannot create a bean of type java.lang.Class like this:
<bean name="aClassBean" class="java.lang.Class" />
Reason:
From Javadocs:
Class has no public constructor. Instead Class objects are constructed automatically by the Java Virtual Machine as classes are loaded and by calls to the defineClass method in the class loader.
To create a bean of type java.lang.Class create your beans like this:
<bean id="aClassBean" class="java.lang.Class" factory-method="forName">
<constructor-arg value="full.package.name.of.the.class"/>
</bean>
You can do it using static factory method for bean creation:
<entry key="ABC">
<bean class="java.lang.Class" factory-method="forName">
<constructor-arg ref="className"/>
</bean>
</entry>
You can also try using automatic conversion from fully qualified string to class but this may not work in you case when generic map is used.
You can try something like this
<bean id="dbFieldConverters" class="java.util.HashMap">
<constructor-arg>
<map value-type="java.lang.Class">
<entry key="tradeDate">
<value>java.util.Date</value>
</entry>
<entry key="lastUpdate">
<value>java.sql.Timestamp</value>
</entry>
</map>
</constructor-arg>
</bean>
this works on my environment (Spring 4):
<map>
<entry key="my-key">
<value type="java.lang.Class">com.example.MyClassName</value>
</entry>
</map>
Please note the target property is Map<String, Class> type and the java.lang.Class is used as value type attribute.
Related
I want to pass a parameter to a bean referenced from another bean in Spring Context.xml. Is it even possible ?
NOTE : The DISCARD bean would have different values when referenced from different beans.
<bean id="dropBadTimestampFilter" class="TimestampRangeMatcherModifier">
<constructor-arg index="0" value="_TIME"/>
<constructor-arg index="1" ref="DISCARD" /> <!--Want to pass a prameter value to this-->
</bean>
<bean id="DISCARD" class="SettingModifier">
<property name="fields">
<map>
<entry key="_ORG" value="CONSTANT"/>
<entry key="CAUSE" value="______"/> <!-- Want to be passed from bean referring it-->
</map>
</property>
</bean>
Is there a way that we could have a reference of bean using a bean using Spring Expression Language so that the following is possible :
<bean id="DISCARD" class="SettingModifier">
<property name="fields">
<map>
<entry key="_ORG" value="CONSTANT"/>
<entry key="CAUSE" value="#{dropBadTimestampFilter.CAUSE}"/> <!-- Can this bean get reference of all the beans using it and not only dropBadTimestampFilter. -->
</map>
</property>
</bean>
Basically you've to make that bean a prototype bean, if it has different properties for different injection. And then, set the value for "CAUSE" key in a #PostConstruct method, of TimestampRangeMatcherModifier bean. In XML, you define such method using init-method attribute of bean tag.
Another approach would be by declaring the bean in-place, like this:
<bean id="dropBadTimestampFilter" class="TimestampRangeMatcherModifier">
<constructor-arg index="0" value="_TIME"/>
<constructor-arg index="1">
<bean class="SettingModifier"> <!-- no need of id here -->
<property name="fields">
<map>
<entry key="_ORG" value="CONSTANT"/>
<entry key="CAUSE" value="______"/>
</map>
</property>
</bean>
</constructor-arg>
</bean>
I'm trying to implement this Java data structure in Spring (which I am new to):
Map<String, List<String>>
I tried the below (and variants of it), but am getting the following exception:
Caused by: org.xml.sax.SAXParseException; lineNumber: XX; columnNumber: YY; cvc-complex-type.2.4.d: Invalid content was found starting with element 'util:list'. No child element is expected at this point.
Can someone tell me the mistake I am making? I need to be able to build out the above mentioned "Map" data structure with literal Keys (String) and List of values. I included twp complete sample "entries" (which are not working) just to show the fill-in pattern that I'm seeking to create.
<bean .... >
...
<property name="monitoredObjects">
<util:map map-class="java.util.HashMap">
<entry key="java.lang:type=GarbageCollector,name=ConcurrentMarkSweep">
<value>
<util:list>
<value>HeapMemoryUsage</value>
<value>NonHeapMemoryUsage</value>
</util:list>
</value>
</entry>
<entry key="java.lang:type=FOO,name=BAR">
<value>
<util:list>
<value>YADA-YADA</value>
<value>BLAH-BLAH</value>
</util:list>
</value>
</entry>
</util:map>
</property>
...
</bean>
Thank you! =:)
I tinkered some more and got it to work by removing "value" elements that enclosed the util:list elements. In other words, like this:
<bean .... >
...
<property name="monitoredObjects">
<util:map map-class="java.util.HashMap">
<entry key="java.lang:type=GarbageCollector,name=ConcurrentMarkSweep">
<util:list>
<value>HeapMemoryUsage</value>
<value>NonHeapMemoryUsage</value>
</util:list>
</entry>
<entry key="java.lang:type=FOO,name=BAR">
<util:list>
<value>YADA-YADA</value>
<value>BLAH-BLAH</value>
</util:list>
</entry>
</util:map>
</property>
...
</bean>
Thanks as always for looking!
Define a Map like this first inside your applicationContext.xml:
<util:list id="list1">
<value>foo#bar.com</value>
<value>foo1#bar.com</value>
</util:list>
<util:list id="list2">
<value>foo2#bar.com</value>
<value>foo3#bar.com</value>
</util:list>
<util:map id="emailMap" value-type="java.util.List">
<!-- Map between String key and List -->
<entry key="entry1" value-ref="list1" />
<entry key="entry2" value-ref="list2" />
...
</util:map>
Then use this Map in any bean of yours like this:
<bean id="myBean" class="com.sample.beans">
<property name="emailMap" ref="emailMap" />
</bean>
How to give value as xpath expression in spring map .
I am trying like below but is not working.
<bean id="test" class="com.test.testmap">
<property name="testmap">
<map>
<entry key="1" value="/emp/empid"/>
<entry key="2" value="/emp/empname"/>
</map>
</property>
</bean>
Regards,
Chaitu
Use Spring's MapFactoryBean to define the testmap property, including the Map implementation you wish to use (below is with a TreeMap).
<bean id="test" class="com.test.testmap">
<property name="testmap">
<bean class="org.springframework.beans.factory.config.MapFactoryBean">
<property name="sourceMap">
<map>
<entry key="1">
<value>/emp/empid</value>
</entry>
<entry key="2">
<value>/emp/empname</value>
</entry>
</map>
</property>
<property name="targetMapClass" value="java.util.TreeMap"/>
</bean>
</property>
</bean>
In your java code, you can use it like this, assuming you have a getter for your testmap field, which you should:
com.test.testmap test = (com.test.testmap)applicationContext.getBean("test");
String xpath = (String)test.getTestmap().get("1");
You should also stick to Java conventions and rename your class com.test.TestMap for readability's sake.
Spring has ability to initialisate values of core java collection types.
I have a complex collection type Map<String, Set<String>> map and it inital value defined in spring config:
<bean id="dao" class="ru.mypkg.dao.DaoImpl">
<property name="dataSource" ref="dataSource"/>
<property name="map">
<map>
<entry key="TABLE">
<set>
<value>COMMENT</value>
<value>INDEX</value>
</set>
</entry>
<entry key="VIEW">
<set>
<value>COMMENT</value>
</set>
</entry>
</map>
</property>
</bean>
I want rewrite my config in next manner: Split it on 2 beans for more readability
<bean id="dao" class="ru.mypkg.dao.DaoImpl">
<property name="dataSource" ref="dataSource"/>
<property name="map" ref-id="myMap"/>
</bean>
<bean id="myMap" ..????..>
<entry key="TABLE">
<set>
<value>COMMENT</value>
<value>INDEX</value>
</set>
</entry>
<entry key="VIEW">
<set>
<value>COMMENT</value>
</set>
</entry>
</bean>
Can I achieve that with no creating additional classes?
Certainly, using the <util:map> namespace. See the Spring documentation C.2.2.5.
Another way to create complex configuration is using the #Configuration approach, or alternatively the FactoryBean interface.
How to inject a Map in java spring framework?
If possible please provide some sample code.
Is the following legal?
<property name="testMap">
<map>
<entry>
<key>
<value>test</value>
</key>
<value>
<list>
<value>String</value>
<value>String</value>
</list>
</value>
</entry>
</map>
</property>
Define a Map like this first inside your applicationContext.xml:
<util:list id="list1">
<value>foo#bar.com</value>
<value>foo1#bar.com</value>
</util:list>
<util:list id="list2">
<value>foo2#bar.com</value>
<value>foo3#bar.com</value>
</util:list>
<util:map id="emailMap" value-type="java.util.List">
<!-- Map between String key and List -->
<entry key="entry1" value-ref="list1" />
<entry key="entry2" value-ref="list2" />
...
</util:map>
Then use this Map in any bean of yours like this:
<bean id="myBean" class="com.sample.beans">
<property name="emailMap" ref="emailMap" />
</bean>
I think your syntax is not legal as spring throws org.xml.sax.SAXParseException when processing the bean configuration xml .
It should work after removing the <value> tag around the <list>.
<property name="testMap">
<map>
<entry>
<key>
<value>test</value>
</key>
<list>
<value>String</value>
<value>String</value>
</list>
</entry>
</map>
</property>
This is my example:
<bean class="com.common.handlermgmnt.HandlerMapAdder">
<constructor-arg index="0" type="java.util.Map">
<map key-type="java.lang.String" value-type="com.common.ViewWidget">
<entry key="DefaultView">
<bean class="com.common.DefaultViewWidget"/>
</entry>
<entry key="AnotherView">
<bean class="com.common.AnotherViewWidget"/>
</entry>
</map>
</constructor-arg>
<constructor-arg index="1" type="com.common.handlermgmnt.HandlerManager" ref="widget_handlerManager"/>
</bean>
Inject it using SpEL. #{id}. this works for me.
in the .xml:
<util:map id="roleLocationMap">
<entry key="ROLE_ADMIN" value-ref="listA" />
<entry key="ROLE_USER" value-ref="listB" />
</util:map>
in the .java
#Autowired
public MainController(
#Value("#{roleLocationMap}") final Map<String, List<String>> roleLocationMap) {
this.roleLocationMap = roleLocationMap;
}
Just ran into this case myself. If no need to reuse the list values as independent beans elsewhere, you could use this shorter version, without using 'value-ref':
<util:map id="mymap">
<entry key="key1">
<util:list>
<value>val1</value>
<value>val2</value>
</util:list>
</entry>
<entry key="key2">
<util:list>
<value>val2</value>
<value>val3</value>
<value>val4</value>
</util:list>
</entry>
</util:map>
And, wire it up in your Java code like this:
#Resource(name="mymap")
Map<String, List<String>> mapKey_List;