Commons Collections
  1. Commons Collections
  2. COLLECTIONS-508

MultiMap's methods are not strongly typed even though the interface supports generics

    Details

    • Type: Improvement Improvement
    • Status: Closed
    • Priority: Major Major
    • Resolution: Fixed
    • Affects Version/s: 4.0
    • Fix Version/s: 4.1
    • Component/s: Map
    • Labels:
      None

      Description

      Recently I had the need of using a MultiMap in one of my projects. While using the same, I found that the MultiMap interface has methods that are not strongly typed even though the interface supports generics. For example if I have a MultiMap like so

      MultiMap<String, User> multiMap = new MultiValueMap<String, User>();

      where User is a custom Class, then the get(key) method would return me an Object which I would need to cast to a Collection like so

      Collection<User> userCol = (Collection<User>) multiMap.get(key);

      I understand that this limitation comes from that fact that the MultiMap extends IterableMap which in turn extends Map and other interfaces. Hence the MultiMap cannot have a get method which returns a Collection instead of Object as that would mean implementing IterableMap with the Generics set to be <K,Collection<V>>. In that case the put method's signature would become

      public Collection<V> put(K key, Collection<V> value);

      which we do not want.The same problem would arise with other methods as well, ex: containsValue method.

      My proposal is why carry on the signatures of a Map and put it on MultiMap. Where as I do agree that it is a Map after all and has very similar implementation and functionality, it is very different at other levels. And even though the MultiMap interface supports generics, the methods are not strongly typed, which defeats the purpose of having generics. So why can't we have a separate set of interfaces for MultiMap which do not extend Map. That way we can have strongly typed methods on the MultiMap.

      I have included a a patch for these changes. It is not fully complete and has some gaps in some TestCases and the documentation but gives a fairly good idea of what I am talking about. Please let me know your thoughts on taking this approach. Then i will improve the implementation and submit another patch.

      The other way could be that we let MultiMap extend the interfaces it does today, but with proper types rather than Object. I mean something like this

      public interface MultiMap<K,V> extends IterableMap<K,Collection<V>> instead of
      public interface MultiMap<K,V> extends IterableMap<K,Object>

      And then have a separate set of methods on the MultiMap interface which supports the specific MultiMap functionality. For example, the put method with the above implementation would become

      Collection<V> put(K key, Collection<V> value)

      and we can have another method as

      V putValue(K key, V value)

      This way the functionality of Map is preserved along with strongly typed MultiMap methods. If you feel that this approach is better than the earlier one, i will implement the same and submit a patch

      1. MultiValuedMap_10.patch
        9 kB
        Dipanjan Laha
      2. MultiValuedMap_2.patch
        46 kB
        Dipanjan Laha
      3. MultiValuedMap_3.patch
        72 kB
        Dipanjan Laha
      4. MultiValuedMap_4.patch
        91 kB
        Dipanjan Laha
      5. MultiValuedMap_5.patch
        44 kB
        Dipanjan Laha
      6. MultiValuedMap_6.patch
        66 kB
        Dipanjan Laha
      7. MultiValuedMap_7.patch
        11 kB
        Dipanjan Laha
      8. MultiValuedMap_8.patch
        53 kB
        Dipanjan Laha
      9. MultiValuedMap_9.patch
        12 kB
        Dipanjan Laha
      10. MultiValuedMap.patch
        65 kB
        Dipanjan Laha
      11. TransformedMultiValuedMap.patch
        18 kB
        Dipanjan Laha

        Activity

        Hide
        Dipanjan Laha added a comment -

        The patch for the first approach mentioned in the description.

        Show
        Dipanjan Laha added a comment - The patch for the first approach mentioned in the description.
        Hide
        Dipanjan Laha added a comment - - edited

        As per my discussions with Thomas and Matt on the commons mailing list, I have implemented the MultiValuedMap interface, the MultiValuedHashMap and a MultiValuedHashMapTest. I haven't completed the documentation yet. If the implementations look fine, I will add the remaining documentations.

        A few more points regarding the implementation

        1. I have added a few methods to the MultiValuedMap interface which were not there in the MultiMap. I think they would be a good addition to the interface IMHO. They are
        boolean containsValue(Object key, Object value);
        int totalSize();
        void putAll(MultiValuedMap<? extends K, ? extends V> map);
        2. I have added an AbstractMultiValuedMapDecoractor on the lines of AbstractMapDecorator, which can be extended by other MultiValuedMap implementations like say a MultiValuedTreeMap
        3. I have created MultiValuedGet and MultiValuedPut to honor the Get/Put split concepts. It was not possible for MultiValuedMap to extend the Get & Put directly due to the limitations I had mentioned in my earlier mail.
        4. I have marked the incomplete documentations with TODO tags.

        Please see the attachment MultiValuedMap.patch

        Show
        Dipanjan Laha added a comment - - edited As per my discussions with Thomas and Matt on the commons mailing list, I have implemented the MultiValuedMap interface, the MultiValuedHashMap and a MultiValuedHashMapTest. I haven't completed the documentation yet. If the implementations look fine, I will add the remaining documentations. A few more points regarding the implementation 1. I have added a few methods to the MultiValuedMap interface which were not there in the MultiMap. I think they would be a good addition to the interface IMHO. They are boolean containsValue(Object key, Object value); int totalSize(); void putAll(MultiValuedMap<? extends K, ? extends V> map); 2. I have added an AbstractMultiValuedMapDecoractor on the lines of AbstractMapDecorator, which can be extended by other MultiValuedMap implementations like say a MultiValuedTreeMap 3. I have created MultiValuedGet and MultiValuedPut to honor the Get/Put split concepts. It was not possible for MultiValuedMap to extend the Get & Put directly due to the limitations I had mentioned in my earlier mail. 4. I have marked the incomplete documentations with TODO tags. Please see the attachment MultiValuedMap.patch
        Hide
        Thomas Neidhart added a comment -

        Hi Dipanjan,

        the patch looks good (the files were duplicated though), just a few comments:

        • Set<Entry<K, Collection<V>>> entrySet():
          I am not so sure if this really makes sense, I think it would be better to have a method like Collection<Entry<K, V> entries
        • boolean containsValue(Object key, Object value): to be consistent with removeMapping, I would propose to name it similar, either both
          xxxMapping or xxxEntry, tbd
        • it would also be interesting to have a Bag<K> keys() method that returns a view of all keys and how many mappings there are for each, but see also below
        • size && totalSize: I would prefer that size returns the total number of mappings (what totalSize does now). The number of keys can be retrieved with keySet().size() imho.
        • a putAll(K key, Iterable<? extends V> values) would be nice too

        Something we have not considered yet is the semantic of the actual Collection type used in the MultiValuedMap. It might have a List or Set behavior, i.e. allowing duplicates or not. We could make specific interfaces for the different types of MultiValuedMaps derived from MultiValuedMap.

        Regarding the Bag issue: actually I wanted to clean up the Bag interface to be fully Collection compliant for 4.0 but we decided to keep it as is. As a workaround there is now a CollectionBag decorator to make a Bag compliant to the Collection contract. We could also add now a new MultiValuedSet interface that is basically the same as a CollectionBag.

        What do you think?

        Show
        Thomas Neidhart added a comment - Hi Dipanjan, the patch looks good (the files were duplicated though), just a few comments: Set<Entry<K, Collection<V>>> entrySet(): I am not so sure if this really makes sense, I think it would be better to have a method like Collection<Entry<K, V> entries boolean containsValue(Object key, Object value): to be consistent with removeMapping, I would propose to name it similar, either both xxxMapping or xxxEntry, tbd it would also be interesting to have a Bag<K> keys() method that returns a view of all keys and how many mappings there are for each, but see also below size && totalSize: I would prefer that size returns the total number of mappings (what totalSize does now). The number of keys can be retrieved with keySet().size() imho. a putAll(K key, Iterable<? extends V> values) would be nice too Something we have not considered yet is the semantic of the actual Collection type used in the MultiValuedMap. It might have a List or Set behavior, i.e. allowing duplicates or not. We could make specific interfaces for the different types of MultiValuedMaps derived from MultiValuedMap. Regarding the Bag issue: actually I wanted to clean up the Bag interface to be fully Collection compliant for 4.0 but we decided to keep it as is. As a workaround there is now a CollectionBag decorator to make a Bag compliant to the Collection contract. We could also add now a new MultiValuedSet interface that is basically the same as a CollectionBag. What do you think?
        Hide
        Dipanjan Laha added a comment - - edited

        Hi Thomas,

        Thanks for looking into the patch. Apologies for the duplicate files, must have messed up somewhere while creating the patch
        Please find my comments below.

        > * Set<Entry<K, Collection<V>>> entrySet():
        > I am not so sure if this really makes sense, I think it would be better to
        > have a method like Collection<Entry<K, V> entries
        Yes, this definitely makes better sense. I will change the implementation appropriately .

        > * boolean containsValue(Object key, Object value): to be consistent with
        > removeMapping, I would propose to name it similar, either both
        > xxxMapping or xxxEntry, tbd
        IMHO I think containsMapping goes well with removeMapping. What do you think?

        > * it would also be interesting to have a Bag<K> keys() method that
        > returns a view of all keys and how many mappings there are for each,
        > but see also below
        Find my comments below

        > * size && totalSize: I would prefer that size returns the total number of
        > mappings (what totalSize does now). The number of keys can be
        > retrieved with keySet().size() imho.
        I couldn't agree more. I kept it so that it would be consistent with the MultiValueMap implementation, but it is quite confusing. I will make the proposed changes.

        > * a putAll(K key, Iterable<? extends V> values) would be nice too
        I will add this method too.

        > Something we have not considered yet is the semantic of the actual
        > Collection type used in the MultiValuedMap. It might have a List or Set
        > behavior, i.e. allowing duplicates or not. We could make specific
        > interfaces for the different types of MultiValuedMaps derived from
        > MultiValuedMap.
        We can surely have specific interfaces for different types of MultiValuedMaps. I was thinking on the lines that we can have a flag like allowDuplicates in the implementing class which can be taken as an argument in a constructor. But your proposal is better as we can then have strongly typed methods which can return a List or a Set depending upon the behavior. My only concern is that we would end up with two implementations for each type of MultiValuedMap, one each for Set & List. If this is fine then we can go ahead with this. One more thing, then should we have MultiValuedHashMap anymore? It would be MultiValuedSetHashMap and MultiValuedListHashMap which can implement MultiValuedMap(common to both) and MultiValuedSetMap and MultiValuedListMap individually(In this case we also need to think about the names too). What do you think?

        >Regarding the Bag issue: actually I wanted to clean up the Bag interface
        > to be fully Collection compliant for 4.0 but we decided to keep it as is. As
        > a workaround there is now a CollectionBag decorator to make a Bag
        > compliant to the Collection contract. We could also add now a new
        > MultiValuedSet interface that is basically the same as a CollectionBag.
        >
        >What do you think?
        I think the Bag<K> keys() method can be really useful IMHO. We can have a new MultiValuedSet interface, but that would be kind of moving away from the Bag interface. Wouldn't it be better to clean up the Bag interface or would it hamper the backward compatibility? In that case we can have a MultiValuedSet interface and have a MultiValuedSetWrapper(or some other name) class for wrapping the existing Bag implementations or have a completely different set of implementations for MultiValuedSet. I think IMHO that we should hold on with the Bag<K> keys() method till we decide on the above issue. Let me know your thoughts.

        Show
        Dipanjan Laha added a comment - - edited Hi Thomas, Thanks for looking into the patch. Apologies for the duplicate files, must have messed up somewhere while creating the patch Please find my comments below. > * Set<Entry<K, Collection<V>>> entrySet(): > I am not so sure if this really makes sense, I think it would be better to > have a method like Collection<Entry<K, V> entries Yes, this definitely makes better sense. I will change the implementation appropriately . > * boolean containsValue(Object key, Object value): to be consistent with > removeMapping, I would propose to name it similar, either both > xxxMapping or xxxEntry, tbd IMHO I think containsMapping goes well with removeMapping. What do you think? > * it would also be interesting to have a Bag<K> keys() method that > returns a view of all keys and how many mappings there are for each, > but see also below Find my comments below > * size && totalSize: I would prefer that size returns the total number of > mappings (what totalSize does now). The number of keys can be > retrieved with keySet().size() imho. I couldn't agree more. I kept it so that it would be consistent with the MultiValueMap implementation, but it is quite confusing. I will make the proposed changes. > * a putAll(K key, Iterable<? extends V> values) would be nice too I will add this method too. > Something we have not considered yet is the semantic of the actual > Collection type used in the MultiValuedMap. It might have a List or Set > behavior, i.e. allowing duplicates or not. We could make specific > interfaces for the different types of MultiValuedMaps derived from > MultiValuedMap. We can surely have specific interfaces for different types of MultiValuedMaps. I was thinking on the lines that we can have a flag like allowDuplicates in the implementing class which can be taken as an argument in a constructor. But your proposal is better as we can then have strongly typed methods which can return a List or a Set depending upon the behavior. My only concern is that we would end up with two implementations for each type of MultiValuedMap, one each for Set & List. If this is fine then we can go ahead with this. One more thing, then should we have MultiValuedHashMap anymore? It would be MultiValuedSetHashMap and MultiValuedListHashMap which can implement MultiValuedMap(common to both) and MultiValuedSetMap and MultiValuedListMap individually(In this case we also need to think about the names too). What do you think? >Regarding the Bag issue: actually I wanted to clean up the Bag interface > to be fully Collection compliant for 4.0 but we decided to keep it as is. As > a workaround there is now a CollectionBag decorator to make a Bag > compliant to the Collection contract. We could also add now a new > MultiValuedSet interface that is basically the same as a CollectionBag. > >What do you think? I think the Bag<K> keys() method can be really useful IMHO. We can have a new MultiValuedSet interface, but that would be kind of moving away from the Bag interface. Wouldn't it be better to clean up the Bag interface or would it hamper the backward compatibility? In that case we can have a MultiValuedSet interface and have a MultiValuedSetWrapper(or some other name) class for wrapping the existing Bag implementations or have a completely different set of implementations for MultiValuedSet. I think IMHO that we should hold on with the Bag<K> keys() method till we decide on the above issue. Let me know your thoughts.
        Hide
        Thomas Neidhart added a comment -

        IMHO I think containsMapping goes well with removeMapping. What do you think?

        thats fine for me.

        Regarding the List & Set MultiValuedMap, what we could do there is to hide this detail completely in the implementation and just provide static factory methods that return a generic MultiValuedMap with either a List or Set as backing collection class. The interfaces ListMultiValuedMap and SetMultiValuedMap would just act as marker interfaces to make the intent clear. I will give it a try with your current patch and see if this can work.

        Regarding MultiValuedSet vs Bag:

        The MultiValuedSet I had in mind (probably a bad name) is the same as the CollectionBag is now, it counts the number of times an object is in this Set the same as the Bag does, but follows the Collection contract. I would see it as a design goal to make all collection classes compliant with the Collection contract. This would make the use of collections less error-prone, but I understand that there are people who value the Bag interface as it is now.

        Show
        Thomas Neidhart added a comment - IMHO I think containsMapping goes well with removeMapping. What do you think? thats fine for me. Regarding the List & Set MultiValuedMap, what we could do there is to hide this detail completely in the implementation and just provide static factory methods that return a generic MultiValuedMap with either a List or Set as backing collection class. The interfaces ListMultiValuedMap and SetMultiValuedMap would just act as marker interfaces to make the intent clear. I will give it a try with your current patch and see if this can work. Regarding MultiValuedSet vs Bag: The MultiValuedSet I had in mind (probably a bad name) is the same as the CollectionBag is now, it counts the number of times an object is in this Set the same as the Bag does, but follows the Collection contract. I would see it as a design goal to make all collection classes compliant with the Collection contract. This would make the use of collections less error-prone, but I understand that there are people who value the Bag interface as it is now.
        Hide
        Dipanjan Laha added a comment -

        Regarding MultiValuedSet vs Bag:
        The MultiValuedSet I had in mind (probably a bad name) is the same as the CollectionBag is now, it counts the number of times an object is in this Set the same as the Bag does, but follows the Collection contract. I would see it as a design goal to make all collection classes compliant with the Collection contract. This would make the use of collections less error-prone, but I understand that there are people who value the Bag interface as it is now.

        In that case we can have a separate set of implementations for MultiValuedSet (I actually like this name) and maybe retire CollectionBag at some time (as of now it lack documentation & the methods in the Java docs has Violation marked as the docs are getting inherited from Bag). Till this is decided, should I add a Bag<K> keyBag() (making it similar to keySet method) method? Later we can also have a MultiValuedSet<K> keys() too. Let me know.

        I have almost completed the rest of the changes, will submit another patch soon.

        Show
        Dipanjan Laha added a comment - Regarding MultiValuedSet vs Bag: The MultiValuedSet I had in mind (probably a bad name) is the same as the CollectionBag is now, it counts the number of times an object is in this Set the same as the Bag does, but follows the Collection contract. I would see it as a design goal to make all collection classes compliant with the Collection contract. This would make the use of collections less error-prone, but I understand that there are people who value the Bag interface as it is now. In that case we can have a separate set of implementations for MultiValuedSet (I actually like this name) and maybe retire CollectionBag at some time (as of now it lack documentation & the methods in the Java docs has Violation marked as the docs are getting inherited from Bag). Till this is decided, should I add a Bag<K> keyBag() (making it similar to keySet method) method? Later we can also have a MultiValuedSet<K> keys() too. Let me know. I have almost completed the rest of the changes, will submit another patch soon.
        Hide
        Thomas Neidhart added a comment -

        CollectionBag is just a decorator for a Bag to make it compliant with the Collection contract, but I just realize now that the javadoc should have been updated to reflect this, as it would otherwise inherit the one from the Bag interface. Thanks for spotting!

        Show
        Thomas Neidhart added a comment - CollectionBag is just a decorator for a Bag to make it compliant with the Collection contract, but I just realize now that the javadoc should have been updated to reflect this, as it would otherwise inherit the one from the Bag interface. Thanks for spotting!
        Hide
        Dipanjan Laha added a comment -

        I have made the changes as discussed and attached it as MultiValuedMap_2.patch. Here's a summary of the changes

        • added a method Collection<Entry<K, V> entries() in place of Set<Entry<K, Collection<V>>> entrySet().
        • removed totalSize and now size() returns the total no. of values
        • added putAll(K key, Iterable<? extends V> values)
        • changed containsValue(key, value) to containsMapping(key, value)
        • changed the Test cases appropriately

        I am a bit unclear on Bag<K> keys() method, should I add that?

        Show
        Dipanjan Laha added a comment - I have made the changes as discussed and attached it as MultiValuedMap_2.patch. Here's a summary of the changes added a method Collection<Entry<K, V> entries() in place of Set<Entry<K, Collection<V>>> entrySet(). removed totalSize and now size() returns the total no. of values added putAll(K key, Iterable<? extends V> values) changed containsValue(key, value) to containsMapping(key, value) changed the Test cases appropriately I am a bit unclear on Bag<K> keys() method, should I add that?
        Hide
        Thomas Neidhart added a comment -

        I did take a look at the second patch:

        • the AbstractMultiValuedMapDecorator is not what the name implies: it is rather an AbstractMultiValuedMap, a decorator for a MultiValuedMap should just delegate all calls of the MultiValuedMap interface to an underlying instance.
        • it would help if you use the same checkstyle/formatting settings as the project, especially trailing spaces should be removed
        • documentation is missing
        • you can add the Bag<K> keys() method. If we really add a MultiValuedSet we can easily change it later

        If you update these things, I can commit it as a first version and we can continue working on it, I would like to have at least the following things before a 4.1 release:

        • Unmodifiable decorator
        • Transformed decorator

        @Put/Get interface:

        I know that Matt mentioned them, but I do not really see a value in or use-case for them. Unless somebody really convinces me that this is useful I would keep it aside.

        Show
        Thomas Neidhart added a comment - I did take a look at the second patch: the AbstractMultiValuedMapDecorator is not what the name implies: it is rather an AbstractMultiValuedMap, a decorator for a MultiValuedMap should just delegate all calls of the MultiValuedMap interface to an underlying instance. it would help if you use the same checkstyle/formatting settings as the project, especially trailing spaces should be removed documentation is missing you can add the Bag<K> keys() method. If we really add a MultiValuedSet we can easily change it later If you update these things, I can commit it as a first version and we can continue working on it, I would like to have at least the following things before a 4.1 release: Unmodifiable decorator Transformed decorator @Put/Get interface: I know that Matt mentioned them, but I do not really see a value in or use-case for them. Unless somebody really convinces me that this is useful I would keep it aside.
        Hide
        Dipanjan Laha added a comment -

        Hi Thomas,

        You correctly pointed out that AbstractMultiValuedMapDecorator is not actually a decorator, my bad. I'll rename it.
        I will also take care of the formatting issues and documentations. I will add a Unmodifiable decorator & a Transformed decorator and remove Get/Put interfaced for MultiValuedMap as suggested. And yes, a Bag<K> keys() method too.
        I will submit a patch with these changes within a couple of days.

        Show
        Dipanjan Laha added a comment - Hi Thomas, You correctly pointed out that AbstractMultiValuedMapDecorator is not actually a decorator, my bad. I'll rename it. I will also take care of the formatting issues and documentations. I will add a Unmodifiable decorator & a Transformed decorator and remove Get/Put interfaced for MultiValuedMap as suggested. And yes, a Bag<K> keys() method too. I will submit a patch with these changes within a couple of days.
        Hide
        Thomas Neidhart added a comment -

        Also, do not forget to add the Apache license header as it was missing in the previous patches but I forgot to mention it.

        Show
        Thomas Neidhart added a comment - Also, do not forget to add the Apache license header as it was missing in the previous patches but I forgot to mention it.
        Hide
        Dipanjan Laha added a comment -

        Yes, I have added the license headers. I have made the other changes that you had mentioned, but I haven't completed the Unmodifiable & Transformed decorators. So I have created a patch without those, I will complete those soon and submit them here.
        In this patch (MultiValuedMap_3), I have

        • Modified the AbstractMultiValuedMapDecorator to AbstractMultiValuedMap
        • Tried to keep the same checkstyle/formatting as per the project
        • Added a Bag<K> keys method (please go through the implementation of this, I could not find a suitable Bag implementation to extend)
        • Added the documentation
        • Removed the Put/Get interface for MultiValuedMap
        Show
        Dipanjan Laha added a comment - Yes, I have added the license headers. I have made the other changes that you had mentioned, but I haven't completed the Unmodifiable & Transformed decorators. So I have created a patch without those, I will complete those soon and submit them here. In this patch (MultiValuedMap_3), I have Modified the AbstractMultiValuedMapDecorator to AbstractMultiValuedMap Tried to keep the same checkstyle/formatting as per the project Added a Bag<K> keys method (please go through the implementation of this, I could not find a suitable Bag implementation to extend) Added the documentation Removed the Put/Get interface for MultiValuedMap
        Hide
        Dipanjan Laha added a comment -

        Hi Thomas,

        Did you find time to take a look at my last patch?
        Also, while implementing the UnmodifiableMultiValuedMap, I made some changes in the AbstractMultiValuedMap and the test cases for it. I have created a AbstractMultiValuedMap test on the same lines of AbstractMapTest and made MultiValuedHashMapTest & UnmodifiableMultiValuedMapTest extend it. So what I wanted to ask was should I create a patch for these changes on top of my last changes (MultiValuedMap_3.patch) or should I create a patch from scratch containing all the changes till now?
        Let me know as I am done with the Unmodifiable map's implementation and test cases and would like to submit the same. I am working on the Transformed map's implementation should be able to complete that soon.

        Show
        Dipanjan Laha added a comment - Hi Thomas, Did you find time to take a look at my last patch? Also, while implementing the UnmodifiableMultiValuedMap, I made some changes in the AbstractMultiValuedMap and the test cases for it. I have created a AbstractMultiValuedMap test on the same lines of AbstractMapTest and made MultiValuedHashMapTest & UnmodifiableMultiValuedMapTest extend it. So what I wanted to ask was should I create a patch for these changes on top of my last changes (MultiValuedMap_3.patch) or should I create a patch from scratch containing all the changes till now? Let me know as I am done with the Unmodifiable map's implementation and test cases and would like to submit the same. I am working on the Transformed map's implementation should be able to complete that soon.
        Hide
        Thomas Neidhart added a comment -

        I am working on your patch but I am not finished yet, so you can attach a patch containing all of your changes which is easier to handle for me.

        There are several things I am working on and I am planning to commit a first version till the weekend.

        Show
        Thomas Neidhart added a comment - I am working on your patch but I am not finished yet, so you can attach a patch containing all of your changes which is easier to handle for me. There are several things I am working on and I am planning to commit a first version till the weekend.
        Hide
        Dipanjan Laha added a comment -

        I have attached a patch (MultiValuedMap_4) which has the UnmodifiableMultiValuedMap including all my earlier changes. It has some other changes which I am listing below.

        • I have created a AbstractMultiValuedMapDecorator which UnmodifiableMultiValuedMap is extending
        • I have added two methods to MultiValuedMap, size(Object key) and iterator(Object key). Let me know if you think that these do not make sense, i'll remove them.
        • The equals method of AbstractMultiValuedMap was flawed in my earlier patch, I have changed it, please take a look.
        • I have created a AbstractMultiValuedMapTest which can be extended by others. I have changed MultiValuedHashMapTest to extend it and so does UnmodifiableMultiValuedMapTest.

        I am working on the Transformed map which I should complete by the weekend.
        It would be great if you can point out my errors in my earlier patch, so hopefully I won't make them again

        Show
        Dipanjan Laha added a comment - I have attached a patch (MultiValuedMap_4) which has the UnmodifiableMultiValuedMap including all my earlier changes. It has some other changes which I am listing below. I have created a AbstractMultiValuedMapDecorator which UnmodifiableMultiValuedMap is extending I have added two methods to MultiValuedMap, size(Object key) and iterator(Object key). Let me know if you think that these do not make sense, i'll remove them. The equals method of AbstractMultiValuedMap was flawed in my earlier patch, I have changed it, please take a look. I have created a AbstractMultiValuedMapTest which can be extended by others. I have changed MultiValuedHashMapTest to extend it and so does UnmodifiableMultiValuedMapTest. I am working on the Transformed map which I should complete by the weekend. It would be great if you can point out my errors in my earlier patch, so hopefully I won't make them again
        Hide
        Dipanjan Laha added a comment -

        Hey Thomas, I have implemented the TransformedMultiValuedMap and its tests. I am attaching a patch for the same (TransformedMultiValuedMap.patch). I have implemented this on the lines of TransformedMap. I have some comments around this.

        • The TransformedMap only overrides the put methods with the transformations. All the get, contains & remove methods need transformed keys and values to be passed(I have kept it the same in my implementation). However, IMHO I feel that any parameters passed into a Transformed map's methods should be in their non-transformed form and any thing returned from the map should be in their Transformed form. In effect, the get, remove and contains methods should take in non-transformed keys & values. What do you think?
        • The transformers only allow transformation to a subclass, hence for a String to Integer transformer, we need to set all the generic types as Objects and eventually cast stuff appropriately. I understand that this is due to the fact that otherwise it would mess up the Map (or in our case, MulltiValuedMap) contract. But IMHO I think that there needs to be a better way to do this. I am not exactly sure what, but maybe a separate contract for Transformed implementations. We can discuss this more if you feel that this is a valid point.

        Let me know if there is anything I need to improve. Otherwise what can I pick up next?

        Show
        Dipanjan Laha added a comment - Hey Thomas, I have implemented the TransformedMultiValuedMap and its tests. I am attaching a patch for the same (TransformedMultiValuedMap.patch). I have implemented this on the lines of TransformedMap. I have some comments around this. The TransformedMap only overrides the put methods with the transformations. All the get, contains & remove methods need transformed keys and values to be passed(I have kept it the same in my implementation). However, IMHO I feel that any parameters passed into a Transformed map's methods should be in their non-transformed form and any thing returned from the map should be in their Transformed form. In effect, the get, remove and contains methods should take in non-transformed keys & values. What do you think? The transformers only allow transformation to a subclass, hence for a String to Integer transformer, we need to set all the generic types as Objects and eventually cast stuff appropriately. I understand that this is due to the fact that otherwise it would mess up the Map (or in our case, MulltiValuedMap) contract. But IMHO I think that there needs to be a better way to do this. I am not exactly sure what, but maybe a separate contract for Transformed implementations. We can discuss this more if you feel that this is a valid point. Let me know if there is anything I need to improve. Otherwise what can I pick up next?
        Hide
        Dipanjan Laha added a comment -

        Do you think it makes sense to have a MapIterator mapIterator() method for MultiValuedMap? I saw that it has been used widely in Map implementations and IMHO I think it would be a good addition.
        In case we do add it, should it be a part of MultiValuedMap or should we have a separated interface like IterableMultiValuedMap which would add the mapIterator() method? Personally, I feel that we can have it in MultiValuedMap itself.
        Let me know your thoughts, then I can work on this.

        Show
        Dipanjan Laha added a comment - Do you think it makes sense to have a MapIterator mapIterator() method for MultiValuedMap? I saw that it has been used widely in Map implementations and IMHO I think it would be a good addition. In case we do add it, should it be a part of MultiValuedMap or should we have a separated interface like IterableMultiValuedMap which would add the mapIterator() method? Personally, I feel that we can have it in MultiValuedMap itself. Let me know your thoughts, then I can work on this.
        Hide
        Thomas Neidhart added a comment - - edited

        In r1581553, I have committed the a cleaned up version of the patches.

        Some things that I changes:

        • removed size(Object) and iterator(Object), see rationale below
        • added a ListValuedMap interface
        • improved documentation

        There is still a lot of things todo:

        • add bulk test similar to Map that test operations on all the returned collections from the interface
        • the retrieval methods for a Key like get(Object) should never return a null Collection, this would simplify the interface and one
          can always safely operate on the returned result, e.g. get(key1).add(value);
        • a MapIterator would make sense imho
        • the Unmodifiable decorator is not yet fully unmodifiable, i.e. the result returned by entries() can be modified
        • add a SetValuedMap interface
        • support also sorted maps
        • add a Util class for factory methods to create various typical types of MultiValuedMaps, e.g. a method
          createArrayListValuedHashMap(), I would prefer this over specific types to avoid bloat
        • maybe add a Builder to easily create a MultiValuedMap by specifying the map and collection type
        • add a method asMap() to the interface which returns a Map view
        • we should support an estimated value collection size parameter which initializes the created collection to this initial size as the default sizes may not appropriate in many cases.

        @Transformed: if we allow transformers to other types we would break the contract, so this is not possible right now. It is still possible by using raw types, but this is a general problem affecting all collection types and should thus be discussed separately.

        Anyway, great work so far.

        Show
        Thomas Neidhart added a comment - - edited In r1581553, I have committed the a cleaned up version of the patches. Some things that I changes: removed size(Object) and iterator(Object), see rationale below added a ListValuedMap interface improved documentation There is still a lot of things todo: add bulk test similar to Map that test operations on all the returned collections from the interface the retrieval methods for a Key like get(Object) should never return a null Collection, this would simplify the interface and one can always safely operate on the returned result, e.g. get(key1).add(value); a MapIterator would make sense imho the Unmodifiable decorator is not yet fully unmodifiable, i.e. the result returned by entries() can be modified add a SetValuedMap interface support also sorted maps add a Util class for factory methods to create various typical types of MultiValuedMaps, e.g. a method createArrayListValuedHashMap(), I would prefer this over specific types to avoid bloat maybe add a Builder to easily create a MultiValuedMap by specifying the map and collection type add a method asMap() to the interface which returns a Map view we should support an estimated value collection size parameter which initializes the created collection to this initial size as the default sizes may not appropriate in many cases. @Transformed: if we allow transformers to other types we would break the contract, so this is not possible right now. It is still possible by using raw types, but this is a general problem affecting all collection types and should thus be discussed separately. Anyway, great work so far.
        Hide
        Dipanjan Laha added a comment -

        Thanks Thomas. It's great to see the first version committed

        I will pick up the following and work on those for now

        add bulk test similar to Map that test operations on all the returned collections from the interface

        • I will add these

        the retrieval methods for a Key like get(Object) should never return a null Collection, this would simplify the interface and one
        can always safely operate on the returned result, e.g. get(key1).add(value);

        • I did think about this, but there is one problem here. For every get with non existent keys, we would need to add a mapping with an empty collection and return that. Otherwise get(key1).add(value) would add the value in the collection, but the collection would not be there in the map. I am not sure whether this behavior of adding an empty Collection in the map for each get with non-existent key is acceptable. Or, it just occurred to me just now that in case of non existent keys, we can return a custom implementation of Collection which has a reference to the map and the key, and would add itself as a mapping when add(value) is called on it. let me know what you think? I'll implement accordingly.
        • I will add a MapIterator

        the Unmodifiable decorator is not yet fully unmodifiable, i.e. the result returned by entries() can be modified

        • The Entry elements in the entries() collection is inherently Unmodifiable i.e Entry.setValue(val) (in AbstractMultiValuedMap) throws UnsupportedOperationException. This is so because imho the setValue for an entry of MultiValuedMap does not make sense as the original mapping is actually a collection. I have also wrapped the entries collections in an UnmodifiableCollection while returning from UnmodifiableMultiValedMap. Let me know if I have missed a gap which is making it modifiable. Also, let me know if you feel differently about the Entry of a MultiValuedMap being inherently unmodifiable, maybe the setValue should replace all the occurrences of the original value in the mapped Collection.
        • I will add SetValuedMap. Are you thinking of factory methods in the MultiValuedMap's implementations (say MultiValuedHashMap) to return ListValuedMap and SetValuedMap or would you have these in the Util class you mentioned?
        • I will work on a SortedMap implementation. I might have some questions around this, I'll ask you once I sit with it.
        • I will add an asMap() method.

        I can pick up more stuff once I am done with these. And if by any chance you use eclipse, can you share your code format settings(exported from excel). I saw that the checked in code had a slightly different code style and I would like to confirm to it. That way you won't have to check the code style for each and every patch I submit.

        Show
        Dipanjan Laha added a comment - Thanks Thomas. It's great to see the first version committed I will pick up the following and work on those for now add bulk test similar to Map that test operations on all the returned collections from the interface I will add these the retrieval methods for a Key like get(Object) should never return a null Collection, this would simplify the interface and one can always safely operate on the returned result, e.g. get(key1).add(value); I did think about this, but there is one problem here. For every get with non existent keys, we would need to add a mapping with an empty collection and return that. Otherwise get(key1).add(value) would add the value in the collection, but the collection would not be there in the map. I am not sure whether this behavior of adding an empty Collection in the map for each get with non-existent key is acceptable. Or, it just occurred to me just now that in case of non existent keys, we can return a custom implementation of Collection which has a reference to the map and the key, and would add itself as a mapping when add(value) is called on it. let me know what you think? I'll implement accordingly. I will add a MapIterator the Unmodifiable decorator is not yet fully unmodifiable, i.e. the result returned by entries() can be modified The Entry elements in the entries() collection is inherently Unmodifiable i.e Entry.setValue(val) (in AbstractMultiValuedMap) throws UnsupportedOperationException. This is so because imho the setValue for an entry of MultiValuedMap does not make sense as the original mapping is actually a collection. I have also wrapped the entries collections in an UnmodifiableCollection while returning from UnmodifiableMultiValedMap. Let me know if I have missed a gap which is making it modifiable. Also, let me know if you feel differently about the Entry of a MultiValuedMap being inherently unmodifiable, maybe the setValue should replace all the occurrences of the original value in the mapped Collection. I will add SetValuedMap. Are you thinking of factory methods in the MultiValuedMap's implementations (say MultiValuedHashMap) to return ListValuedMap and SetValuedMap or would you have these in the Util class you mentioned? I will work on a SortedMap implementation. I might have some questions around this, I'll ask you once I sit with it. I will add an asMap() method. I can pick up more stuff once I am done with these. And if by any chance you use eclipse, can you share your code format settings(exported from excel). I saw that the checked in code had a slightly different code style and I would like to confirm to it. That way you won't have to check the code style for each and every patch I submit.
        Hide
        Thomas Neidhart added a comment -

        @get(Object): this was just an idea after looking at the Mulitmap interface of guava. The returned collection would need to be added immediately to avoid undefined behavior when calling get(Object) twice before adding an value. I do not like the fact that containsKey would return something else after get has been called, but never returning null also has benefits. Maybe we should discuss this on the mailinglist

        @Unmodifiable: you are right, I did not check the actual collection returned by entries(), so this should be correct, but we need to add tests to check that the returned collections are indeed unmodifiable

        @SortedMap: maybe we should postpone this to later and first focus on making the existing things complete

        @formatter: I do not use a specific formatter for this project due to the inherited codestyle, but I have checkstyle enabled, using the rules in src/conf/checkstyle.xml

        Show
        Thomas Neidhart added a comment - @get(Object): this was just an idea after looking at the Mulitmap interface of guava. The returned collection would need to be added immediately to avoid undefined behavior when calling get(Object) twice before adding an value. I do not like the fact that containsKey would return something else after get has been called, but never returning null also has benefits. Maybe we should discuss this on the mailinglist @Unmodifiable: you are right, I did not check the actual collection returned by entries(), so this should be correct, but we need to add tests to check that the returned collections are indeed unmodifiable @SortedMap: maybe we should postpone this to later and first focus on making the existing things complete @formatter: I do not use a specific formatter for this project due to the inherited codestyle, but I have checkstyle enabled, using the rules in src/conf/checkstyle.xml
        Hide
        Dipanjan Laha added a comment -

        I have worked on a few things I had mentioned and created another patch over your last commit (MultiValuedMap_5). This patch contains the following

        • Tests for collections returned by UnmodifiableMultiValuedMap to test the unmodifiable behavior
        • Bulk Test for all the collections returned from the map
        • While adding the BulkTests, I found certain issue within the AbstractMultiValuedMap and I fixed them
        • Also, while adding the Bulk tests, I found an issue with AbstractCollectionTest's testCollectionRemoveAll methods. The sublist call with min and max calculations on getFullElements() returns empty when the getFullElements size is 3. I have fixed that.
        • Added a asMap method and associated tests.
        • Added a mapIterator() and tests.

        I have not touched the get behavior yet as imo a proper consensus has not been reached on the mailing list. Let me know which approach to follow and I will make the appropriate changes.

        I am not working on the sorted map now as suggested by you. I will take up the other items you had mentioned and work on them.

        Show
        Dipanjan Laha added a comment - I have worked on a few things I had mentioned and created another patch over your last commit (MultiValuedMap_5). This patch contains the following Tests for collections returned by UnmodifiableMultiValuedMap to test the unmodifiable behavior Bulk Test for all the collections returned from the map While adding the BulkTests, I found certain issue within the AbstractMultiValuedMap and I fixed them Also, while adding the Bulk tests, I found an issue with AbstractCollectionTest's testCollectionRemoveAll methods. The sublist call with min and max calculations on getFullElements() returns empty when the getFullElements size is 3. I have fixed that. Added a asMap method and associated tests. Added a mapIterator() and tests. I have not touched the get behavior yet as imo a proper consensus has not been reached on the mailing list. Let me know which approach to follow and I will make the appropriate changes. I am not working on the sorted map now as suggested by you. I will take up the other items you had mentioned and work on them.
        Hide
        Thomas Neidhart added a comment -

        Sorry for the delay, will take a look at your patch this weekend!

        Show
        Thomas Neidhart added a comment - Sorry for the delay, will take a look at your patch this weekend!
        Hide
        Dipanjan Laha added a comment -

        No issues Thomas. You can take a look at the new patch I am submitting now(MultiValuedMap_6). This has the changes of the last patch and the new behavior for get (as decided on the mailing list) and tests for it. I have also added support for load factor, initial capacity and initial collection capacity. I have added overloaded constructors for the same. Please review these and also the parameter ordering of the overloaded constructor, I am not sure about that. I have also added a SetValuedMap interface, but no implementations or factory methods for that yet.
        I actually have one question regarding the ListValued and the SetValued maps. We would need concrete implementation as down casting of MultiValuedMap won't work. So should I add abstract implementations for these which would down cast the collection appropriately? The factory methods in MultiValudHashMap can initialize these anonymously and return them. What do you think?

        Show
        Dipanjan Laha added a comment - No issues Thomas. You can take a look at the new patch I am submitting now(MultiValuedMap_6). This has the changes of the last patch and the new behavior for get (as decided on the mailing list) and tests for it. I have also added support for load factor, initial capacity and initial collection capacity. I have added overloaded constructors for the same. Please review these and also the parameter ordering of the overloaded constructor, I am not sure about that. I have also added a SetValuedMap interface, but no implementations or factory methods for that yet. I actually have one question regarding the ListValued and the SetValued maps. We would need concrete implementation as down casting of MultiValuedMap won't work. So should I add abstract implementations for these which would down cast the collection appropriately? The factory methods in MultiValudHashMap can initialize these anonymously and return them. What do you think?
        Hide
        Thomas Neidhart added a comment -

        Applied patch in r1585335.

        Show
        Thomas Neidhart added a comment - Applied patch in r1585335.
        Hide
        Thomas Neidhart added a comment -

        Committed first round of changes in r1585601:

        • review/update of javadoc for MultiValuedMap
        • updated contract for get(Object key): always returns a collection, never returns null
        • changed signature of V put(K, V) to boolean put(K, V) which is more reasonable imho
        • changed contract for remove(Object key): returns an empty unmodifiable collection if the key was not contained in the map

        Rest looks already pretty good, great work.
        Still need a MuliValuedMapUtil class with all the factory methods, although the name is horrible. Need to find a better name....

        Show
        Thomas Neidhart added a comment - Committed first round of changes in r1585601: review/update of javadoc for MultiValuedMap updated contract for get(Object key): always returns a collection, never returns null changed signature of V put(K, V) to boolean put(K, V) which is more reasonable imho changed contract for remove(Object key): returns an empty unmodifiable collection if the key was not contained in the map Rest looks already pretty good, great work. Still need a MuliValuedMapUtil class with all the factory methods, although the name is horrible. Need to find a better name....
        Hide
        Dipanjan Laha added a comment -

        Thanks Thomas.
        I am a bit stuck/confused here and need your help. I was implementing an abstract class for ListValuedMap. But since now we return a WrappedCollection from get, for ListValuedMap we need to return a WrappedList. Also the ListIterator has add() method and this should also add a mapping if not present. I have implemented all this in AbstractListValuedMap and added a factory method in MultiValuedHashMap to instantiate the abstract class anonymously. But I am not quite confident about this. Please review the implementation (MultiValuedMap_7.patch) and let me know your thoughts. I haven't added any documentation or much tests for this yet as this is for your review. Let me know what you think.

        Regarding the MuliValuedMapUtil name, do you think MultiMapUtils make sense? We can later add utils methods for MultiKeyMap here when we move MultiKeyMap to the multimap package.

        Show
        Dipanjan Laha added a comment - Thanks Thomas. I am a bit stuck/confused here and need your help. I was implementing an abstract class for ListValuedMap. But since now we return a WrappedCollection from get, for ListValuedMap we need to return a WrappedList. Also the ListIterator has add() method and this should also add a mapping if not present. I have implemented all this in AbstractListValuedMap and added a factory method in MultiValuedHashMap to instantiate the abstract class anonymously. But I am not quite confident about this. Please review the implementation (MultiValuedMap_7.patch) and let me know your thoughts. I haven't added any documentation or much tests for this yet as this is for your review. Let me know what you think. Regarding the MuliValuedMapUtil name, do you think MultiMapUtils make sense? We can later add utils methods for MultiKeyMap here when we move MultiKeyMap to the multimap package.
        Hide
        Dipanjan Laha added a comment -

        Hi Thomas,
        Did you find time to look at the last patch I submitted. I am not very confident about the implementation of ListValuedMap, so it would be great if you can please review it. Then I will add the docs and the tests.

        I have started work on the MultiMapUtils (let me know if I should change this name) and will submit a first cut soon.

        Show
        Dipanjan Laha added a comment - Hi Thomas, Did you find time to look at the last patch I submitted. I am not very confident about the implementation of ListValuedMap, so it would be great if you can please review it. Then I will add the docs and the tests. I have started work on the MultiMapUtils (let me know if I should change this name) and will submit a first cut soon.
        Hide
        Dipanjan Laha added a comment -

        Hi Thomas, I have done some work on the MultiMapUtils and am attaching a patch for it (MultiValuedMap_8.patch). This has some other additions and changes too.

        • Implementations for ListValuedMap and SetValuedMap. Please review these implementations.
        • Added factory methods for ListValuedMap and SetValuedMap in MultiValuedHashMap and respective tests
        • I have removed MultiValuedHashMap#multiValuedMap(collectionClass) method as imho there's no need for this anymore with the factory methods for ListValuedMap and SetValuedMap
        • The MultiMapUtils is not complete. It lacks the print and the putAll methods. I'll work on them this week. I am not sure how much sense a toProperties & toMap(ResourceBundle) would make for MultiValuedMap (they are present in MapUtils), what do you think? I might have missed other methods too, please point them out.
        • Improved java docs at certain places
        Show
        Dipanjan Laha added a comment - Hi Thomas, I have done some work on the MultiMapUtils and am attaching a patch for it (MultiValuedMap_8.patch). This has some other additions and changes too. Implementations for ListValuedMap and SetValuedMap. Please review these implementations. Added factory methods for ListValuedMap and SetValuedMap in MultiValuedHashMap and respective tests I have removed MultiValuedHashMap#multiValuedMap(collectionClass) method as imho there's no need for this anymore with the factory methods for ListValuedMap and SetValuedMap The MultiMapUtils is not complete. It lacks the print and the putAll methods. I'll work on them this week. I am not sure how much sense a toProperties & toMap(ResourceBundle) would make for MultiValuedMap (they are present in MapUtils), what do you think? I might have missed other methods too, please point them out. Improved java docs at certain places
        Hide
        Thomas Neidhart added a comment -

        Committed latest patch in r1588354.

        I will not have much time the next week so do not expect any activity from my side.

        Regarding the List & Set implementations & factory methods: I thought they may be better fitted in the MultiMapUtils class rather than in the MultiValuedHashMap class, but that would be easy to change.

        Show
        Thomas Neidhart added a comment - Committed latest patch in r1588354. I will not have much time the next week so do not expect any activity from my side. Regarding the List & Set implementations & factory methods: I thought they may be better fitted in the MultiMapUtils class rather than in the MultiValuedHashMap class, but that would be easy to change.
        Hide
        Dipanjan Laha added a comment -

        Thanks Thomas. I'll also be off for the next week as I'll be travelling. I'll try and complete the MultiMapUtils once I am back.

        @List & Set impl: I kept the ListValuedHashMap and SetValuedHashMap classes inside MultiValuedHashMap as imho I feel that these implementations should be a part of the MultiValuedHashMap and should not be inside the utils class. The factory methods can be totally in the utils class, but that would mean making the ListValuedHashMap and SetValuedHashMap classes public. I am not sure if that should be done. What do you think? We can discuss this once you have some time.

        Show
        Dipanjan Laha added a comment - Thanks Thomas. I'll also be off for the next week as I'll be travelling. I'll try and complete the MultiMapUtils once I am back. @List & Set impl: I kept the ListValuedHashMap and SetValuedHashMap classes inside MultiValuedHashMap as imho I feel that these implementations should be a part of the MultiValuedHashMap and should not be inside the utils class. The factory methods can be totally in the utils class, but that would mean making the ListValuedHashMap and SetValuedHashMap classes public. I am not sure if that should be done. What do you think? We can discuss this once you have some time.
        Hide
        Dipanjan Laha added a comment -

        Hi Thomas,

        The equals and the hash code in AbstractMultiValuedMap was flawed and I missed those in the Set and List valued maps. I have changed these and submitted a patch for the same (MultiValuedMap_9).
        Sorry I couldn't complete the utils class, was caught up with too many things. I will complete it by this weekend for sure.
        What are your thoughts on the SortedMultiValuedMap and a MultiValuedTrie, do you want to cut a 4.1 release with the current implementations and push these to a later release?

        Show
        Dipanjan Laha added a comment - Hi Thomas, The equals and the hash code in AbstractMultiValuedMap was flawed and I missed those in the Set and List valued maps. I have changed these and submitted a patch for the same (MultiValuedMap_9). Sorry I couldn't complete the utils class, was caught up with too many things. I will complete it by this weekend for sure. What are your thoughts on the SortedMultiValuedMap and a MultiValuedTrie, do you want to cut a 4.1 release with the current implementations and push these to a later release?
        Hide
        Dipanjan Laha added a comment -

        Hi Thomas,

        I have added the print methods in MultiMapUtils on similar lines as MapUtils (MultiValuedMap_10.patch). However, I am not sure if the format in which I am printing is the best format. Please review the format of the print. I have not added test cases for these methods. I will add them as soon as we freeze down on the format.

        Show
        Dipanjan Laha added a comment - Hi Thomas, I have added the print methods in MultiMapUtils on similar lines as MapUtils (MultiValuedMap_10.patch). However, I am not sure if the format in which I am printing is the best format. Please review the format of the print. I have not added test cases for these methods. I will add them as soon as we freeze down on the format.
        Hide
        Dipanjan Laha added a comment -

        Committed MultiValuedMap_9.patch in r1610049

        Show
        Dipanjan Laha added a comment - Committed MultiValuedMap_9.patch in r1610049
        Hide
        Dipanjan Laha added a comment -

        Thomas Neidhart, Sorry for dissapearing for such a long time, changed my place of work which involved relocating to another country and starting everything afresh.
        Regarding this issue, I think this is complete. The MultiMapUtils might need more methods, which we can added incrementally. What do you think?
        I am keen on getting the 4.1 release out. Let me know what you think is pending so that I can wrap them up.

        Show
        Dipanjan Laha added a comment - Thomas Neidhart , Sorry for dissapearing for such a long time, changed my place of work which involved relocating to another country and starting everything afresh. Regarding this issue, I think this is complete. The MultiMapUtils might need more methods, which we can added incrementally. What do you think? I am keen on getting the 4.1 release out. Let me know what you think is pending so that I can wrap them up.
        Hide
        Thomas Neidhart added a comment -

        np and we should aim for a release soon. I will present collections at ApacheCon in November, so it would be good to have a release at the time or shortly afterwards.

        Show
        Thomas Neidhart added a comment - np and we should aim for a release soon. I will present collections at ApacheCon in November, so it would be good to have a release at the time or shortly afterwards.
        Hide
        Dipanjan Laha added a comment -

        Thomas Neidhart Do you think we should close this ticket, we would be having separate tickets for the different implementations we add.

        Show
        Dipanjan Laha added a comment - Thomas Neidhart Do you think we should close this ticket, we would be having separate tickets for the different implementations we add.
        Hide
        Thomas Neidhart added a comment -

        Completed for 4.1. There are still areas which can be improved, but this can be done in a later release.

        Show
        Thomas Neidhart added a comment - Completed for 4.1. There are still areas which can be improved, but this can be done in a later release.

          People

          • Assignee:
            Dipanjan Laha
            Reporter:
            Dipanjan Laha
          • Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved:

              Development