Page 2 of 2 FirstFirst 12
Results 11 to 14 of 14

Thread: <util:list> and merge attribute

  1. #11
    Join Date
    Jul 2007
    Posts
    101

    Default New Implementation

    I have created an implementation that will merge any number of "collections" into a parent collection to create a single collection. This should be easily patched into the current spring-utils based version if needed. Here is the test spring config for an example.

    Code:
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:collections="http://www.ccanning.com/spring/collections"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="
              http://www.springframework.org/schema/beans
              http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
              http://www.ccanning.com/spring/collections
              http://www.ccanning.com/spring/collections-1.0.xsd">
    
      <collections:list id="parentList">
        <value>1</value>
        <value>2</value>
      </collections:list>
    
      <collections:list id="childList1" parent="parentList">
        <value>3</value>
        <value>4</value>
      </collections:list>
    
      <collections:list id="childList2" parent="parentList"">
        <value>5</value>
        <value>6</value>
        <value>2</value>
      </collections:list>
    
      <collections:set id="parentSet">
        <value>1</value>
        <value>2</value>
      </collections:set>
    
      <collections:set id="childSet1" parent="parentSet">
        <value>2</value>
        <value>3</value>
      </collections:set>
    
      <collections:set id="childSet2" parent="parentSet">
        <value>4</value>
        <value>3</value>
      </collections:set>
    
      <collections:map id="parentMap">
        <entry key="1" value="1"/>
        <entry key="2" value="2"/>
      </collections:map>
    
      <collections:map id="childMap1" parent="parentMap">
        <entry key="2" value="4"/>
        <entry key="3" value="3"/>
        <entry key="4" value="4"/>
      </collections:map>
    
      <collections:map id="childMap2" parent="parentMap">
        <entry key="4" value="16"/>
      </collections:map>
    </beans>
    This would provide the following parent collections:
    Code:
      <collections:list id="parentList">
        <value>1</value>
        <value>2</value>
        <value>3</value>
        <value>4</value>
        <value>5</value>
        <value>6</value>
        <value>2</value>
      </collections:list>
    
      <collections:set id="parentSet">
        <value>1</value>
        <value>2</value>
        <value>3</value>
        <value>4</value>
      </collections:set>
    
      <collections:map id="parentMap">
        <entry key="1" value="1"/>
        <entry key="2" value="4"/>
        <entry key="3" value="3"/>
        <entry key="4" value="16"/>
      </collections:map>
    The children also exist as is.

    Currently, this does not recurse through ancestor chains or validate that. if you want this style of functionality, feel free to use the attached source (full maven build with test).

    chuck
    Attached Files Attached Files

  2. #12
    Join Date
    Sep 2008
    Posts
    1

    Exclamation

    if I understand you right, you're proposing that the 'merged collections' be declared in the components which will be used to construct them. I don't think this is a satisfactory solution for several reasons.

    First, the ability to create a merged collection is predicated on the ability to modify the declarations of the component collections. This is frequently not available. In my particular use case I need to create a list which is a merge of lists contained in the resources from several different projects, contained in distributed jars and thus the source XML is read only. I suspect that merging of collections from external read only sources is frequently going to be the case if not the norm.

    Second, this solution ends up creating named beans which aren't explicitly declared in the source xml, at least not as named beans. This seems to go against the design philosophy of spring, where if you didn't declare an object with a given id attribute, you can't get it out of the context.

    Third, how do you create multiple merged collections from the same source collections? You can't have more than one parent attribute and creating a new set of rules for parsing the contents of the parents attribute presents a whole new level of complexity

    There's a number of other unanswered questions...

    What happens if you have a name collision between the phantom collection created and an explicitly declared bean? This would probably result in an initialization error, but it would be hard for spring config editors to catch beforehand without making them significantly more complex.

    What happens if you're building an ordered collection from several different beans. What order will the final collection be in? It seems at first glance that it would simply end up being declaration order, but that has a issues of its own. You don't want to have to start re-ordering other parts of your spring config or possibly other spring configs which you're including in order to achieve a given order. Even worse, what if you have multiple collections which need to be merged into different orders from the same source collections.

    While turning this problem on its head as you've done does present certain advantages from an implementation perspective, I believe it will be difficult to tie up all the loose ends and end up needing lots of caveats in the documentation making it overly complicated to use. The goal of spring should be easy to understand and use no matter how hard it is to code.

  3. #13
    Join Date
    Jul 2007
    Posts
    101

    Default

    Sorry for the late reply.

    No, I am not implying that they be defined in the same resource, on the contrary, it is to define them in multiple configuration files. That is our use case. This solution sticks with the design methodology of the collections factory bean design to allow collections to be merged into a parent collection wherever they are defined.

    On your second point, all of the collections have an id and can be assigned.

    On your third point, there are two methods to solve this:
    1) have a single parent and multiple children, this is how we use it
    2) I could easily add recursion to merge up the ancestor chain (I left this out because it wasn't a requiremnt for us because 1 was sufficient

    On your 4th point, with the current implmentation and how the spring parsing is implemented, the last bean definition defined wins. This is a real problem for us as we configure our system as components and you import the config for each component. If spring imports the same beans twice, it destroys the existing config and you lose previous merges. I have a fix that checks for duplicate beans (assuming import case) that returns the original so this behavior is not "destructive". This is a gerneal problem with spring, not with this solution.

    On your 5th point, it occurs the same as spring currently does, the ordered list is built in the order that spring reads in the beans. They will be merged in that order. It wouldn't be that hard to add an order attribute, but using depends-on would be better for this since you have to know your order and that should enforce it.

    This works like the merge functionality does when you embed lists inside a bean and use the merge feature. I am not turning anything on its head or adding any extra caveats beyond the current implementation (as far as i can tell).

    Hope this clarifies my solution. If you have more questions, please feel free to post them and I should respond much more quickly as i am not so busy now.

    Also, feel free to disagree or challenge any of these points. The best solution is one that works for everyone.

  4. #14
    Join Date
    Dec 2009
    Location
    Pune,India
    Posts
    60

    Default uitl:list and spring @autowire behave strangely.

    I have rather different experience.

    here is an example
    I have person class in my configuration file I have say following bean definitions.

    Code:
     <bean id="person1" class="com.test.Person"/>
    
       <bean id="personA" class="za.co.discovery.util.Person"/>
       	   
       <bean id="personB" class="za.co.discovery.util.Person"/>
    	 
    
             <util:list id="persons">
    		<ref bean="personA" />
    		<ref bean="personB" />
    	</util:list>
    in my code if I put @Autowired

    Code:
    @Autowired
    	List<Person> persons;
    All I get in the list personA , personB and surprisingly person1 . with autowired list will give me all the beans person declared inside application context. My List size showing me 3 instead of 2

    if I declare one more list


    Code:
    <bean id="person1" class="com.test.Person"/>
    
       <bean id="personA" class="za.co.discovery.util.Person"/>
       	   
       <bean id="personB" class="za.co.discovery.util.Person"/>
    
    <bean id="personC" class="za.co.discovery.util.Person"/>
    
    
    <bean id="personD" class="za.co.discovery.util.Person"/>
    
    
    <util:list id="persons">
    		<ref bean="personA" />
    		<ref bean="personB" />
    	</util:list>
    
    <util:list id="persons2">
    		<ref bean="personC" />
    		<ref bean="personD" />
    	</util:list>
    
    @Autowired
    	List<Person> persons;
    
    @Autowired
    	List<Person> persons2;
    both list showing me size 5 that means all the person's beans inside xml i.e. 5 instead of 2.

    but if I do context.getBean("persons") give me size 2 and context.getBean("persons2")
    give me size 2 which is proper behavior

    is it bug ????

    I have tested both spring 2.5.6 and spring 3.1.0.M1 same result.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •