diff --git a/org.springframework.core/src/main/java/org/springframework/core/CollectionFactory.java b/org.springframework.core/src/main/java/org/springframework/core/CollectionFactory.java index 1574b3563cb..a2055c2edf2 100644 --- a/org.springframework.core/src/main/java/org/springframework/core/CollectionFactory.java +++ b/org.springframework.core/src/main/java/org/springframework/core/CollectionFactory.java @@ -36,12 +36,7 @@ import java.util.TreeSet; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArraySet; -import org.apache.commons.collections.map.CaseInsensitiveMap; -import org.apache.commons.collections.map.ListOrderedMap; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import org.springframework.util.ClassUtils; +import org.springframework.util.LinkedCaseInsensitiveMap; /** * Factory for collections, being aware of Commons Collection 3.x's extended @@ -58,13 +53,6 @@ import org.springframework.util.ClassUtils; */ public abstract class CollectionFactory { - private static final Log logger = LogFactory.getLog(CollectionFactory.class); - - /** Whether the Commons Collections 3.x library is present on the classpath */ - private static final boolean commonsCollections3Available = - ClassUtils.isPresent("org.apache.commons.collections.map.CaseInsensitiveMap", - CollectionFactory.class.getClassLoader()); - private static final Set approximableCollectionTypes = new HashSet(10); private static final Set approximableMapTypes = new HashSet(6); @@ -129,23 +117,15 @@ public abstract class CollectionFactory { } /** - * Create a linked case-insensitive Map if possible: if Commons Collections - * 3.x is available, a CaseInsensitiveMap with ListOrderedMap decorator will - * be created. Else, a JDK {@link java.util.LinkedHashMap} will be used. + * Create a linked case-insensitive Map if possible: This implementation + * always returns a {@link org.springframework.util.LinkedCaseInsensitiveMap}. * @param initialCapacity the initial capacity of the Map * @return the new Map instance - * @see org.apache.commons.collections.map.CaseInsensitiveMap - * @see org.apache.commons.collections.map.ListOrderedMap + * @deprecated as of Spring 3.0, for usage on JDK 1.5 or higher */ - public static Map createLinkedCaseInsensitiveMapIfPossible(int initialCapacity) { - if (commonsCollections3Available) { - logger.trace("Creating [org.apache.commons.collections.map.ListOrderedMap/CaseInsensitiveMap]"); - return CommonsCollectionFactory.createListOrderedCaseInsensitiveMap(initialCapacity); - } - else { - logger.debug("Falling back to [java.util.LinkedHashMap] for linked case-insensitive map"); - return new LinkedHashMap(initialCapacity); - } + @Deprecated + public static Map createLinkedCaseInsensitiveMapIfPossible(int initialCapacity) { + return new LinkedCaseInsensitiveMap(initialCapacity); } /** @@ -157,8 +137,8 @@ public abstract class CollectionFactory { * @deprecated as of Spring 2.5, for usage on JDK 1.4 or higher */ @Deprecated - public static Map createIdentityMapIfPossible(int initialCapacity) { - return new IdentityHashMap(initialCapacity); + public static Map createIdentityMapIfPossible(int initialCapacity) { + return new IdentityHashMap(initialCapacity); } /** @@ -170,8 +150,8 @@ public abstract class CollectionFactory { * @deprecated as of Spring 3.0, for usage on JDK 1.5 or higher */ @Deprecated - public static Map createConcurrentMapIfPossible(int initialCapacity) { - return new ConcurrentHashMap(initialCapacity); + public static Map createConcurrentMapIfPossible(int initialCapacity) { + return new ConcurrentHashMap(initialCapacity); } /** @@ -183,8 +163,8 @@ public abstract class CollectionFactory { * @deprecated as of Spring 3.0, for usage on JDK 1.5 or higher */ @Deprecated - public static ConcurrentMap createConcurrentMap(int initialCapacity) { - return new JdkConcurrentHashMap(initialCapacity); + public static ConcurrentMap createConcurrentMap(int initialCapacity) { + return new JdkConcurrentHashMap(initialCapacity); } /** @@ -246,26 +226,12 @@ public abstract class CollectionFactory { * @see java.util.LinkedHashMap */ @SuppressWarnings("unchecked") - public static Map createApproximateMap(Object map, int initialCapacity) { + public static Map createApproximateMap(Object map, int initialCapacity) { if (map instanceof SortedMap) { - return new TreeMap(((SortedMap) map).comparator()); + return new TreeMap(((SortedMap) map).comparator()); } else { - return new LinkedHashMap(initialCapacity); - } - } - - - /** - * Actual creation of Commons Collections. - * In separate inner class to avoid runtime dependency on Commons Collections 3.x. - */ - private static abstract class CommonsCollectionFactory { - - @SuppressWarnings("unchecked") - private static Map createListOrderedCaseInsensitiveMap(int initialCapacity) { - // Commons Collections does not support initial capacity of 0. - return ListOrderedMap.decorate(new CaseInsensitiveMap(initialCapacity == 0 ? 1 : initialCapacity)); + return new LinkedHashMap(initialCapacity); } } @@ -274,7 +240,7 @@ public abstract class CollectionFactory { * ConcurrentMap adapter for the JDK ConcurrentHashMap class. */ @Deprecated - private static class JdkConcurrentHashMap extends ConcurrentHashMap implements ConcurrentMap { + private static class JdkConcurrentHashMap extends ConcurrentHashMap implements ConcurrentMap { private JdkConcurrentHashMap(int initialCapacity) { super(initialCapacity); diff --git a/org.springframework.core/src/main/java/org/springframework/core/ConcurrentMap.java b/org.springframework.core/src/main/java/org/springframework/core/ConcurrentMap.java index 8bcaa5b9734..64597193c97 100644 --- a/org.springframework.core/src/main/java/org/springframework/core/ConcurrentMap.java +++ b/org.springframework.core/src/main/java/org/springframework/core/ConcurrentMap.java @@ -33,14 +33,14 @@ import java.util.Map; * is available on Java 5+ anyway */ @Deprecated -public interface ConcurrentMap extends Map { +public interface ConcurrentMap extends Map { - V putIfAbsent(K key, V value); + Object putIfAbsent(Object key, Object value); boolean remove(Object key, Object value); - boolean replace(K key, V oldValue, V newValue); + boolean replace(Object key, Object oldValue, Object newValue); - V replace(K key, V value); + Object replace(Object key, Object value); } diff --git a/org.springframework.core/src/main/java/org/springframework/util/LinkedCaseInsensitiveMap.java b/org.springframework.core/src/main/java/org/springframework/util/LinkedCaseInsensitiveMap.java new file mode 100644 index 00000000000..8ab19d42384 --- /dev/null +++ b/org.springframework.core/src/main/java/org/springframework/util/LinkedCaseInsensitiveMap.java @@ -0,0 +1,139 @@ +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.util; + +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.Locale; +import java.util.Map; + +/** + * {@link LinkedHashMap} variant that stores String keys in a case-insensitive + * manner, for example for key-based access in a results table. + * + *

Preserves the original order as well as the original casing of keys, + * while allowing for contains, get and remove calls with any case of key. + * + *

Does not support null keys. + * + * @author Juergen Hoeller + * @since 3.0 + */ +public class LinkedCaseInsensitiveMap extends LinkedHashMap { + + private final Map caseInsensitiveKeys; + + private final Locale locale; + + + /** + * Create a new LinkedCaseInsensitiveMap for the default Locale. + * @see java.lang.String#toLowerCase() + */ + public LinkedCaseInsensitiveMap() { + this(null); + } + + /** + * Create a new LinkedCaseInsensitiveMap that stores lower-case keys + * according to the given Locale. + * @param locale the Locale to use for lower-case conversion + * @see java.lang.String#toLowerCase(java.util.Locale) + */ + public LinkedCaseInsensitiveMap(Locale locale) { + super(); + this.caseInsensitiveKeys = new HashMap(); + this.locale = (locale != null ? locale : Locale.getDefault()); + } + + /** + * Create a new LinkedCaseInsensitiveMap that wraps a {@link LinkedHashMap} + * with the given initial capacity and stores lower-case keys according + * to the default Locale. + * @param initialCapacity the initial capacity + * @see java.lang.String#toLowerCase() + */ + public LinkedCaseInsensitiveMap(int initialCapacity) { + this(initialCapacity, null); + } + + /** + * Create a new LinkedCaseInsensitiveMap that wraps a {@link LinkedHashMap} + * with the given initial capacity and stores lower-case keys according + * to the given Locale. + * @param initialCapacity the initial capacity + * @param locale the Locale to use for lower-case conversion + * @see java.lang.String#toLowerCase(java.util.Locale) + */ + public LinkedCaseInsensitiveMap(int initialCapacity, Locale locale) { + super(initialCapacity); + this.caseInsensitiveKeys = new HashMap(initialCapacity); + this.locale = (locale != null ? locale : Locale.getDefault()); + } + + + @Override + public V put(String key, V value) { + this.caseInsensitiveKeys.put(convertKey(key), key); + return super.put(key, value); + } + + @Override + public boolean containsKey(Object key) { + return (key instanceof String && this.caseInsensitiveKeys.containsKey(convertKey((String) key))); + } + + @Override + public V get(Object key) { + if (key instanceof String) { + return super.get(this.caseInsensitiveKeys.get(convertKey((String) key))); + } + else { + return null; + } + } + + @Override + public V remove(Object key) { + if (key instanceof String ) { + return super.remove(this.caseInsensitiveKeys.remove(convertKey((String) key))); + } + else { + return null; + } + } + + @Override + public void clear() { + this.caseInsensitiveKeys.clear(); + super.clear(); + } + + + /** + * Convert the given key to a case-insensitive key. + *

The default implementation converts the key + * to lower-case according to this Map's Locale. + * @param key the user-specified key + * @return the key to use for storing + * @see java.lang.String#toLowerCase(java.util.Locale) + */ + protected String convertKey(String key) { + return key.toLowerCase(this.locale); + } + +} diff --git a/org.springframework.core/src/main/java/org/springframework/util/LinkedMultiValueMap.java b/org.springframework.core/src/main/java/org/springframework/util/LinkedMultiValueMap.java index f22286c2aff..ed1a82436c1 100644 --- a/org.springframework.core/src/main/java/org/springframework/util/LinkedMultiValueMap.java +++ b/org.springframework.core/src/main/java/org/springframework/util/LinkedMultiValueMap.java @@ -24,11 +24,12 @@ import java.util.Map; import java.util.Set; /** - * Simple implementation of {@link MultiValueMap} that wraps a plain {@code Map} - * (by default a {@link LinkedHashMap}, storing multiple values in a {@link LinkedList}. + * Simple implementation of {@link MultiValueMap} that wraps a {@link LinkedHashMap}, + * storing multiple values in a {@link LinkedList}. * *

This Map implementation is generally not thread-safe. It is primarily designed * for data structures exposed from request objects, for use in a single thread only. + * * @author Arjen Poutsma * @author Juergen Hoeller * @since 3.0 @@ -37,15 +38,17 @@ public class LinkedMultiValueMap implements MultiValueMap { private final Map> targetMap; + /** - * Create a new SimpleMultiValueMap that wraps a newly created {@link LinkedHashMap}. + * Create a new LinkedMultiValueMap that wraps a {@link LinkedHashMap}. */ public LinkedMultiValueMap() { this.targetMap = new LinkedHashMap>(); } /** - * Create a new SimpleMultiValueMap that wraps a newly created {@link LinkedHashMap} with the given initial capacity. + * Create a new LinkedMultiValueMap that wraps a {@link LinkedHashMap} + * with the given initial capacity. * @param initialCapacity the initial capacity */ public LinkedMultiValueMap(int initialCapacity) { @@ -53,17 +56,15 @@ public class LinkedMultiValueMap implements MultiValueMap { } /** - * Create a new SimpleMultiValueMap that wraps the given target Map. - *

Note: The given Map will be used as active underlying Map. - * Any changes in the underlying map will be reflected in the - * MultiValueMap object, and vice versa. - * @param targetMap the target Map to wrap + * Copy constructor: Create a new LinkedMultiValueMap with the same mappings + * as the specified Map. + * @param otherMap the Map whose mappings are to be placed in this Map */ - public LinkedMultiValueMap(Map> targetMap) { - Assert.notNull(targetMap, "'targetMap' must not be null"); - this.targetMap = targetMap; + public LinkedMultiValueMap(Map> otherMap) { + this.targetMap = new LinkedHashMap>(otherMap); } + // MultiValueMap implementation public void add(K key, V value) { @@ -86,6 +87,7 @@ public class LinkedMultiValueMap implements MultiValueMap { this.targetMap.put(key, values); } + // Map implementation public int size() { @@ -136,6 +138,7 @@ public class LinkedMultiValueMap implements MultiValueMap { return this.targetMap.entrySet(); } + @Override public boolean equals(Object obj) { return this.targetMap.equals(obj); diff --git a/org.springframework.jdbc/src/main/java/org/springframework/jdbc/core/ColumnMapRowMapper.java b/org.springframework.jdbc/src/main/java/org/springframework/jdbc/core/ColumnMapRowMapper.java index 1fa92032a85..3fa01e271aa 100644 --- a/org.springframework.jdbc/src/main/java/org/springframework/jdbc/core/ColumnMapRowMapper.java +++ b/org.springframework.jdbc/src/main/java/org/springframework/jdbc/core/ColumnMapRowMapper.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2007 the original author or authors. + * Copyright 2002-2009 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,8 +21,8 @@ import java.sql.ResultSetMetaData; import java.sql.SQLException; import java.util.Map; -import org.springframework.core.CollectionFactory; import org.springframework.jdbc.support.JdbcUtils; +import org.springframework.util.LinkedCaseInsensitiveMap; /** * {@link RowMapper} implementation that creates a java.util.Map @@ -61,16 +61,15 @@ public class ColumnMapRowMapper implements RowMapper> { /** * Create a Map instance to be used as column map. - *

By default, a linked case-insensitive Map will be created if possible, - * else a plain HashMap (see Spring's CollectionFactory). + *

By default, a linked case-insensitive Map will be created. * @param columnCount the column count, to be used as initial * capacity for the Map * @return the new Map instance - * @see org.springframework.core.CollectionFactory#createLinkedCaseInsensitiveMapIfPossible + * @see org.springframework.util.LinkedCaseInsensitiveMap */ @SuppressWarnings("unchecked") protected Map createColumnMap(int columnCount) { - return CollectionFactory.createLinkedCaseInsensitiveMapIfPossible(columnCount); + return new LinkedCaseInsensitiveMap(columnCount); } /** diff --git a/org.springframework.jdbc/src/main/java/org/springframework/jdbc/core/JdbcTemplate.java b/org.springframework.jdbc/src/main/java/org/springframework/jdbc/core/JdbcTemplate.java index c2affa0d269..869f5409419 100644 --- a/org.springframework.jdbc/src/main/java/org/springframework/jdbc/core/JdbcTemplate.java +++ b/org.springframework.jdbc/src/main/java/org/springframework/jdbc/core/JdbcTemplate.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2008 the original author or authors. + * Copyright 2002-2009 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -35,7 +35,6 @@ import java.util.List; import java.util.Map; import javax.sql.DataSource; -import org.springframework.core.CollectionFactory; import org.springframework.dao.DataAccessException; import org.springframework.dao.InvalidDataAccessApiUsageException; import org.springframework.dao.support.DataAccessUtils; @@ -48,6 +47,7 @@ import org.springframework.jdbc.support.KeyHolder; import org.springframework.jdbc.support.nativejdbc.NativeJdbcExtractor; import org.springframework.jdbc.support.rowset.SqlRowSet; import org.springframework.util.Assert; +import org.springframework.util.LinkedCaseInsensitiveMap; /** * This is the central class in the JDBC core package. @@ -1161,16 +1161,14 @@ public class JdbcTemplate extends JdbcAccessor implements JdbcOperations { /** * Create a Map instance to be used as results map. - *

If "isResultsMapCaseInsensitive" has been set to true, a linked case-insensitive Map - * will be created if possible, else a plain HashMap (see Spring's CollectionFactory). + *

If "isResultsMapCaseInsensitive" has been set to true, + * a linked case-insensitive Map will be created. * @return the results Map instance * @see #setResultsMapCaseInsensitive - * @see org.springframework.core.CollectionFactory#createLinkedCaseInsensitiveMapIfPossible */ - @SuppressWarnings("unchecked") protected Map createResultsMap() { if (isResultsMapCaseInsensitive()) { - return CollectionFactory.createLinkedCaseInsensitiveMapIfPossible(16); + return new LinkedCaseInsensitiveMap(); } else { return new LinkedHashMap(); diff --git a/org.springframework.jdbc/src/test/java/org/springframework/jdbc/core/JdbcTemplateTests.java b/org.springframework.jdbc/src/test/java/org/springframework/jdbc/core/JdbcTemplateTests.java index 2014c9daf5b..1dbc083de6d 100644 --- a/org.springframework.jdbc/src/test/java/org/springframework/jdbc/core/JdbcTemplateTests.java +++ b/org.springframework.jdbc/src/test/java/org/springframework/jdbc/core/JdbcTemplateTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2008 the original author or authors. + * Copyright 2002-2009 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -29,11 +29,10 @@ import java.util.ArrayList; import java.util.LinkedList; import java.util.List; import java.util.Map; - import javax.sql.DataSource; -import org.easymock.MockControl; import org.apache.commons.logging.LogFactory; +import org.easymock.MockControl; import org.springframework.dao.DataAccessException; import org.springframework.dao.InvalidDataAccessApiUsageException; @@ -49,6 +48,7 @@ import org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator; import org.springframework.jdbc.support.SQLStateSQLExceptionTranslator; import org.springframework.jdbc.support.nativejdbc.NativeJdbcExtractor; import org.springframework.jdbc.support.nativejdbc.NativeJdbcExtractorAdapter; +import org.springframework.util.LinkedCaseInsensitiveMap; /** * Mock object based tests for JdbcTemplate. @@ -1954,8 +1954,7 @@ public class JdbcTemplateTests extends AbstractJdbcTests { JdbcTemplate template = new JdbcTemplate(mockDataSource); try { template.call(new CallableStatementCreator() { - public CallableStatement createCallableStatement(Connection conn) - throws SQLException { + public CallableStatement createCallableStatement(Connection conn) throws SQLException { return conn.prepareCall("my query"); } }, params); @@ -2005,13 +2004,11 @@ public class JdbcTemplateTests extends AbstractJdbcTests { params.add(new SqlOutParameter("a", 12)); Map out = template.call(new CallableStatementCreator() { - public CallableStatement createCallableStatement(Connection conn) - throws SQLException { + public CallableStatement createCallableStatement(Connection conn) throws SQLException { return conn.prepareCall("my query"); } }, params); - assertTrue("this should have been an Apache Commons Collections class", - out.getClass().getName().startsWith("org.apache.commons.collections.map")); + assertTrue("this should have been a LinkedCaseInsensitiveMap", out instanceof LinkedCaseInsensitiveMap); assertNotNull("we should have gotten the result with upper case", out.get("A")); assertNotNull("we should have gotten the result with lower case", out.get("a")); diff --git a/org.springframework.test/src/main/java/org/springframework/mock/web/MockHttpServletRequest.java b/org.springframework.test/src/main/java/org/springframework/mock/web/MockHttpServletRequest.java index b7c0a1174ba..85dd8742f25 100644 --- a/org.springframework.test/src/main/java/org/springframework/mock/web/MockHttpServletRequest.java +++ b/org.springframework.test/src/main/java/org/springframework/mock/web/MockHttpServletRequest.java @@ -42,6 +42,7 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; import org.springframework.util.Assert; +import org.springframework.util.LinkedCaseInsensitiveMap; /** * Mock implementation of the {@link javax.servlet.http.HttpServletRequest} @@ -142,10 +143,7 @@ public class MockHttpServletRequest implements HttpServletRequest { private Cookie[] cookies; - /** - * The key is the lowercase header name; the value is a {@link HeaderValueHolder} object. - */ - private final Map headers = new LinkedHashMap(); + private final Map headers = new LinkedCaseInsensitiveMap(); private String method; diff --git a/org.springframework.test/src/main/java/org/springframework/mock/web/MockHttpServletResponse.java b/org.springframework.test/src/main/java/org/springframework/mock/web/MockHttpServletResponse.java index d941c466952..6256bbe5163 100644 --- a/org.springframework.test/src/main/java/org/springframework/mock/web/MockHttpServletResponse.java +++ b/org.springframework.test/src/main/java/org/springframework/mock/web/MockHttpServletResponse.java @@ -25,7 +25,6 @@ import java.io.UnsupportedEncodingException; import java.io.Writer; import java.util.ArrayList; import java.util.Collections; -import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; @@ -35,6 +34,7 @@ import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletResponse; import org.springframework.util.Assert; +import org.springframework.util.LinkedCaseInsensitiveMap; import org.springframework.web.util.WebUtils; /** @@ -88,10 +88,7 @@ public class MockHttpServletResponse implements HttpServletResponse { private final List cookies = new ArrayList(); - /** - * The key is the lowercase header name; the value is a {@link HeaderValueHolder} object. - */ - private final Map headers = new HashMap(); + private final Map headers = new LinkedCaseInsensitiveMap(); private int status = HttpServletResponse.SC_OK; diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/mock/web/MockHttpServletRequest.java b/org.springframework.web.servlet/src/test/java/org/springframework/mock/web/MockHttpServletRequest.java index 273c8cdc8e7..53cc174c091 100644 --- a/org.springframework.web.servlet/src/test/java/org/springframework/mock/web/MockHttpServletRequest.java +++ b/org.springframework.web.servlet/src/test/java/org/springframework/mock/web/MockHttpServletRequest.java @@ -42,6 +42,7 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; import org.springframework.util.Assert; +import org.springframework.util.LinkedCaseInsensitiveMap; /** * Mock implementation of the {@link javax.servlet.http.HttpServletRequest} @@ -142,10 +143,7 @@ public class MockHttpServletRequest implements HttpServletRequest { private Cookie[] cookies; - /** - * The key is the lowercase header name; the value is a {@link HeaderValueHolder} object. - */ - private final Map headers = new LinkedHashMap(); + private final Map headers = new LinkedCaseInsensitiveMap(); private String method; diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/mock/web/MockHttpServletResponse.java b/org.springframework.web.servlet/src/test/java/org/springframework/mock/web/MockHttpServletResponse.java index 13d6a510026..4bd0c51e761 100644 --- a/org.springframework.web.servlet/src/test/java/org/springframework/mock/web/MockHttpServletResponse.java +++ b/org.springframework.web.servlet/src/test/java/org/springframework/mock/web/MockHttpServletResponse.java @@ -25,7 +25,6 @@ import java.io.UnsupportedEncodingException; import java.io.Writer; import java.util.ArrayList; import java.util.Collections; -import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; @@ -35,6 +34,7 @@ import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletResponse; import org.springframework.util.Assert; +import org.springframework.util.LinkedCaseInsensitiveMap; import org.springframework.web.util.WebUtils; /** @@ -88,10 +88,7 @@ public class MockHttpServletResponse implements HttpServletResponse { private final List cookies = new ArrayList(); - /** - * The key is the lowercase header name; the value is a {@link HeaderValueHolder} object. - */ - private final Map headers = new HashMap(); + private final Map headers = new LinkedCaseInsensitiveMap(); private int status = HttpServletResponse.SC_OK; diff --git a/org.springframework.web/src/main/java/org/springframework/http/HttpHeaders.java b/org.springframework.web/src/main/java/org/springframework/http/HttpHeaders.java index bf7bc069b0f..c634540a8de 100644 --- a/org.springframework.web/src/main/java/org/springframework/http/HttpHeaders.java +++ b/org.springframework.web/src/main/java/org/springframework/http/HttpHeaders.java @@ -29,8 +29,8 @@ import java.util.Locale; import java.util.Map; import java.util.Set; -import org.springframework.core.CollectionFactory; import org.springframework.util.Assert; +import org.springframework.util.LinkedCaseInsensitiveMap; import org.springframework.util.MultiValueMap; import org.springframework.util.StringUtils; @@ -64,7 +64,7 @@ public class HttpHeaders implements MultiValueMap { private static String LOCATION = "Location"; - private final Map> headers = CollectionFactory.createLinkedCaseInsensitiveMapIfPossible(5); + private final Map> headers = new LinkedCaseInsensitiveMap>(8); /** @@ -303,6 +303,7 @@ public class HttpHeaders implements MultiValueMap { return this.headers.entrySet(); } + @Override public boolean equals(Object other) { if (this == other) { diff --git a/org.springframework.web/src/main/java/org/springframework/http/MediaType.java b/org.springframework.web/src/main/java/org/springframework/http/MediaType.java index 3a36d89b03d..98746dbe93d 100644 --- a/org.springframework.web/src/main/java/org/springframework/http/MediaType.java +++ b/org.springframework.web/src/main/java/org/springframework/http/MediaType.java @@ -26,9 +26,9 @@ import java.util.List; import java.util.Locale; import java.util.Map; -import org.springframework.core.CollectionFactory; import org.springframework.util.Assert; import org.springframework.util.CollectionUtils; +import org.springframework.util.LinkedCaseInsensitiveMap; import org.springframework.util.StringUtils; /** @@ -102,7 +102,7 @@ public class MediaType implements Comparable { this.type = type.toLowerCase(Locale.ENGLISH); this.subtype = subtype.toLowerCase(Locale.ENGLISH); if (!CollectionUtils.isEmpty(parameters)) { - this.parameters = CollectionFactory.createLinkedCaseInsensitiveMapIfPossible(parameters.size()); + this.parameters = new LinkedCaseInsensitiveMap(parameters.size()); this.parameters.putAll(parameters); } else { @@ -282,31 +282,29 @@ public class MediaType implements Comparable { Assert.hasLength(mediaType, "'mediaType' must not be empty"); String[] parts = StringUtils.tokenizeToStringArray(mediaType, ";"); - Map parameters; - if (parts.length <= 1) { - parameters = null; - } - else { - parameters = new LinkedHashMap(parts.length - 1); - } - for (int i = 1; i < parts.length; i++) { - String part = parts[i]; - int idx = part.indexOf('='); - if (idx != -1) { - String name = part.substring(0, idx); - String value = part.substring(idx + 1, part.length()); - parameters.put(name, value); - } - } String fullType = parts[0].trim(); - // java.net.HttpURLConnection returns a *; q=.2 Accept header if (WILDCARD_TYPE.equals(fullType)) { fullType = "*/*"; } - int idx = fullType.indexOf('/'); - String type = fullType.substring(0, idx); - String subtype = fullType.substring(idx + 1, fullType.length()); + int subIndex = fullType.indexOf('/'); + String type = fullType.substring(0, subIndex); + String subtype = fullType.substring(subIndex + 1, fullType.length()); + + Map parameters = null; + if (parts.length > 1) { + parameters = new LinkedHashMap(parts.length - 1); + for (int i = 1; i < parts.length; i++) { + String part = parts[i]; + int eqIndex = part.indexOf('='); + if (eqIndex != -1) { + String name = part.substring(0, eqIndex); + String value = part.substring(eqIndex + 1, part.length()); + parameters.put(name, value); + } + } + } + return new MediaType(type, subtype, parameters); } diff --git a/org.springframework.web/src/test/java/org/springframework/http/server/ServletHttpResponseTest.java b/org.springframework.web/src/test/java/org/springframework/http/server/ServletHttpResponseTests.java similarity index 98% rename from org.springframework.web/src/test/java/org/springframework/http/server/ServletHttpResponseTest.java rename to org.springframework.web/src/test/java/org/springframework/http/server/ServletHttpResponseTests.java index 7becb7f9246..01fc88775cb 100644 --- a/org.springframework.web/src/test/java/org/springframework/http/server/ServletHttpResponseTest.java +++ b/org.springframework.web/src/test/java/org/springframework/http/server/ServletHttpResponseTests.java @@ -30,7 +30,7 @@ import org.springframework.http.HttpStatus; /** * @author Arjen Poutsma */ -public class ServletHttpResponseTest { +public class ServletHttpResponseTests { private ServletServerHttpResponse response; diff --git a/org.springframework.web/src/test/java/org/springframework/mock/web/MockHttpServletRequest.java b/org.springframework.web/src/test/java/org/springframework/mock/web/MockHttpServletRequest.java index 273c8cdc8e7..53cc174c091 100644 --- a/org.springframework.web/src/test/java/org/springframework/mock/web/MockHttpServletRequest.java +++ b/org.springframework.web/src/test/java/org/springframework/mock/web/MockHttpServletRequest.java @@ -42,6 +42,7 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; import org.springframework.util.Assert; +import org.springframework.util.LinkedCaseInsensitiveMap; /** * Mock implementation of the {@link javax.servlet.http.HttpServletRequest} @@ -142,10 +143,7 @@ public class MockHttpServletRequest implements HttpServletRequest { private Cookie[] cookies; - /** - * The key is the lowercase header name; the value is a {@link HeaderValueHolder} object. - */ - private final Map headers = new LinkedHashMap(); + private final Map headers = new LinkedCaseInsensitiveMap(); private String method; diff --git a/org.springframework.web/src/test/java/org/springframework/mock/web/MockHttpServletResponse.java b/org.springframework.web/src/test/java/org/springframework/mock/web/MockHttpServletResponse.java index 13d6a510026..4bd0c51e761 100644 --- a/org.springframework.web/src/test/java/org/springframework/mock/web/MockHttpServletResponse.java +++ b/org.springframework.web/src/test/java/org/springframework/mock/web/MockHttpServletResponse.java @@ -25,7 +25,6 @@ import java.io.UnsupportedEncodingException; import java.io.Writer; import java.util.ArrayList; import java.util.Collections; -import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; @@ -35,6 +34,7 @@ import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletResponse; import org.springframework.util.Assert; +import org.springframework.util.LinkedCaseInsensitiveMap; import org.springframework.web.util.WebUtils; /** @@ -88,10 +88,7 @@ public class MockHttpServletResponse implements HttpServletResponse { private final List cookies = new ArrayList(); - /** - * The key is the lowercase header name; the value is a {@link HeaderValueHolder} object. - */ - private final Map headers = new HashMap(); + private final Map headers = new LinkedCaseInsensitiveMap(); private int status = HttpServletResponse.SC_OK;