PicoContainer
  1. PicoContainer
  2. PICO-243

Order of the elements of an array dependency is not preserved

    Details

    • Type: Improvement Improvement
    • Status: Resolved Resolved
    • Priority: Major Major
    • Resolution: Fixed
    • Affects Version/s: 1.2
    • Fix Version/s: 1.2
    • Component/s: PicoContainer (Java)
    • Labels:
      None
    • Testcase included:
      yes
    • Number of attachments :
      2

      Description

      If I have the following ctor:
      ComponentA(ComponentB[] bees)

      The order of the ComponentB elements of the bees array is random-ish.

      I think it would be desirable for ComponentA to get the array of ComponentB in order of registration.

      I believe the culprit lies in CollectionComponentParameter's getMatchingComponentAdapters, which uses an HashMap, thus losing order of insertion. An easy of going around this would be to use jdk1.4's LinkedHashMap (just tested that, test passes), but that would of course break the 1.3 compat rule, so I guess that's a no go.

      See attached testcase. (I added this to CollectionComponentParameterTestCase)
      As you can see in the test, getting the components of type ComponentB (Strings here) gets them in the right order, it's only failing when injecting the array in ComponentA (Truc)

      1. PICO-243-order.patch
        5 kB
        Grégory Joseph
      2. test-order.txt
        2 kB
        Grégory Joseph

        Issue Links

          Activity

          Grégory Joseph made changes -
          Field Original Value New Value
          Attachment test-order.txt [ 16100 ]
          Hide
          Jörg Schaible added a comment -

          Well, there was never a guarantee of any order. See, if you register in a child pico a component with the same key as in its parent, you will never get the parent's component, although it might have been instantiated and is of a matching type. OTOH I would have been used a LinkedHashMap also ...

          Show
          Jörg Schaible added a comment - Well, there was never a guarantee of any order. See, if you register in a child pico a component with the same key as in its parent, you will never get the parent's component, although it might have been instantiated and is of a matching type. OTOH I would have been used a LinkedHashMap also ...
          Hide
          Jörg Schaible added a comment -

          BTW: If we don't release JDK 1.3 constraint, we will have to set the fix version to 2.0 .. at least currently.

          Show
          Jörg Schaible added a comment - BTW: If we don't release JDK 1.3 constraint, we will have to set the fix version to 2.0 .. at least currently.
          Hide
          Grégory Joseph added a comment -

          Joerg: yes, your example with parent/child containers + component using the same key is valid, but, well, I don't really see the connection with the order of the elements on array-depency, since there'd be only one component to inject anyways !?

          As for the constraint on jdk1.3, maybe there's another solution than a LinkedHM ?

          Show
          Grégory Joseph added a comment - Joerg: yes, your example with parent/child containers + component using the same key is valid, but, well, I don't really see the connection with the order of the elements on array-depency, since there'd be only one component to inject anyways !? As for the constraint on jdk1.3, maybe there's another solution than a LinkedHM ?
          Hide
          Jörg Schaible added a comment -

          MPC parent = new DPC();
          MPC child = new DPC(parent);
          parent.registerInstance("1", "1");
          parent.registerInstance("3", "3");
          parent.registerInstance("4", "4");
          parent.registerInstance("5", "5");
          child.registerInstance("2", "2");
          child.registerInstance("3", "3a");

          child.getComponentInstance("1");
          child.getComponentInstance("2");
          parent.getComponentInstance("3");
          child.getComponentInstance("3");
          parent.getComponentInstance("4");
          parent.getComponentInstance("5");
          child.getComponentInstance("5");
          child.getComponentInstance("4");
          parent.getComponentInstance("1");

          Parameter p = new CCParameter();
          String[] stringsChild = p.resolveInstance(child, null, String[]);
          String[] stringsParent = p.resolveInstance(child, null, String[])

          So, what should the sequence be for stringsChild?
          1) 1,2,3a,5,4
          2) 1,2,3a,4,5

          and for the stringsParent?
          3) 1,3,4,5
          4) 3,4,5,1

          You cannot solve this even with a LinkedHashMap though ...

          Show
          Jörg Schaible added a comment - MPC parent = new DPC(); MPC child = new DPC(parent); parent.registerInstance("1", "1"); parent.registerInstance("3", "3"); parent.registerInstance("4", "4"); parent.registerInstance("5", "5"); child.registerInstance("2", "2"); child.registerInstance("3", "3a"); child.getComponentInstance("1"); child.getComponentInstance("2"); parent.getComponentInstance("3"); child.getComponentInstance("3"); parent.getComponentInstance("4"); parent.getComponentInstance("5"); child.getComponentInstance("5"); child.getComponentInstance("4"); parent.getComponentInstance("1"); Parameter p = new CCParameter(); String[] stringsChild = p.resolveInstance(child, null, String[]); String[] stringsParent = p.resolveInstance(child, null, String[]) So, what should the sequence be for stringsChild? 1) 1,2,3a,5,4 2) 1,2,3a,4,5 and for the stringsParent? 3) 1,3,4,5 4) 3,4,5,1 You cannot solve this even with a LinkedHashMap though ...
          Hide
          Jörg Schaible added a comment -

          Should have been:

          Parameter p = new CCParameter();
          String[] stringsChild = p.resolveInstance(child, null, String[]);
          String[] stringsParent = p.resolveInstance(parent, null, String[]);

          Show
          Jörg Schaible added a comment - Should have been: Parameter p = new CCParameter(); String[] stringsChild = p.resolveInstance(child, null, String[]); String[] stringsParent = p.resolveInstance(parent, null, String[]);
          Hide
          Grégory Joseph added a comment -

          Joerg,

          Since I haven't personnaly really enjoyed using child/parent container relations - outside of those provided by nanowar, that is - I don't really have an opinion as to what your examples should result in. However, I believe that they should be, in any case, in a predictable order, which is not the case currently - well, you could predict it if you could guess what the hashcode() of your CompKey return, which I don't even want to think about

          While looking for an alternative to LinkedHM which would be jdk1.3 compatible, I came accross this:
          http://cvs.sourceforge.net/viewcvs.py/springframework/spring/src/org/springframework/core/CollectionFactory.java
          How about using something similar, which would instantiate a type of Map depending on what's available? (Of course, this particular example isn't the best there is <gg>, but the idea is there)

          Show
          Grégory Joseph added a comment - Joerg, Since I haven't personnaly really enjoyed using child/parent container relations - outside of those provided by nanowar, that is - I don't really have an opinion as to what your examples should result in. However, I believe that they should be, in any case, in a predictable order, which is not the case currently - well, you could predict it if you could guess what the hashcode() of your CompKey return, which I don't even want to think about While looking for an alternative to LinkedHM which would be jdk1.3 compatible, I came accross this: http://cvs.sourceforge.net/viewcvs.py/springframework/spring/src/org/springframework/core/CollectionFactory.java How about using something similar, which would instantiate a type of Map depending on what's available? (Of course, this particular example isn't the best there is <gg>, but the idea is there)
          Hide
          Jörg Schaible added a comment -

          In this case I would rather copy the code of the LinkedMap of c-c as inner class to CollectionParam and remove it as soon as we drop JDK 1.3.x. Note, such an action is encouraged by the policy of Jakrta Commons, a lot of them were originally never designed as standalone library, but of usable code fragments. At least as long as you don't use the original package name

          Show
          Jörg Schaible added a comment - In this case I would rather copy the code of the LinkedMap of c-c as inner class to CollectionParam and remove it as soon as we drop JDK 1.3.x. Note, such an action is encouraged by the policy of Jakrta Commons, a lot of them were originally never designed as standalone library, but of usable code fragments. At least as long as you don't use the original package name
          Hide
          Mauro Talevi added a comment -

          I agree with Joerg - as long as we give credit and reference - I should think is a better solution.

          Show
          Mauro Talevi added a comment - I agree with Joerg - as long as we give credit and reference - I should think is a better solution.
          Hide
          Grégory Joseph added a comment -

          Mind that if we copy it roughly, it's going to be an inner class of about 2000 lines of code

          Show
          Grégory Joseph added a comment - Mind that if we copy it roughly, it's going to be an inner class of about 2000 lines of code
          Hide
          Jörg Schaible added a comment -

          As alternative you might set the "fix version" to 1.3 <veg>

          Show
          Jörg Schaible added a comment - As alternative you might set the "fix version" to 1.3 <veg>
          Hide
          Grégory Joseph added a comment -

          If 1.3 will require jdk1.4, well yes, sure, I can live with that in the meantime (because my CompB can be instanciated easily, they have no deps, currently )

          Show
          Grégory Joseph added a comment - If 1.3 will require jdk1.4, well yes, sure, I can live with that in the meantime (because my CompB can be instanciated easily, they have no deps, currently )
          Grégory Joseph made changes -
          Fix Version/s 1.3 [ 11331 ]
          Fix Version/s 1.2 [ 11330 ]
          Hide
          Mauro Talevi added a comment -

          We could also provide in .alternatives or .gems a different implementation of CCParameter -
          say OrderPreservingCollectionComponentParameter or JDK14CollectionComponentParameter -
          which uses the LinkedHashMap and requires JDK1.4.
          We would still have 1.3 compat for all that is possible in 1.3, but allow users that use Pico with 1.4
          to do so.
          Same we could do with some 1.5 features. As long as they are compiled with 1.5 but not used
          as default .

          Show
          Mauro Talevi added a comment - We could also provide in .alternatives or .gems a different implementation of CCParameter - say OrderPreservingCollectionComponentParameter or JDK14CollectionComponentParameter - which uses the LinkedHashMap and requires JDK1.4. We would still have 1.3 compat for all that is possible in 1.3, but allow users that use Pico with 1.4 to do so. Same we could do with some 1.5 features. As long as they are compiled with 1.5 but not used as default .
          Hide
          Jörg Schaible added a comment -

          I would rather wait for pico 1.3. Currently I can just switch the jdk to 1.3 to run all unit tests otherwise I cannot.

          Show
          Jörg Schaible added a comment - I would rather wait for pico 1.3. Currently I can just switch the jdk to 1.3 to run all unit tests otherwise I cannot.
          Grégory Joseph made changes -
          Link This issue is depended upon by BERKANO-17 [ BERKANO-17 ]
          Hide
          Christopher Paul Simmons added a comment -

          Could we take a leaf out of the picocontainer book, and use picocontainer to configure picocontainer (with a Map/SetFactory perhaps?). The default behaviour could be retained, but this would allow the user to inject the set/map implementation of their choice.

          In my application we have gone to considerable lengths to try and ensure deterministic behaviour and it would be unfortunate if we were unable to use picocontainer because of the nondeterminism this introduces.

          Show
          Christopher Paul Simmons added a comment - Could we take a leaf out of the picocontainer book, and use picocontainer to configure picocontainer (with a Map/SetFactory perhaps?). The default behaviour could be retained, but this would allow the user to inject the set/map implementation of their choice. In my application we have gone to considerable lengths to try and ensure deterministic behaviour and it would be unfortunate if we were unable to use picocontainer because of the nondeterminism this introduces.
          Hide
          Grégory Joseph added a comment -

          Here's a patch based on the Map Factory idea.
          Tell me what you think.
          Testcase passes on jdk1.4 or jdk1.3+commons-collections

          Show
          Grégory Joseph added a comment - Here's a patch based on the Map Factory idea. Tell me what you think. Testcase passes on jdk1.4 or jdk1.3+commons-collections
          Grégory Joseph made changes -
          Attachment PICO-243-order.patch [ 17762 ]
          Hide
          Mauro Talevi added a comment -

          Since it's backward compatible and falls back on the HashMap impl for JDK1.3 and no commons-collections
          I see no problem in pushing this into 1.2 release.

          Show
          Mauro Talevi added a comment - Since it's backward compatible and falls back on the HashMap impl for JDK1.3 and no commons-collections I see no problem in pushing this into 1.2 release.
          Hide
          Grégory Joseph added a comment -

          Patch applied.

          Show
          Grégory Joseph added a comment - Patch applied.
          Grégory Joseph made changes -
          Assignee Grégory Joseph [ gjoseph ]
          Resolution Fixed [ 1 ]
          Status Open [ 1 ] Resolved [ 5 ]
          Fix Version/s 1.3 [ 11331 ]
          Fix Version/s 1.2 [ 11330 ]

            People

            • Assignee:
              Grégory Joseph
              Reporter:
              Grégory Joseph
            • Votes:
              0 Vote for this issue
              Watchers:
              0 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved: