Creating a Commons Collections MultiValueMap with a custom value collection type

Ryan Bennetts picture Ryan Bennetts · Mar 25, 2014 · Viewed 7.4k times · Source

The 4.0 release of the Apache Commons Collections library has added generics support. I am having trouble converting my code to take advantage of it:

I would like a MultiValueMap which takes a String as a key, and a collection of Strings as the value. But:

  1. The keys should retain insertion ordering (so I create the multi-valued map by decorating a LinkedHashMap)
  2. The values should be unique for each key and retain insertion ordering (so I want the values Collection type to be a LinkedHashSet).

The closest I can get is:

MultiValueMap<String, String> orderedMap = MultiValueMap.multiValueMap(
    new LinkedHashMap<String, Collection<String>>(), 
    LinkedHashSet.class
);

But that produces the error:

The method multiValueMap(Map<K,? super C>, Class<C>) in the type MultiValueMap is not applicable for the arguments (LinkedHashMap<String,Collection<String>>, Class<LinkedHashSet>)

So now I am in generics hell. Any suggestions would be most welcome.

Prior to version 4.0, I accomplished that with the following:

MultiValueMap orderedMap = MultiValueMap.decorate(
    new LinkedHashMap<>(), 
    LinkedHashSet.class
);

Simple! I provide the LinkedHashMap to decorate with MultiValueMap behaviour, and specify the type of collection (LinkedHashSet) to use as the values. But that requires casting when I call put() and get() and so I'd like to be able to use the new generic version provided by 4.0.

Answer

Ryan Bennetts picture Ryan Bennetts · Apr 1, 2014

I consulted the Apache Commons Collections mailing list, where it was explained to me that the interface for MultiValueMap is known to be lacking, but will be revamped in version 4.1 (see here for the JIRA issue and associated discussion).

So in the future we may have a better solution, but in the meantime, as Rohit Jain mentioned in his answer, we're just going to have to suppress some warnings. However, since the key aspect of type safety is for the MultiValueMap (not the custom collection type), the simplest way to achieve this is:

@SuppressWarnings({ "rawtypes", "unchecked" })
MultiValueMap<String, String> orderedMap = 
    MapUtils.multiValueMap(new LinkedHashMap(), LinkedHashSet.class);

Note the use of the MapUtils factory method, rather than the more direct MultiValueMap which I had used in my original question.