Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to extend already defined lists and maps in Spring application context?

Imagine a staged application context with different phases. We start with an early phase to define the necessary infrastructure. The xml application contexts are loaded sequentially.

The reason to split up these files is an extension/plugin mechanism.

Stage 01-default-configuration.xml

We prepare and declare the map with id exampleMapping to enhance them later with data.

<beans xmlns="http://www.springframework.org/schema/beans" 
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:util="http://www.springframework.org/schema/util"
       xsi:schemaLocation="[...]">

  <util:map id="exampleMapping" />
</beans>

Stage 02-custom-configuration.xml (optional)

We configure the exampleMapping and add an entry.

<beans xmlns="http://www.springframework.org/schema/beans" 
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:util="http://www.springframework.org/schema/util"
       xsi:schemaLocation="[...]">

  <util:map id="exampleMapping">
    <entry key="theKey" value="theValue" />
  </util:map>
</beans>

Stage 03-make-use-of-configuration.xml (mandatory)

Uses the defined map exampleMapping, whether it's configured customly or it's still the empty declared map.

<beans xmlns="http://www.springframework.org/schema/beans" 
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="[...]">

    <bean id="exampleService" class="com.stackoverflow.example.ExampleService">
       <property name="mapping" ref="exampleMapping" />
    </bean>
</beans>

The problem here is, that it's not possible to add entries to the exampleMapping map after the first stage. Spring throws an exception that the map with id exampleMapping already exists. If we leave out the first stage the map is undeclared and the third stage can't resolve exampleMapping which also produces an exception.

How can I solve this issue? I read Collection merging (spring docs) but this didn't helped. Is it possible to add values later to maps/lists before using them?

Thank you!

like image 772
Christopher Klewes Avatar asked Jan 11 '11 10:01

Christopher Klewes


People also ask

Can we have multiple application context in spring?

We can have multiple application contexts that share a parent-child relationship. A context hierarchy allows multiple child contexts to share beans which reside in the parent context. Each child context can override configuration inherited from the parent context.

How would you define context path for spring boot application?

The context path is the name of the URL at which we access the application. The default context path is empty. The context path can be changed in many ways. We can set it in the properties file, with the SERVER_SERVLET_CONTEXT_PATH environment variable, with Java System property, or on the command line.

What is BeanFactory in Java?

The BeanFactory is the actual container which instantiates, configures, and manages a number of beans. These beans typically collaborate with one another, and thus have dependencies between themselves.

How do you get the BeanFactory reference in any class?

I can have my class implement BeanFactoryAware to get a reference to my beanfactory. Then I can do beanFactory. getBean("name"); to get access to a single bean.


1 Answers

Both map and list has this attribute named merge=true|false for merging two lists. Alternatively you can use MethodInvokingFactoryBean for calling already defined list's add method to add extra items later.

Let's go over your example.

1) First the second scenario with MethodInvokingFactoryBean. Instead of defining the way you do, I defined your beans a little differently.

<bean class="java.util.HashMap" id="exampleMapping">
    <constructor-arg index="0">
        <map>
            <entry key="theKey" value="theValue"/>
        </map>
    </constructor-arg>
</bean>

<bean id="exampleService" class="com.stackoverflow.example.ExampleService">
    <property name="mapping" ref="exampleMapping"/>
</bean>

In another application content file, you can do the following to extend the map.

<bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
    <property name="targetObject" ref="exampleMapping"/>
    <property name="targetMethod" value="putAll"/>
    <property name="arguments">
        <list>
            <map id="exampleMapping">
            <entry key="theKey2" value="theValue2"/>
            <entry key="theKey3" value="theValue3"/>
            <map>
        </list>
    </property>
</bean>

2) Now the first scenario. For this one, I just found something on page http://forum.springsource.org/showthread.php?t=53358

<bean id="commonData" class="A">
    <property name="map">
        <util:map>
            <entry key="1" value="1"/>
        </util:map>
    </property>
</bean>
<bean id="data" class="A" parent="commonData">
    <property name="map">
        <util:map merge="true">
            <entry key="2" value="2"/>
        </util:map>
    </property>
</bean>

Hope it helps.

like image 174
Umut Utkan Avatar answered Oct 16 '22 10:10

Umut Utkan