You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tapestry.apache.org by jk...@apache.org on 2015/03/19 16:08:26 UTC

tapestry-5 git commit: TAP5-2452: prevent modifications to CaseInsensitiveMap's key set

Repository: tapestry-5
Updated Branches:
  refs/heads/master 65b9671c2 -> 0a1993457


TAP5-2452: prevent modifications to CaseInsensitiveMap's key set


Project: http://git-wip-us.apache.org/repos/asf/tapestry-5/repo
Commit: http://git-wip-us.apache.org/repos/asf/tapestry-5/commit/0a199345
Tree: http://git-wip-us.apache.org/repos/asf/tapestry-5/tree/0a199345
Diff: http://git-wip-us.apache.org/repos/asf/tapestry-5/diff/0a199345

Branch: refs/heads/master
Commit: 0a19934571247b7642fb6b0a6899e2c368b1d0b9
Parents: 65b9671
Author: Jochen Kemnade <jo...@eddyson.de>
Authored: Wed Feb 18 10:08:32 2015 +0100
Committer: Jochen Kemnade <jo...@eddyson.de>
Committed: Thu Mar 19 16:06:08 2015 +0100

----------------------------------------------------------------------
 .../tapestry5/ioc/util/CaseInsensitiveMap.java  | 73 +++++++++++++++++---
 .../ioc/specs/CaseInsensitiveMapSpec.groovy     | 23 ++++++
 2 files changed, 87 insertions(+), 9 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/0a199345/commons/src/main/java/org/apache/tapestry5/ioc/util/CaseInsensitiveMap.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/util/CaseInsensitiveMap.java b/commons/src/main/java/org/apache/tapestry5/ioc/util/CaseInsensitiveMap.java
index f5aff7e..7862f9f 100644
--- a/commons/src/main/java/org/apache/tapestry5/ioc/util/CaseInsensitiveMap.java
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/util/CaseInsensitiveMap.java
@@ -29,7 +29,8 @@ import java.util.*;
  */
 public class CaseInsensitiveMap<V> extends AbstractMap<String, V> implements Serializable
 {
-    private static final long serialVersionUID = 3362718337611953298L;
+
+    private static final long serialVersionUID = -3162531976817110908L;
 
     private static final int NULL_HASH = Integer.MIN_VALUE;
 
@@ -91,9 +92,17 @@ public class CaseInsensitiveMap<V> extends AbstractMap<String, V> implements Ser
         {
             return value == this.value || (value != null && value.equals(this.value));
         }
+
+        @Override
+        public String toString() {
+          StringBuilder builder = new StringBuilder();
+          builder.append("CIMEntry [key=").append(key).append(", value=").append(value).append("]");
+          return builder.toString();
+        }
+
     }
 
-    private class EntrySetIterator implements Iterator
+    private class EntrySetIterator implements Iterator<Entry<String, V>>
     {
         int expectedModCount = modCount;
 
@@ -108,7 +117,7 @@ public class CaseInsensitiveMap<V> extends AbstractMap<String, V> implements Ser
         }
 
         @Override
-        public Object next()
+        public Entry<String, V> next()
         {
             check();
 
@@ -135,13 +144,17 @@ public class CaseInsensitiveMap<V> extends AbstractMap<String, V> implements Ser
         {
             if (expectedModCount != modCount) throw new ConcurrentModificationException();
         }
+
+        @Override
+        public String toString() {
+           return "EntrySetIterator, current key: "+entries[current].key;
+        }
     }
 
-    @SuppressWarnings("unchecked")
-    private class EntrySet extends AbstractSet
+    private class EntrySet extends AbstractSet<Entry<String, V>>
     {
         @Override
-        public Iterator iterator()
+        public Iterator<Entry<String, V>> iterator()
         {
             return new EntrySetIterator();
         }
@@ -163,6 +176,7 @@ public class CaseInsensitiveMap<V> extends AbstractMap<String, V> implements Ser
         {
             if (!(o instanceof Map.Entry)) return false;
 
+            @SuppressWarnings("rawtypes")
             Map.Entry e = (Map.Entry) o;
 
             Position position = select(e.getKey());
@@ -175,6 +189,7 @@ public class CaseInsensitiveMap<V> extends AbstractMap<String, V> implements Ser
         {
             if (!(o instanceof Map.Entry)) return false;
 
+            @SuppressWarnings("rawtypes")
             Map.Entry e = (Map.Entry) o;
 
             Position position = select(e.getKey());
@@ -352,7 +367,6 @@ public class CaseInsensitiveMap<V> extends AbstractMap<String, V> implements Ser
         return size;
     }
 
-    @SuppressWarnings("unchecked")
     @Override
     public V put(String key, V value)
     {
@@ -379,7 +393,6 @@ public class CaseInsensitiveMap<V> extends AbstractMap<String, V> implements Ser
         return select(key).remove();
     }
 
-    @SuppressWarnings("unchecked")
     @Override
     public Set<Map.Entry<String, V>> entrySet()
     {
@@ -388,6 +401,48 @@ public class CaseInsensitiveMap<V> extends AbstractMap<String, V> implements Ser
         return entrySet;
     }
 
+    @Override
+    public Set<String> keySet() {
+
+        AbstractSet<String> set = new AbstractSet<String>() {
+
+          @Override
+          public Iterator<String> iterator() {
+
+            final Iterator<java.util.Map.Entry<String, V>> entrySetIterator = entrySet().iterator();
+
+            return new Iterator<String>() {
+              @Override
+              public boolean hasNext() {
+                return entrySetIterator.hasNext();
+              }
+              @Override
+              public String next() {
+                String nextKey = entrySetIterator.next().getKey();
+                return nextKey;
+              }
+
+              @Override
+              public void remove() {
+                throw new UnsupportedOperationException("Modifications to the key set are not allowed.");
+              }
+            };
+          }
+
+          @Override
+          public boolean contains(Object o) {
+            return containsKey(o);
+          }
+
+          @Override
+          public int size() {
+            return size;
+          }
+        };
+
+        return Collections.unmodifiableSet(set);
+    }
+
     private Position select(Object key)
     {
         if (key == null || key instanceof String)
@@ -416,7 +471,7 @@ public class CaseInsensitiveMap<V> extends AbstractMap<String, V> implements Ser
         {
             cursor = (low + high) >> 1;
 
-            CIMEntry e = entries[cursor];
+            CIMEntry<V> e = entries[cursor];
 
             if (e.hashCode < hashCode)
             {

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/0a199345/tapestry-ioc/src/test/groovy/ioc/specs/CaseInsensitiveMapSpec.groovy
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/test/groovy/ioc/specs/CaseInsensitiveMapSpec.groovy b/tapestry-ioc/src/test/groovy/ioc/specs/CaseInsensitiveMapSpec.groovy
index c4e43f0..4813003 100644
--- a/tapestry-ioc/src/test/groovy/ioc/specs/CaseInsensitiveMapSpec.groovy
+++ b/tapestry-ioc/src/test/groovy/ioc/specs/CaseInsensitiveMapSpec.groovy
@@ -1,6 +1,8 @@
 package ioc.specs
 
 import org.apache.tapestry5.ioc.util.CaseInsensitiveMap
+
+import spock.lang.Issue;
 import spock.lang.Specification
 
 class CaseInsensitiveMapSpec extends Specification {
@@ -300,4 +302,25 @@ class CaseInsensitiveMapSpec extends Specification {
 
     copy == map
   }
+  
+  @Issue('https://issues.apache.org/jira/browse/TAP5-2452')
+  def "Modifications to key set are not allowed"(){
+    setup:
+    def map = new CaseInsensitiveMap<String>()
+    map.put('1', '1')
+    map.put('2', '2')
+    map.put('3', '3')
+    def keysToRetain = ['3', '4', '5']
+    expect:
+    map.keySet().size() == 3
+    map.keySet() == ['1', '2', '3'] as Set
+    when:
+    map.keySet().retainAll(keysToRetain)
+    then:
+    thrown(UnsupportedOperationException)
+    when:
+    map.keySet().remove("Zaphod")
+    then:
+    thrown(UnsupportedOperationException)
+  }
 }