users@jsr311.java.net

Re: Case insensitive map

From: Reto Bachmann-Gmür <reto_at_gmuer.ch>
Date: Tue, 02 Sep 2008 16:20:38 +0200

Bill Burke wrote:
>
>
> Reto Bachmann-Gmür wrote:
>> Bill Burke wrote:
>>> I wrote a CaseInsensitiveMap. I don't see what the problem is.
>> 1. To which object are instances of your class equals?
>> 2. How to you calculate the hashCode?
>>
>
> Go see for yourself:
>
> http://resteasy.svn.sourceforge.net/viewvc/resteasy/trunk/jaxrs/resteasy-jaxrs/src/main/java/org/jboss/resteasy/util/CaseInsensitiveMap.java?view=markup
>
>
> Its probably not a perfect implementation, but, IIRC, it was pretty damn
> close. Granted, what I really wanted was a case-insensitive lookup of
> headers, so I didn't test much beyond that, but I'm confident I could
> make it work... Then again, I'm usually overconfident.
Your implementations seems fine, you're using the lower-case string for
hash-computation. This would cause a different hash than when the same
entries with keys containing upper-case letters are added to another
Map. While this seems like the best thing to do, if we have to do a
case-insensitive map, strictly speaking this breaks the definition of
java.util.Map. So to me the clean solution to reduce the support for
mixed case keys to HttpHeaders.getRequestHeader(name) and have the Map
contain lower-case keys.
>
>> If you do consider the case of the keys (i.e. use the keys as added)
>> this is against the concept of case-insensitiveness. Also you would
>> have two maps which result as different even though they answer the
>> same value for the same set of keys. If you take the hashCode of key
>> in specific casing you're making an arbitrary choice and it not longer
>> workds properly across different implementations (which is why
>> java.util.Map defines how these Methods are to be implemented).
>>
>
> Internally, you create your own CaseInsensitiveKey and your own internal
> map based on that.
>
>> java.util.Map.get(key) is defined as:
>>> More formally, if this map contains a mapping from a key k to a value
>>> v such that (key==null ? k==null : key.equals(k)), then this method
>>> returns v; otherwise it returns null. (There can be at most one such
>>> mapping.)
>>
>> 3. How do you implement your Map do satisfy this inherited requirement
>> and be case-insensitive for keys?
>>
>
> What you are logically doing is two things:
>
> 1) Overriding the behavior of hashCode() to be consistent in a
> case-insensitive way
For which you make arbitrary decision, so that your implementation is
not only not a map according to java.util.Map but may also incompatible
with other case-insensitive implementations.
>
> 2) Overriding the behavior of String.equals().
>
> In the implementation, what you have to do is write *a lot* of wrapper
> classes to provide this logical behavior.
>
>> 4. Do map.comtainsKey(k) and map.keySet().contains(k) return the same
>> value?
>
> Yes.
>
>> (do you return a case-insensitive set)
>>
>
> IIRC, I do. There's probably bugs, but, I think I was on to the right
> approach.

I think your implementation is at least very close to the best one can
do, but it's about satisfying incompatible requirements between jax-rs
and java.util.Map.

Reto