, Ini
public void afterPropertiesSet() throws IOException, CacheException {
logger.info("Initializing EHCache CacheManager");
- if (this.shared) {
- // Shared CacheManager singleton at the VM level.
- if (this.configLocation != null) {
- this.cacheManager = CacheManager.create(this.configLocation.getInputStream());
+ if (this.configLocation != null) {
+ InputStream is = this.configLocation.getInputStream();
+ try {
+ this.cacheManager = (this.shared ? CacheManager.create(is) : new CacheManager(is));
}
- else {
- this.cacheManager = CacheManager.create();
+ finally {
+ is.close();
}
}
else {
- // Independent CacheManager instance (the default).
- if (this.configLocation != null) {
- this.cacheManager = new CacheManager(this.configLocation.getInputStream());
- }
- else {
- this.cacheManager = new CacheManager();
- }
+ this.cacheManager = (this.shared ? CacheManager.create() : new CacheManager());
}
if (this.cacheManagerName != null) {
this.cacheManager.setName(this.cacheManagerName);
diff --git a/org.springframework.context.support/src/main/java/org/springframework/scheduling/quartz/LocalTaskExecutorThreadPool.java b/org.springframework.context.support/src/main/java/org/springframework/scheduling/quartz/LocalTaskExecutorThreadPool.java
index 54f25a4d62..8738e21a51 100644
--- a/org.springframework.context.support/src/main/java/org/springframework/scheduling/quartz/LocalTaskExecutorThreadPool.java
+++ b/org.springframework.context.support/src/main/java/org/springframework/scheduling/quartz/LocalTaskExecutorThreadPool.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2009 the original author or authors.
+ * Copyright 2002-2011 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.
@@ -40,6 +40,13 @@ public class LocalTaskExecutorThreadPool implements ThreadPool {
private Executor taskExecutor;
+ public void setInstanceId(String schedInstId) {
+ }
+
+ public void setInstanceName(String schedName) {
+ }
+
+
public void initialize() throws SchedulerConfigException {
// Absolutely needs thread-bound TaskExecutor to initialize.
this.taskExecutor = SchedulerFactoryBean.getConfigTimeTaskExecutor();
diff --git a/org.springframework.context.support/src/main/java/org/springframework/scheduling/quartz/SchedulerAccessor.java b/org.springframework.context.support/src/main/java/org/springframework/scheduling/quartz/SchedulerAccessor.java
index e3473520fc..07ac232ea1 100644
--- a/org.springframework.context.support/src/main/java/org/springframework/scheduling/quartz/SchedulerAccessor.java
+++ b/org.springframework.context.support/src/main/java/org/springframework/scheduling/quartz/SchedulerAccessor.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2008 the original author or authors.
+ * Copyright 2002-2011 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.
@@ -16,6 +16,7 @@
package org.springframework.scheduling.quartz;
+import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
@@ -34,7 +35,6 @@ import org.quartz.SchedulerListener;
import org.quartz.Trigger;
import org.quartz.TriggerListener;
import org.quartz.spi.ClassLoadHelper;
-import org.quartz.xml.JobSchedulingDataProcessor;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.core.io.ResourceLoader;
@@ -240,9 +240,25 @@ public abstract class SchedulerAccessor implements ResourceLoaderAware {
if (this.jobSchedulingDataLocations != null) {
ClassLoadHelper clh = new ResourceLoaderClassLoadHelper(this.resourceLoader);
clh.initialize();
- JobSchedulingDataProcessor dataProcessor = new JobSchedulingDataProcessor(clh, true, true);
- for (String location : this.jobSchedulingDataLocations) {
- dataProcessor.processFileAndScheduleJobs(location, getScheduler(), this.overwriteExistingJobs);
+ try {
+ // Quartz 1.8 or higher?
+ Class dataProcessorClass = getClass().getClassLoader().loadClass("org.quartz.xml.XMLSchedulingDataProcessor");
+ logger.debug("Using Quartz 1.8 XMLSchedulingDataProcessor");
+ Object dataProcessor = dataProcessorClass.getConstructor(ClassLoadHelper.class).newInstance(clh);
+ Method processFileAndScheduleJobs = dataProcessorClass.getMethod("processFileAndScheduleJobs", String.class, Scheduler.class);
+ for (String location : this.jobSchedulingDataLocations) {
+ processFileAndScheduleJobs.invoke(dataProcessor, location, getScheduler());
+ }
+ }
+ catch (ClassNotFoundException ex) {
+ // Quartz 1.6
+ Class dataProcessorClass = getClass().getClassLoader().loadClass("org.quartz.xml.JobSchedulingDataProcessor");
+ logger.debug("Using Quartz 1.6 JobSchedulingDataProcessor");
+ Object dataProcessor = dataProcessorClass.getConstructor(ClassLoadHelper.class, boolean.class, boolean.class).newInstance(clh, true, true);
+ Method processFileAndScheduleJobs = dataProcessorClass.getMethod("processFileAndScheduleJobs", String.class, Scheduler.class, boolean.class);
+ for (String location : this.jobSchedulingDataLocations) {
+ processFileAndScheduleJobs.invoke(dataProcessor, location, getScheduler(), this.overwriteExistingJobs);
+ }
}
}
diff --git a/org.springframework.context.support/src/main/java/org/springframework/scheduling/quartz/SchedulerFactoryBean.java b/org.springframework.context.support/src/main/java/org/springframework/scheduling/quartz/SchedulerFactoryBean.java
index 24c42e341c..2abaab665d 100644
--- a/org.springframework.context.support/src/main/java/org/springframework/scheduling/quartz/SchedulerFactoryBean.java
+++ b/org.springframework.context.support/src/main/java/org/springframework/scheduling/quartz/SchedulerFactoryBean.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2010 the original author or authors.
+ * Copyright 2002-2011 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.
@@ -74,9 +74,9 @@ import org.springframework.util.CollectionUtils;
* automatically apply to Scheduler operations performed within those scopes.
* Alternatively, you may add transactional advice for the Scheduler itself.
*
- * Note: This version of Spring's SchedulerFactoryBean requires
- * Quartz 1.5.x or 1.6.x. The "jobSchedulingDataLocation" feature requires
- * Quartz 1.6.1 or higher (as of Spring 2.5.5).
+ *
Note: This version of Spring's SchedulerFactoryBean supports Quartz 1.x,
+ * more specifically Quartz 1.5 or higher. The "jobSchedulingDataLocation" feature
+ * requires Quartz 1.6.1 or higher (as of Spring 2.5.5).
*
* @author Juergen Hoeller
* @since 18.02.2004
diff --git a/org.springframework.context/src/main/java/org/springframework/remoting/support/RemoteExporter.java b/org.springframework.context/src/main/java/org/springframework/remoting/support/RemoteExporter.java
index c4e64e90d9..79c7bda8c3 100644
--- a/org.springframework.context/src/main/java/org/springframework/remoting/support/RemoteExporter.java
+++ b/org.springframework.context/src/main/java/org/springframework/remoting/support/RemoteExporter.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2008 the original author or authors.
+ * Copyright 2002-2011 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.
@@ -166,6 +166,7 @@ public abstract class RemoteExporter extends RemotingSupport {
}
}
proxyFactory.setTarget(getService());
+ proxyFactory.setOpaque(true);
return proxyFactory.getProxy(getBeanClassLoader());
}
diff --git a/org.springframework.context/src/main/java/org/springframework/validation/AbstractBindingResult.java b/org.springframework.context/src/main/java/org/springframework/validation/AbstractBindingResult.java
index d6e061c597..20ddaf7969 100644
--- a/org.springframework.context/src/main/java/org/springframework/validation/AbstractBindingResult.java
+++ b/org.springframework.context/src/main/java/org/springframework/validation/AbstractBindingResult.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2010 the original author or authors.
+ * Copyright 2002-2011 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.
@@ -19,8 +19,8 @@ package org.springframework.validation;
import java.beans.PropertyEditor;
import java.io.Serializable;
import java.util.Collections;
-import java.util.HashMap;
import java.util.HashSet;
+import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
@@ -28,6 +28,7 @@ import java.util.Set;
import org.springframework.beans.PropertyEditorRegistry;
import org.springframework.util.Assert;
+import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
/**
@@ -130,7 +131,7 @@ public abstract class AbstractBindingResult extends AbstractErrors implements Bi
}
public String[] resolveMessageCodes(String errorCode, String field) {
- Class fieldType = getFieldType(field);
+ Class> fieldType = getFieldType(field);
return getMessageCodesResolver().resolveMessageCodes(
errorCode, getObjectName(), fixedField(field), fieldType);
}
@@ -236,7 +237,7 @@ public abstract class AbstractBindingResult extends AbstractErrors implements Bi
* @see #getActualFieldValue
*/
@Override
- public Class getFieldType(String field) {
+ public Class> getFieldType(String field) {
Object value = getActualFieldValue(fixedField(field));
if (value != null) {
return value.getClass();
@@ -268,11 +269,11 @@ public abstract class AbstractBindingResult extends AbstractErrors implements Bi
* @see org.springframework.web.servlet.mvc.SimpleFormController
*/
public Map getModel() {
- Map model = new HashMap(2);
- // Errors instance, even if no errors.
- model.put(MODEL_KEY_PREFIX + getObjectName(), this);
+ Map model = new LinkedHashMap(2);
// Mapping from name to target object.
model.put(getObjectName(), getTarget());
+ // Errors instance, even if no errors.
+ model.put(MODEL_KEY_PREFIX + getObjectName(), this);
return model;
}
@@ -285,10 +286,10 @@ public abstract class AbstractBindingResult extends AbstractErrors implements Bi
* {@link #getPropertyEditorRegistry() PropertyEditorRegistry}'s
* editor lookup facility, if available.
*/
- public PropertyEditor findEditor(String field, Class valueType) {
+ public PropertyEditor findEditor(String field, Class> valueType) {
PropertyEditorRegistry editorRegistry = getPropertyEditorRegistry();
if (editorRegistry != null) {
- Class valueTypeToUse = valueType;
+ Class> valueTypeToUse = valueType;
if (valueTypeToUse == null) {
valueTypeToUse = getFieldType(field);
}
@@ -337,13 +338,13 @@ public abstract class AbstractBindingResult extends AbstractErrors implements Bi
}
BindingResult otherResult = (BindingResult) other;
return (getObjectName().equals(otherResult.getObjectName()) &&
- getTarget().equals(otherResult.getTarget()) &&
+ ObjectUtils.nullSafeEquals(getTarget(), otherResult.getTarget()) &&
getAllErrors().equals(otherResult.getAllErrors()));
}
@Override
public int hashCode() {
- return getObjectName().hashCode() * 29 + getTarget().hashCode();
+ return getObjectName().hashCode();
}
diff --git a/org.springframework.context/src/main/java/org/springframework/validation/BindingResult.java b/org.springframework.context/src/main/java/org/springframework/validation/BindingResult.java
index c681562165..848c3e0292 100644
--- a/org.springframework.context/src/main/java/org/springframework/validation/BindingResult.java
+++ b/org.springframework.context/src/main/java/org/springframework/validation/BindingResult.java
@@ -94,7 +94,7 @@ public interface BindingResult extends Errors {
* is given but should be specified in any case for consistency checking)
* @return the registered editor, or null if none
*/
- PropertyEditor findEditor(String field, Class valueType);
+ PropertyEditor findEditor(String field, Class> valueType);
/**
* Return the underlying PropertyEditorRegistry.
diff --git a/org.springframework.core/src/main/java/org/springframework/core/AttributeAccessorSupport.java b/org.springframework.core/src/main/java/org/springframework/core/AttributeAccessorSupport.java
index a2424de60b..bd598c2f8a 100644
--- a/org.springframework.core/src/main/java/org/springframework/core/AttributeAccessorSupport.java
+++ b/org.springframework.core/src/main/java/org/springframework/core/AttributeAccessorSupport.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2008 the original author or authors.
+ * Copyright 2002-2011 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,7 @@ import org.springframework.util.Assert;
public abstract class AttributeAccessorSupport implements AttributeAccessor, Serializable {
/** Map with String keys and Object values */
- private final Map attributes = new LinkedHashMap();
+ private final Map attributes = new LinkedHashMap(0);
public void setAttribute(String name, Object value) {
diff --git a/org.springframework.core/src/main/java/org/springframework/util/StringUtils.java b/org.springframework.core/src/main/java/org/springframework/util/StringUtils.java
index f2505f21c4..e86ab49793 100644
--- a/org.springframework.core/src/main/java/org/springframework/util/StringUtils.java
+++ b/org.springframework.core/src/main/java/org/springframework/util/StringUtils.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2010 the original author or authors.
+ * Copyright 2002-2011 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.
@@ -529,8 +529,15 @@ public abstract class StringUtils {
if (path == null) {
return null;
}
- int sepIndex = path.lastIndexOf(EXTENSION_SEPARATOR);
- return (sepIndex != -1 ? path.substring(sepIndex + 1) : null);
+ int extIndex = path.lastIndexOf(EXTENSION_SEPARATOR);
+ if (extIndex == -1) {
+ return null;
+ }
+ int folderIndex = path.lastIndexOf(FOLDER_SEPARATOR);
+ if (folderIndex > extIndex) {
+ return null;
+ }
+ return path.substring(extIndex + 1);
}
/**
@@ -544,8 +551,15 @@ public abstract class StringUtils {
if (path == null) {
return null;
}
- int sepIndex = path.lastIndexOf(EXTENSION_SEPARATOR);
- return (sepIndex != -1 ? path.substring(0, sepIndex) : path);
+ int extIndex = path.lastIndexOf(EXTENSION_SEPARATOR);
+ if (extIndex == -1) {
+ return path;
+ }
+ int folderIndex = path.lastIndexOf(FOLDER_SEPARATOR);
+ if (folderIndex > extIndex) {
+ return path;
+ }
+ return path.substring(0, extIndex);
}
/**
@@ -643,7 +657,7 @@ public abstract class StringUtils {
}
/**
- * Parse the given localeString into a {@link Locale}.
+ * Parse the given localeString value into a {@link Locale}.
* This is the inverse operation of {@link Locale#toString Locale's toString}.
* @param localeString the locale string, following Locale's
* toString() format ("en", "en_UK", etc);
@@ -651,6 +665,13 @@ public abstract class StringUtils {
* @return a corresponding Locale instance
*/
public static Locale parseLocaleString(String localeString) {
+ for (int i = 0; i < localeString.length(); i++) {
+ char ch = localeString.charAt(i);
+ if (ch != '_' && ch != ' ' && !Character.isLetterOrDigit(ch)) {
+ throw new IllegalArgumentException(
+ "Locale value \"" + localeString + "\" contains invalid characters");
+ }
+ }
String[] parts = tokenizeToStringArray(localeString, "_ ", false, false);
String language = (parts.length > 0 ? parts[0] : "");
String country = (parts.length > 1 ? parts[1] : "");
@@ -726,7 +747,7 @@ public abstract class StringUtils {
* array elements only included once.
*
The order of elements in the original arrays is preserved
* (with the exception of overlapping elements, which are only
- * included on their first occurence).
+ * included on their first occurrence).
* @param array1 the first array (can be null)
* @param array2 the second array (can be null)
* @return the new array (null if both given arrays were null)
@@ -1043,12 +1064,12 @@ public abstract class StringUtils {
* @param suffix the String to end each element with
* @return the delimited String
*/
- public static String collectionToDelimitedString(Collection coll, String delim, String prefix, String suffix) {
+ public static String collectionToDelimitedString(Collection> coll, String delim, String prefix, String suffix) {
if (CollectionUtils.isEmpty(coll)) {
return "";
}
StringBuilder sb = new StringBuilder();
- Iterator it = coll.iterator();
+ Iterator> it = coll.iterator();
while (it.hasNext()) {
sb.append(prefix).append(it.next()).append(suffix);
if (it.hasNext()) {
@@ -1065,7 +1086,7 @@ public abstract class StringUtils {
* @param delim the delimiter to use (probably a ",")
* @return the delimited String
*/
- public static String collectionToDelimitedString(Collection coll, String delim) {
+ public static String collectionToDelimitedString(Collection> coll, String delim) {
return collectionToDelimitedString(coll, delim, "", "");
}
@@ -1075,7 +1096,7 @@ public abstract class StringUtils {
* @param coll the Collection to display
* @return the delimited String
*/
- public static String collectionToCommaDelimitedString(Collection coll) {
+ public static String collectionToCommaDelimitedString(Collection> coll) {
return collectionToDelimitedString(coll, ",");
}
diff --git a/org.springframework.orm/src/main/java/org/springframework/orm/jpa/EntityManagerFactoryUtils.java b/org.springframework.orm/src/main/java/org/springframework/orm/jpa/EntityManagerFactoryUtils.java
index ecaca5890f..8e52e83683 100644
--- a/org.springframework.orm/src/main/java/org/springframework/orm/jpa/EntityManagerFactoryUtils.java
+++ b/org.springframework.orm/src/main/java/org/springframework/orm/jpa/EntityManagerFactoryUtils.java
@@ -257,7 +257,7 @@ public abstract class EntityManagerFactoryUtils {
public static void applyTransactionTimeout(Query query, EntityManagerFactory emf) {
EntityManagerHolder emHolder = (EntityManagerHolder) TransactionSynchronizationManager.getResource(emf);
if (emHolder != null && emHolder.hasTimeout()) {
- int timeoutValue = emHolder.getTimeToLiveInSeconds();
+ int timeoutValue = (int) emHolder.getTimeToLiveInMillis();
query.setHint("javax.persistence.lock.timeout", timeoutValue);
query.setHint("javax.persistence.query.timeout", timeoutValue);
}
diff --git a/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/bind/PortletRequestDataBinder.java b/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/bind/PortletRequestDataBinder.java
index 26c3a5b55f..a63b894d17 100644
--- a/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/bind/PortletRequestDataBinder.java
+++ b/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/bind/PortletRequestDataBinder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2010 the original author or authors.
+ * Copyright 2002-2011 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.
@@ -22,6 +22,7 @@ import org.springframework.beans.MutablePropertyValues;
import org.springframework.validation.BindException;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.multipart.MultipartRequest;
+import org.springframework.web.portlet.util.PortletUtils;
/**
* Special {@link org.springframework.validation.DataBinder} to perform data binding
@@ -105,8 +106,8 @@ public class PortletRequestDataBinder extends WebDataBinder {
*/
public void bind(PortletRequest request) {
MutablePropertyValues mpvs = new PortletRequestParameterPropertyValues(request);
- if (request instanceof MultipartRequest) {
- MultipartRequest multipartRequest = (MultipartRequest) request;
+ MultipartRequest multipartRequest = PortletUtils.getNativeRequest(request, MultipartRequest.class);
+ if (multipartRequest != null) {
bindMultipart(multipartRequest.getMultiFileMap(), mpvs);
}
doBind(mpvs);
diff --git a/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/context/PortletWebRequest.java b/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/context/PortletWebRequest.java
index 9be71736c4..52907bba74 100644
--- a/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/context/PortletWebRequest.java
+++ b/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/context/PortletWebRequest.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2010 the original author or authors.
+ * Copyright 2002-2011 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.
@@ -23,13 +23,12 @@ import java.util.Map;
import javax.portlet.PortletRequest;
import javax.portlet.PortletResponse;
import javax.portlet.PortletSession;
-import javax.portlet.filter.PortletRequestWrapper;
-import javax.portlet.filter.PortletResponseWrapper;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.NativeWebRequest;
+import org.springframework.web.portlet.util.PortletUtils;
/**
* {@link org.springframework.web.context.request.WebRequest} adapter
@@ -79,40 +78,12 @@ public class PortletWebRequest extends PortletRequestAttributes implements Nativ
@SuppressWarnings("unchecked")
public T getNativeRequest(Class requiredType) {
- if (requiredType != null) {
- PortletRequest request = getRequest();
- while (request != null) {
- if (requiredType.isInstance(request)) {
- return (T) request;
- }
- else if (request instanceof PortletRequestWrapper) {
- request = ((PortletRequestWrapper) request).getRequest();
- }
- else {
- request = null;
- }
- }
- }
- return null;
+ return PortletUtils.getNativeRequest(getRequest(), requiredType);
}
@SuppressWarnings("unchecked")
public T getNativeResponse(Class requiredType) {
- if (requiredType != null) {
- PortletResponse response = getResponse();
- while (response != null) {
- if (requiredType.isInstance(response)) {
- return (T) response;
- }
- else if (response instanceof PortletResponseWrapper) {
- response = ((PortletResponseWrapper) response).getResponse();
- }
- else {
- response = null;
- }
- }
- }
- return null;
+ return PortletUtils.getNativeResponse(getResponse(), requiredType);
}
diff --git a/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/util/PortletUtils.java b/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/util/PortletUtils.java
index cd9040b1b5..968229c753 100644
--- a/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/util/PortletUtils.java
+++ b/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/util/PortletUtils.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2009 the original author or authors.
+ * Copyright 2002-2011 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.
@@ -32,6 +32,9 @@ import javax.portlet.PortletRequestDispatcher;
import javax.portlet.PortletSession;
import javax.portlet.ResourceRequest;
import javax.portlet.ResourceResponse;
+import javax.portlet.PortletResponse;
+import javax.portlet.filter.PortletRequestWrapper;
+import javax.portlet.filter.PortletResponseWrapper;
import javax.servlet.http.Cookie;
import org.springframework.util.Assert;
@@ -276,6 +279,48 @@ public abstract class PortletUtils {
}
+ /**
+ * Return an appropriate request object of the specified type, if available,
+ * unwrapping the given request as far as necessary.
+ * @param request the portlet request to introspect
+ * @param requiredType the desired type of request object
+ * @return the matching request object, or null if none
+ * of that type is available
+ */
+ @SuppressWarnings("unchecked")
+ public static T getNativeRequest(PortletRequest request, Class requiredType) {
+ if (requiredType != null) {
+ if (requiredType.isInstance(request)) {
+ return (T) request;
+ }
+ else if (request instanceof PortletRequestWrapper) {
+ return getNativeRequest(((PortletRequestWrapper) request).getRequest(), requiredType);
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Return an appropriate response object of the specified type, if available,
+ * unwrapping the given response as far as necessary.
+ * @param response the portlet response to introspect
+ * @param requiredType the desired type of response object
+ * @return the matching response object, or null if none
+ * of that type is available
+ */
+ @SuppressWarnings("unchecked")
+ public static T getNativeResponse(PortletResponse response, Class requiredType) {
+ if (requiredType != null) {
+ if (requiredType.isInstance(response)) {
+ return (T) response;
+ }
+ else if (response instanceof PortletResponseWrapper) {
+ return getNativeResponse(((PortletResponseWrapper) response).getResponse(), requiredType);
+ }
+ }
+ return null;
+ }
+
/**
* Expose the given Map as request attributes, using the keys as attribute names
* and the values as corresponding attribute values. Keys must be Strings.
@@ -293,7 +338,7 @@ public abstract class PortletUtils {
/**
* Retrieve the first cookie with the given name. Note that multiple
* cookies can have the same name but different paths or domains.
- * @param request current servlet request
+ * @param request current portlet request
* @param name cookie name
* @return the first cookie with the given name, or null if none is found
*/
diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/i18n/LocaleChangeInterceptor.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/i18n/LocaleChangeInterceptor.java
index d6b9a90e71..a39919c3e8 100644
--- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/i18n/LocaleChangeInterceptor.java
+++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/i18n/LocaleChangeInterceptor.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2008 the original author or authors.
+ * Copyright 2002-2011 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.
@@ -16,13 +16,11 @@
package org.springframework.web.servlet.i18n;
-import java.util.Locale;
-
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
-import org.springframework.beans.propertyeditors.LocaleEditor;
+import org.springframework.util.StringUtils;
import org.springframework.web.servlet.LocaleResolver;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import org.springframework.web.servlet.support.RequestContextUtils;
@@ -72,9 +70,7 @@ public class LocaleChangeInterceptor extends HandlerInterceptorAdapter {
if (localeResolver == null) {
throw new IllegalStateException("No LocaleResolver found: not in a DispatcherServlet request?");
}
- LocaleEditor localeEditor = new LocaleEditor();
- localeEditor.setAsText(newLocale);
- localeResolver.setLocale(request, response, (Locale) localeEditor.getValue());
+ localeResolver.setLocale(request, response, StringUtils.parseLocaleString(newLocale));
}
// Proceed in any case.
return true;
diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/resource/ResourceHttpRequestHandler.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/resource/ResourceHttpRequestHandler.java
index 07fe31be8c..8540de9c2e 100644
--- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/resource/ResourceHttpRequestHandler.java
+++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/resource/ResourceHttpRequestHandler.java
@@ -35,9 +35,9 @@ import org.springframework.web.servlet.support.WebContentGenerator;
/**
* {@link HttpRequestHandler} that serves static resources optimized for superior browser performance
* (according to the guidelines of Page Speed, YSlow, etc.) by allowing for flexible cache settings
- * ({@link #setCacheSeconds "cacheSeconds" property}, last-modified support).
+ * ({@linkplain #setCacheSeconds "cacheSeconds" property}, last-modified support).
*
- * The {@link #setLocations "locations" property takes a list of Spring {@link Resource} locations
+ *
The {@linkplain #setLocations "locations" property} takes a list of Spring {@link Resource} locations
* from which static resources are allowed to be served by this handler. For a given request, the
* list of locations will be consulted in order for the presence of the requested resource, and the
* first found match will be written to the response, with {@code Expires} and {@code Cache-Control}
@@ -54,7 +54,7 @@ import org.springframework.web.servlet.support.WebContentGenerator;
* using Spring EL. See the reference manual for further examples of this approach.
*
*
Rather than being directly configured as a bean, this handler will typically be configured
- * through use of the <mvc:resources/> XML configuration element.
+ * through use of the {@code } XML configuration element.
*
* @author Keith Donald
* @author Jeremy Grelle
@@ -121,11 +121,11 @@ public class ResourceHttpRequestHandler extends WebContentGenerator implements H
}
// header phase
- setHeaders(response, resource, mediaType);
if (new ServletWebRequest(request, response).checkNotModified(resource.lastModified())) {
logger.debug("Resource not modified - returning 304");
return;
}
+ setHeaders(response, resource, mediaType);
// content phase
if (METHOD_HEAD.equals(request.getMethod())) {
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 c4ba00c4cf..800ededbaf 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
@@ -1,11 +1,11 @@
/*
- * Copyright 2002-2010 the original author or authors.
+ * Copyright 2002-2011 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
+ * 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,
@@ -177,11 +177,15 @@ public class HttpHeaders implements MultiValueMap {
String[] tokens = value.split(",\\s*");
for (String token : tokens) {
int paramIdx = token.indexOf(';');
+ String charsetName;
if (paramIdx == -1) {
- result.add(Charset.forName(token));
+ charsetName = token;
}
else {
- result.add(Charset.forName(token.substring(0, paramIdx)));
+ charsetName = token.substring(0, paramIdx);
+ }
+ if (!charsetName.equals("*")) {
+ result.add(Charset.forName(charsetName));
}
}
}
@@ -310,7 +314,11 @@ public class HttpHeaders implements MultiValueMap {
* @param eTag the new entity tag
*/
public void setETag(String eTag) {
- set(ETAG, quote(eTag));
+ if (eTag != null) {
+ Assert.isTrue(eTag.startsWith("\"") || eTag.startsWith("W/"), "Invalid eTag, does not start with W/ or \"");
+ Assert.isTrue(eTag.endsWith("\""), "Invalid eTag, does not end with \"");
+ }
+ set(ETAG, eTag);
}
/**
@@ -318,7 +326,7 @@ public class HttpHeaders implements MultiValueMap {
* @return the entity tag
*/
public String getETag() {
- return unquote(getFirst(ETAG));
+ return getFirst(ETAG);
}
/**
@@ -362,7 +370,7 @@ public class HttpHeaders implements MultiValueMap {
* @param ifNoneMatch the new value of the header
*/
public void setIfNoneMatch(String ifNoneMatch) {
- set(IF_NONE_MATCH, quote(ifNoneMatch));
+ set(IF_NONE_MATCH, ifNoneMatch);
}
/**
@@ -373,7 +381,7 @@ public class HttpHeaders implements MultiValueMap {
StringBuilder builder = new StringBuilder();
for (Iterator iterator = ifNoneMatchList.iterator(); iterator.hasNext();) {
String ifNoneMatch = iterator.next();
- builder.append(quote(ifNoneMatch));
+ builder.append(ifNoneMatch);
if (iterator.hasNext()) {
builder.append(", ");
}
@@ -392,7 +400,7 @@ public class HttpHeaders implements MultiValueMap {
if (value != null) {
String[] tokens = value.split(",\\s*");
for (String token : tokens) {
- result.add(unquote(token));
+ result.add(token);
}
}
return result;
@@ -452,31 +460,6 @@ public class HttpHeaders implements MultiValueMap {
// Utility methods
- private String quote(String s) {
- Assert.notNull(s);
- if (!s.startsWith("\"")) {
- s = "\"" + s;
- }
- if (!s.endsWith("\"")) {
- s = s + "\"";
- }
- return s;
- }
-
- private String unquote(String s) {
- if (s == null) {
- return null;
- }
- if (s.startsWith("\"")) {
- s = s.substring(1);
- }
- if (s.endsWith("\"")) {
- s = s.substring(0, s.length() - 1);
- }
- return s;
- }
-
-
private long getFirstDate(String headerName) {
String headerValue = getFirst(headerName);
if (headerValue == null) {
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 185e9e6cab..fa7886216a 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
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2010 the original author or authors.
+ * Copyright 2002-2011 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.
@@ -187,7 +187,7 @@ public class MediaType implements Comparable {
/**
- * Create a new {@link MediaType} for the given primary type.
+ * Create a new {@code MediaType} for the given primary type.
* The {@linkplain #getSubtype() subtype} is set to *, parameters empty.
* @param type the primary type
* @throws IllegalArgumentException if any of the parameters contain illegal characters
@@ -197,7 +197,7 @@ public class MediaType implements Comparable {
}
/**
- * Create a new {@link MediaType} for the given primary type and subtype.
+ * Create a new {@code MediaType} for the given primary type and subtype.
* The parameters are empty.
* @param type the primary type
* @param subtype the subtype
@@ -208,18 +208,18 @@ public class MediaType implements Comparable {
}
/**
- * Create a new {@link MediaType} for the given type, subtype, and character set.
+ * Create a new {@code MediaType} for the given type, subtype, and character set.
* @param type the primary type
* @param subtype the subtype
* @param charSet the character set
* @throws IllegalArgumentException if any of the parameters contain illegal characters
*/
public MediaType(String type, String subtype, Charset charSet) {
- this(type, subtype, Collections.singletonMap(PARAM_CHARSET, charSet.toString()));
+ this(type, subtype, Collections.singletonMap(PARAM_CHARSET, charSet.name()));
}
/**
- * Create a new {@link MediaType} for the given type, subtype, and quality value.
+ * Create a new {@code MediaType} for the given type, subtype, and quality value.
*
* @param type the primary type
* @param subtype the subtype
@@ -231,7 +231,7 @@ public class MediaType implements Comparable {
}
/**
- * Copy-constructor that copies the type and subtype of the given {@link MediaType},
+ * Copy-constructor that copies the type and subtype of the given {@code MediaType},
* and allows for different parameter.
* @param other the other media type
* @param parameters the parameters, may be null
@@ -242,7 +242,7 @@ public class MediaType implements Comparable {
}
/**
- * Create a new {@link MediaType} for the given type, subtype, and parameters.
+ * Create a new {@code MediaType} for the given type, subtype, and parameters.
* @param type the primary type
* @param subtype the subtype
* @param parameters the parameters, may be null
@@ -322,7 +322,7 @@ public class MediaType implements Comparable {
}
/**
- * Indicate whether the {@linkplain #getType() type} is the wildcard character * or not.
+ * Indicates whether the {@linkplain #getType() type} is the wildcard character * or not.
*/
public boolean isWildcardType() {
return WILDCARD_TYPE.equals(type);
@@ -336,13 +336,22 @@ public class MediaType implements Comparable {
}
/**
- * Indicate whether the {@linkplain #getSubtype() subtype} is the wildcard character * or not.
+ * Indicates whether the {@linkplain #getSubtype() subtype} is the wildcard character * or not.
* @return whether the subtype is *
*/
public boolean isWildcardSubtype() {
return WILDCARD_TYPE.equals(subtype);
}
+ /**
+ * Indicates whether this media type is concrete, i.e. whether neither the type or subtype is a wildcard
+ * character *.
+ * @return whether this media type is concrete
+ */
+ public boolean isConcrete() {
+ return !isWildcardType() && !isWildcardSubtype();
+ }
+
/**
* Return the character set, as indicated by a charset parameter, if any.
* @return the character set; or null if not available
@@ -372,9 +381,9 @@ public class MediaType implements Comparable {
}
/**
- * Indicate whether this {@link MediaType} includes the given media type.
- * For instance, {@code text/*} includes {@code text/plain}, {@code text/html}, and {@code application/*+xml}
- * includes {@code application/soap+xml}, etc. This method is non-symmetic.
+ * Indicate whether this {@code MediaType} includes the given media type.
+ *
For instance, {@code text/*} includes {@code text/plain} and {@code text/html}, and {@code application/*+xml}
+ * includes {@code application/soap+xml}, etc. This method is not symmetric.
* @param other the reference media type with which to compare
* @return true if this media type includes the given media type; false otherwise
*/
@@ -407,9 +416,9 @@ public class MediaType implements Comparable {
}
/**
- * Indicate whether this {@link MediaType} is compatible with the given media type.
+ * Indicate whether this {@code MediaType} is compatible with the given media type.
* For instance, {@code text/*} is compatible with {@code text/plain}, {@code text/html}, and vice versa.
- * In effect, this method is similar to {@link #includes(MediaType)}, except that it's symmetric.
+ * In effect, this method is similar to {@link #includes(MediaType)}, except that it is symmetric.
* @param other the reference media type with which to compare
* @return true if this media type is compatible with the given media type; false otherwise
*/
@@ -444,7 +453,7 @@ public class MediaType implements Comparable {
}
/**
- * Compares this {@link MediaType} to another alphabetically.
+ * Compares this {@code MediaType} to another alphabetically.
* @param other media type to compare to
* @see #sortBySpecificity(List)
*/
@@ -533,7 +542,7 @@ public class MediaType implements Comparable {
/**
- * Parse the given String value into a {@link MediaType} object,
+ * Parse the given String value into a {@code MediaType} object,
* with this method name following the 'valueOf' naming convention
* (as supported by {@link org.springframework.core.convert.ConversionService}.
* @see #parseMediaType(String)
@@ -543,7 +552,7 @@ public class MediaType implements Comparable {
}
/**
- * Parse the given String into a single {@link MediaType}.
+ * Parse the given String into a single {@code MediaType}.
* @param mediaType the string to parse
* @return the media type
* @throws IllegalArgumentException if the string cannot be parsed
@@ -586,7 +595,7 @@ public class MediaType implements Comparable {
/**
- * Parse the given, comma-seperated string into a list of {@link MediaType} objects.
+ * Parse the given, comma-separated string into a list of {@code MediaType} objects.
* This method can be used to parse an Accept or Content-Type header.
* @param mediaTypes the string to parse
* @return the list of media types
@@ -605,7 +614,7 @@ public class MediaType implements Comparable {
}
/**
- * Return a string representation of the given list of {@link MediaType} objects.
+ * Return a string representation of the given list of {@code MediaType} objects.
* This method can be used to for an {@code Accept} or {@code Content-Type} header.
* @param mediaTypes the string to parse
* @return the list of media types
@@ -624,7 +633,7 @@ public class MediaType implements Comparable {
}
/**
- * Sorts the given list of {@link MediaType} objects by specificity.
+ * Sorts the given list of {@code MediaType} objects by specificity.
* Given two media types:
*
* - if either media type has a {@linkplain #isWildcardType() wildcard type}, then the media type without the
@@ -657,7 +666,7 @@ public class MediaType implements Comparable {
}
/**
- * Sorts the given list of {@link MediaType} objects by quality value.
+ * Sorts the given list of {@code MediaType} objects by quality value.
*
Given two media types:
*
* - if the two media types have different {@linkplain #getQualityValue() quality value}, then the media type
@@ -684,7 +693,10 @@ public class MediaType implements Comparable {
}
- static final Comparator SPECIFICITY_COMPARATOR = new Comparator() {
+ /**
+ * Comparator used by {@link #sortBySpecificity(List)}.
+ */
+ public static final Comparator SPECIFICITY_COMPARATOR = new Comparator() {
public int compare(MediaType mediaType1, MediaType mediaType2) {
if (mediaType1.isWildcardType() && !mediaType2.isWildcardType()) { // */* < audio/*
@@ -724,7 +736,10 @@ public class MediaType implements Comparable {
};
- static final Comparator QUALITY_VALUE_COMPARATOR = new Comparator() {
+ /**
+ * Comparator used by {@link #sortByQualityValue(List)}.
+ */
+ public static final Comparator QUALITY_VALUE_COMPARATOR = new Comparator() {
public int compare(MediaType mediaType1, MediaType mediaType2) {
double quality1 = mediaType1.getQualityValue();
diff --git a/org.springframework.web/src/main/java/org/springframework/http/converter/FormHttpMessageConverter.java b/org.springframework.web/src/main/java/org/springframework/http/converter/FormHttpMessageConverter.java
index 7bcb4f2a75..609489af7f 100644
--- a/org.springframework.web/src/main/java/org/springframework/http/converter/FormHttpMessageConverter.java
+++ b/org.springframework.web/src/main/java/org/springframework/http/converter/FormHttpMessageConverter.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2010 the original author or authors.
+ * Copyright 2002-2011 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.
@@ -19,13 +19,11 @@ package org.springframework.http.converter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
-import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
@@ -43,38 +41,28 @@ import org.springframework.util.FileCopyUtils;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.util.StringUtils;
-import org.springframework.web.util.WebUtils;
/**
- * Implementation of {@link HttpMessageConverter} that can handle form data, including multipart form data
- * (i.e. file uploads).
+ * Implementation of {@link HttpMessageConverter} that can handle form data, including multipart form data (i.e. file
+ * uploads).
*
*
This converter can write the {@code application/x-www-form-urlencoded} and {@code multipart/form-data} media
* types, and read the {@code application/x-www-form-urlencoded}) media type (but not {@code multipart/form-data}).
*
- *
In other words, this converter can read and write 'normal' HTML forms (as
- * {@link MultiValueMap MultiValueMap<String, String>}), and it can write multipart form (as
- * {@link MultiValueMap MultiValueMap<String, Object>}. When writing multipart, this converter uses other
- * {@link HttpMessageConverter HttpMessageConverters} to write the respective MIME parts. By default, basic converters
- * are registered (supporting {@code Strings} and {@code Resources}, for instance); these can be overridden by setting
- * the {@link #setPartConverters(java.util.List) partConverters} property.
+ *
In other words, this converter can read and write 'normal' HTML forms (as {@link MultiValueMap
+ * MultiValueMap<String, String>}), and it can write multipart form (as {@link MultiValueMap
+ * MultiValueMap<String, Object>}. When writing multipart, this converter uses other {@link HttpMessageConverter
+ * HttpMessageConverters} to write the respective MIME parts. By default, basic converters are registered (supporting
+ * {@code Strings} and {@code Resources}, for instance); these can be overridden by setting the {@link
+ * #setPartConverters(java.util.List) partConverters} property.
*
- *
For example, the following snippet shows how to submit an HTML form:
- *
- * RestTemplate template = new RestTemplate(); // FormHttpMessageConverter is configured by default
- * MultiValueMap<String, String> form = new LinkedMultiValueMap<String, String>();
- * form.add("field 1", "value 1");
- * form.add("field 2", "value 2");
- * form.add("field 2", "value 3");
- * template.postForLocation("http://example.com/myForm", form);
- *
- * The following snippet shows how to do a file upload:
- *
- * MultiValueMap<String, Object> parts = new LinkedMultiValueMap<String, Object>();
- * parts.add("field 1", "value 1");
- * parts.add("file", new ClassPathResource("myFile.jpg"));
- * template.postForLocation("http://example.com/myFileUpload", parts);
- *
+ * For example, the following snippet shows how to submit an HTML form:
RestTemplate template =
+ * new RestTemplate(); // FormHttpMessageConverter is configured by default MultiValueMap<String, String> form =
+ * new LinkedMultiValueMap<String, String>(); form.add("field 1", "value 1"); form.add("field 2", "value 2");
+ * form.add("field 2", "value 3"); template.postForLocation("http://example.com/myForm", form); The following
+ * snippet shows how to do a file upload:
MultiValueMap<String, Object> parts = new
+ * LinkedMultiValueMap<String, Object>(); parts.add("field 1", "value 1"); parts.add("file", new
+ * ClassPathResource("myFile.jpg")); template.postForLocation("http://example.com/myFileUpload", parts);
*
* Some methods in this class were inspired by {@link org.apache.commons.httpclient.methods.multipart.MultipartRequestEntity}.
*
@@ -88,16 +76,21 @@ public class FormHttpMessageConverter implements HttpMessageConverter supportedMediaTypes = new ArrayList();
private List> partConverters = new ArrayList>();
public FormHttpMessageConverter() {
+ this.supportedMediaTypes.add(MediaType.APPLICATION_FORM_URLENCODED);
+ this.supportedMediaTypes.add(MediaType.MULTIPART_FORM_DATA);
+
this.partConverters.add(new ByteArrayHttpMessageConverter());
StringHttpMessageConverter stringHttpMessageConverter = new StringHttpMessageConverter();
stringHttpMessageConverter.setWriteAcceptCharset(false);
@@ -106,14 +99,6 @@ public class FormHttpMessageConverter implements HttpMessageConverter partConverter) {
- Assert.notNull(partConverter, "'partConverter' must not be NULL");
- this.partConverters.add(partConverter);
- }
-
/**
* Set the message body converters to use. These converters are used to convert objects to MIME parts.
*/
@@ -122,6 +107,14 @@ public class FormHttpMessageConverter implements HttpMessageConverter partConverter) {
+ Assert.notNull(partConverter, "'partConverter' must not be NULL");
+ this.partConverters.add(partConverter);
+ }
+
/**
* Sets the character set used for writing form data.
*/
@@ -129,34 +122,47 @@ public class FormHttpMessageConverter implements HttpMessageConverter clazz, MediaType mediaType) {
if (!MultiValueMap.class.isAssignableFrom(clazz)) {
return false;
}
- if (mediaType != null) {
- return MediaType.APPLICATION_FORM_URLENCODED.includes(mediaType);
- }
- else {
+ if (mediaType == null) {
return true;
}
+ for (MediaType supportedMediaType : getSupportedMediaTypes()) {
+ // we can't read multipart
+ if (!supportedMediaType.equals(MediaType.MULTIPART_FORM_DATA) &&
+ supportedMediaType.includes(mediaType)) {
+ return true;
+ }
+ }
+ return false;
}
public boolean canWrite(Class> clazz, MediaType mediaType) {
if (!MultiValueMap.class.isAssignableFrom(clazz)) {
return false;
}
- if (mediaType != null) {
- return mediaType.isCompatibleWith(MediaType.APPLICATION_FORM_URLENCODED) ||
- mediaType.isCompatibleWith(MediaType.MULTIPART_FORM_DATA);
- }
- else {
+ if (mediaType == null || MediaType.ALL.equals(mediaType)) {
return true;
}
+ for (MediaType supportedMediaType : getSupportedMediaTypes()) {
+ if (supportedMediaType.isCompatibleWith(mediaType)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Set the list of {@link MediaType} objects supported by this converter.
+ */
+ public void setSupportedMediaTypes(List supportedMediaTypes) {
+ this.supportedMediaTypes = supportedMediaTypes;
}
public List getSupportedMediaTypes() {
- return Arrays.asList(MediaType.APPLICATION_FORM_URLENCODED, MediaType.MULTIPART_FORM_DATA);
+ return Collections.unmodifiableList(this.supportedMediaTypes);
}
public MultiValueMap read(Class extends MultiValueMap> clazz,
@@ -188,7 +194,7 @@ public class FormHttpMessageConverter implements HttpMessageConverter map, MediaType contentType, HttpOutputMessage outputMessage)
throws IOException, HttpMessageNotWritableException {
if (!isMultipart(map, contentType)) {
- writeForm((MultiValueMap) map, outputMessage);
+ writeForm((MultiValueMap) map, contentType, outputMessage);
}
else {
writeMultipart((MultiValueMap) map, outputMessage);
@@ -209,8 +215,17 @@ public class FormHttpMessageConverter implements HttpMessageConverter form, HttpOutputMessage outputMessage) throws IOException {
- outputMessage.getHeaders().setContentType(MediaType.APPLICATION_FORM_URLENCODED);
+ private void writeForm(MultiValueMap form, MediaType contentType, HttpOutputMessage outputMessage)
+ throws IOException {
+ Charset charset;
+ if (contentType != null) {
+ outputMessage.getHeaders().setContentType(contentType);
+ charset = contentType.getCharSet() != null ? contentType.getCharSet() : this.charset;
+ }
+ else {
+ outputMessage.getHeaders().setContentType(MediaType.APPLICATION_FORM_URLENCODED);
+ charset = this.charset;
+ }
StringBuilder builder = new StringBuilder();
for (Iterator nameIterator = form.keySet().iterator(); nameIterator.hasNext();) {
String name = nameIterator.next();
@@ -229,10 +244,13 @@ public class FormHttpMessageConverter implements HttpMessageConverter parts, HttpOutputMessage outputMessage) throws IOException {
+ private void writeMultipart(MultiValueMap parts, HttpOutputMessage outputMessage)
+ throws IOException {
byte[] boundary = generateMultipartBoundary();
Map parameters = Collections.singletonMap("boundary", new String(boundary, "US-ASCII"));
@@ -310,7 +328,8 @@ public class FormHttpMessageConverter implements HttpMessageConverterDefault implementation returns a random boundary. Can be overridden in subclasses.
+ * The default implementation returns a random boundary.
+ * Can be overridden in subclasses.
*/
protected byte[] generateMultipartBoundary() {
byte[] boundary = new byte[rnd.nextInt(11) + 30];
@@ -321,9 +340,10 @@ public class FormHttpMessageConverter implements HttpMessageConverterDefault implementation returns {@link Resource#getFilename()} if the part is a {@code Resource}, and
- * {@code null} in other cases. Can be overridden in subclasses.
+ * Return the filename of the given multipart part. This value will be used for the
+ * {@code Content-Disposition} header.
+ * The default implementation returns {@link Resource#getFilename()} if the part is a
+ * {@code Resource}, and {@code null} in other cases. Can be overridden in subclasses.
* @param part the part to determine the file name for
* @return the filename, or {@code null} if not known
*/
diff --git a/org.springframework.web/src/main/java/org/springframework/http/server/ServletServerHttpRequest.java b/org.springframework.web/src/main/java/org/springframework/http/server/ServletServerHttpRequest.java
index a3c6788594..28339d375e 100644
--- a/org.springframework.web/src/main/java/org/springframework/http/server/ServletServerHttpRequest.java
+++ b/org.springframework.web/src/main/java/org/springframework/http/server/ServletServerHttpRequest.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2010 the original author or authors.
+ * Copyright 2002-2011 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.
@@ -16,11 +16,20 @@
package org.springframework.http.server;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
import java.net.URI;
import java.net.URISyntaxException;
+import java.net.URLEncoder;
+import java.util.Arrays;
import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.springframework.http.HttpHeaders;
@@ -35,14 +44,22 @@ import org.springframework.util.Assert;
*/
public class ServletServerHttpRequest implements ServerHttpRequest {
+ private static final String FORM_CONTENT_TYPE = "application/x-www-form-urlencoded";
+
+ private static final String POST_METHOD = "POST";
+
+ private static final String PUT_METHOD = "PUT";
+
+ private static final String FORM_CHARSET = "UTF-8";
+
private final HttpServletRequest servletRequest;
private HttpHeaders headers;
/**
- * Construct a new instance of the ServletServerHttpRequest based on the given {@link HttpServletRequest}
- * @param servletRequest the HttpServletRequest
+ * Construct a new instance of the ServletServerHttpRequest based on the given {@link HttpServletRequest}.
+ * @param servletRequest the servlet request
*/
public ServletServerHttpRequest(HttpServletRequest servletRequest) {
Assert.notNull(servletRequest, "'servletRequest' must not be null");
@@ -50,15 +67,22 @@ public class ServletServerHttpRequest implements ServerHttpRequest {
}
+ /**
+ * Returns the {@code HttpServletRequest} this object is based on.
+ */
+ public HttpServletRequest getServletRequest() {
+ return this.servletRequest;
+ }
+
public HttpMethod getMethod() {
return HttpMethod.valueOf(this.servletRequest.getMethod());
}
public URI getURI() {
try {
- return new URI(servletRequest.getScheme(), null, servletRequest.getServerName(),
- servletRequest.getServerPort(), servletRequest.getRequestURI(),
- servletRequest.getQueryString(), null);
+ return new URI(this.servletRequest.getScheme(), null, this.servletRequest.getServerName(),
+ this.servletRequest.getServerPort(), this.servletRequest.getRequestURI(),
+ this.servletRequest.getQueryString(), null);
}
catch (URISyntaxException ex) {
throw new IllegalStateException("Could not get HttpServletRequest URI: " + ex.getMessage(), ex);
@@ -70,7 +94,8 @@ public class ServletServerHttpRequest implements ServerHttpRequest {
this.headers = new HttpHeaders();
for (Enumeration headerNames = this.servletRequest.getHeaderNames(); headerNames.hasMoreElements();) {
String headerName = (String) headerNames.nextElement();
- for (Enumeration headerValues = this.servletRequest.getHeaders(headerName); headerValues.hasMoreElements();) {
+ for (Enumeration headerValues = this.servletRequest.getHeaders(headerName);
+ headerValues.hasMoreElements();) {
String headerValue = (String) headerValues.nextElement();
this.headers.add(headerName, headerValue);
}
@@ -80,7 +105,45 @@ public class ServletServerHttpRequest implements ServerHttpRequest {
}
public InputStream getBody() throws IOException {
- return this.servletRequest.getInputStream();
+ if (isFormSubmittal(this.servletRequest)) {
+ return getFormBody(this.servletRequest);
+ }
+ else {
+ return this.servletRequest.getInputStream();
+ }
+ }
+
+ private boolean isFormSubmittal(HttpServletRequest request) {
+ return FORM_CONTENT_TYPE.equals(request.getContentType()) &&
+ (POST_METHOD.equalsIgnoreCase(request.getMethod()) || PUT_METHOD.equalsIgnoreCase(request.getMethod()));
+ }
+
+ private InputStream getFormBody(HttpServletRequest request) throws IOException {
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ Writer writer = new OutputStreamWriter(bos, FORM_CHARSET);
+
+ Map form = request.getParameterMap();
+ for (Iterator nameIterator = form.keySet().iterator(); nameIterator.hasNext();) {
+ String name = nameIterator.next();
+ List values = Arrays.asList(form.get(name));
+ for (Iterator valueIterator = values.iterator(); valueIterator.hasNext();) {
+ String value = valueIterator.next();
+ writer.write(URLEncoder.encode(name, FORM_CHARSET));
+ if (value != null) {
+ writer.write('=');
+ writer.write(URLEncoder.encode(value, FORM_CHARSET));
+ if (valueIterator.hasNext()) {
+ writer.write('&');
+ }
+ }
+ }
+ if (nameIterator.hasNext()) {
+ writer.append('&');
+ }
+ }
+ writer.flush();
+
+ return new ByteArrayInputStream(bos.toByteArray());
}
}
diff --git a/org.springframework.web/src/main/java/org/springframework/http/server/ServletServerHttpResponse.java b/org.springframework.web/src/main/java/org/springframework/http/server/ServletServerHttpResponse.java
index af7ab7e449..9752c4259d 100644
--- a/org.springframework.web/src/main/java/org/springframework/http/server/ServletServerHttpResponse.java
+++ b/org.springframework.web/src/main/java/org/springframework/http/server/ServletServerHttpResponse.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2010 the original author or authors.
+ * Copyright 2002-2011 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.
@@ -43,7 +43,7 @@ public class ServletServerHttpResponse implements ServerHttpResponse {
/**
* Construct a new instance of the ServletServerHttpResponse based on the given {@link HttpServletResponse}.
- * @param servletResponse the HTTP Servlet response
+ * @param servletResponse the servlet response
*/
public ServletServerHttpResponse(HttpServletResponse servletResponse) {
Assert.notNull(servletResponse, "'servletResponse' must not be null");
@@ -51,12 +51,19 @@ public class ServletServerHttpResponse implements ServerHttpResponse {
}
+ /**
+ * Return the {@code HttpServletResponse} this object is based on.
+ */
+ public HttpServletResponse getServletResponse() {
+ return this.servletResponse;
+ }
+
public void setStatusCode(HttpStatus status) {
this.servletResponse.setStatus(status.value());
}
public HttpHeaders getHeaders() {
- return headersWritten ? HttpHeaders.readOnlyHttpHeaders(headers) : this.headers;
+ return (this.headersWritten ? HttpHeaders.readOnlyHttpHeaders(this.headers) : this.headers);
}
public OutputStream getBody() throws IOException {
diff --git a/org.springframework.web/src/main/java/org/springframework/web/bind/ServletRequestDataBinder.java b/org.springframework.web/src/main/java/org/springframework/web/bind/ServletRequestDataBinder.java
index 2edc899cfa..f488024d9b 100644
--- a/org.springframework.web/src/main/java/org/springframework/web/bind/ServletRequestDataBinder.java
+++ b/org.springframework.web/src/main/java/org/springframework/web/bind/ServletRequestDataBinder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2010 the original author or authors.
+ * Copyright 2002-2011 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,6 +21,7 @@ import javax.servlet.ServletRequest;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.validation.BindException;
import org.springframework.web.multipart.MultipartRequest;
+import org.springframework.web.util.WebUtils;
/**
* Special {@link org.springframework.validation.DataBinder} to perform data binding
@@ -103,8 +104,8 @@ public class ServletRequestDataBinder extends WebDataBinder {
*/
public void bind(ServletRequest request) {
MutablePropertyValues mpvs = new ServletRequestParameterPropertyValues(request);
- if (request instanceof MultipartRequest) {
- MultipartRequest multipartRequest = (MultipartRequest) request;
+ MultipartRequest multipartRequest = WebUtils.getNativeRequest(request, MultipartRequest.class);
+ if (multipartRequest != null) {
bindMultipart(multipartRequest.getMultiFileMap(), mpvs);
}
doBind(mpvs);
diff --git a/org.springframework.web/src/main/java/org/springframework/web/context/request/ServletWebRequest.java b/org.springframework.web/src/main/java/org/springframework/web/context/request/ServletWebRequest.java
index b59909052b..d772877c74 100644
--- a/org.springframework.web/src/main/java/org/springframework/web/context/request/ServletWebRequest.java
+++ b/org.springframework.web/src/main/java/org/springframework/web/context/request/ServletWebRequest.java
@@ -1,11 +1,11 @@
/*
- * Copyright 2002-2010 the original author or authors.
+ * Copyright 2002-2011 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
+ * 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,
@@ -20,10 +20,6 @@ import java.security.Principal;
import java.util.Iterator;
import java.util.Locale;
import java.util.Map;
-import javax.servlet.ServletRequest;
-import javax.servlet.ServletRequestWrapper;
-import javax.servlet.ServletResponse;
-import javax.servlet.ServletResponseWrapper;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
@@ -31,6 +27,7 @@ import javax.servlet.http.HttpSession;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
+import org.springframework.web.util.WebUtils;
/**
* {@link WebRequest} adapter for an {@link javax.servlet.http.HttpServletRequest}.
@@ -40,10 +37,16 @@ import org.springframework.util.StringUtils;
*/
public class ServletWebRequest extends ServletRequestAttributes implements NativeWebRequest {
+ private static final String HEADER_ETAG = "ETag";
+
private static final String HEADER_IF_MODIFIED_SINCE = "If-Modified-Since";
+ private static final String HEADER_IF_NONE_MATCH = "If-None-Match";
+
private static final String HEADER_LAST_MODIFIED = "Last-Modified";
+ private static final String METHOD_GET = "GET";
+
private HttpServletResponse response;
@@ -86,40 +89,12 @@ public class ServletWebRequest extends ServletRequestAttributes implements Nativ
@SuppressWarnings("unchecked")
public T getNativeRequest(Class requiredType) {
- if (requiredType != null) {
- ServletRequest request = getRequest();
- while (request != null) {
- if (requiredType.isInstance(request)) {
- return (T) request;
- }
- else if (request instanceof ServletRequestWrapper) {
- request = ((ServletRequestWrapper) request).getRequest();
- }
- else {
- request = null;
- }
- }
- }
- return null;
+ return WebUtils.getNativeRequest(getRequest(), requiredType);
}
@SuppressWarnings("unchecked")
public T getNativeResponse(Class requiredType) {
- if (requiredType != null) {
- ServletResponse response = getResponse();
- while (response != null) {
- if (requiredType.isInstance(response)) {
- return (T) response;
- }
- else if (response instanceof ServletResponseWrapper) {
- response = ((ServletResponseWrapper) response).getResponse();
- }
- else {
- response = null;
- }
- }
- }
- return null;
+ return WebUtils.getNativeResponse(getResponse(), requiredType);
}
@@ -186,7 +161,7 @@ public class ServletWebRequest extends ServletRequestAttributes implements Nativ
long ifModifiedSince = getRequest().getDateHeader(HEADER_IF_MODIFIED_SINCE);
this.notModified = (ifModifiedSince >= (lastModifiedTimestamp / 1000 * 1000));
if (this.response != null) {
- if (this.notModified && "GET".equals(getRequest().getMethod())) {
+ if (this.notModified && METHOD_GET.equals(getRequest().getMethod())) {
this.response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
}
else {
diff --git a/org.springframework.web/src/main/java/org/springframework/web/filter/ShallowEtagHeaderFilter.java b/org.springframework.web/src/main/java/org/springframework/web/filter/ShallowEtagHeaderFilter.java
index 07269002c4..d214561959 100644
--- a/org.springframework.web/src/main/java/org/springframework/web/filter/ShallowEtagHeaderFilter.java
+++ b/org.springframework.web/src/main/java/org/springframework/web/filter/ShallowEtagHeaderFilter.java
@@ -69,7 +69,6 @@ public class ShallowEtagHeaderFilter extends OncePerRequestFilter {
if (logger.isTraceEnabled()) {
logger.trace("ETag [" + responseETag + "] equal to If-None-Match, sending 304");
}
- response.setContentLength(0);
response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
}
else {
@@ -89,8 +88,8 @@ public class ShallowEtagHeaderFilter extends OncePerRequestFilter {
}
private void copyBodyToResponse(byte[] body, HttpServletResponse response) throws IOException {
- response.setContentLength(body.length);
if (body.length > 0) {
+ response.setContentLength(body.length);
FileCopyUtils.copy(body, response.getOutputStream());
}
}
@@ -113,7 +112,7 @@ public class ShallowEtagHeaderFilter extends OncePerRequestFilter {
/**
* Generate the ETag header value from the given response body byte array.
* The default implementation generates an MD5 hash.
- * @param bytes the response bdoy as byte array
+ * @param bytes the response body as byte array
* @return the ETag header value
* @see org.springframework.util.DigestUtils
*/
@@ -168,6 +167,10 @@ public class ShallowEtagHeaderFilter extends OncePerRequestFilter {
this.statusCode = sc;
}
+ @Override
+ public void setContentLength(int len) {
+ }
+
@Override
public ServletOutputStream getOutputStream() {
return this.outputStream;
diff --git a/org.springframework.web/src/main/java/org/springframework/web/util/WebUtils.java b/org.springframework.web/src/main/java/org/springframework/web/util/WebUtils.java
index c11df93a05..8e19d70926 100644
--- a/org.springframework.web/src/main/java/org/springframework/web/util/WebUtils.java
+++ b/org.springframework.web/src/main/java/org/springframework/web/util/WebUtils.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2009 the original author or authors.
+ * Copyright 2002-2011 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.
@@ -23,6 +23,9 @@ import java.util.Map;
import java.util.TreeMap;
import javax.servlet.ServletContext;
import javax.servlet.ServletRequest;
+import javax.servlet.ServletRequestWrapper;
+import javax.servlet.ServletResponse;
+import javax.servlet.ServletResponseWrapper;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@@ -366,6 +369,48 @@ public abstract class WebUtils {
}
+ /**
+ * Return an appropriate request object of the specified type, if available,
+ * unwrapping the given request as far as necessary.
+ * @param request the servlet request to introspect
+ * @param requiredType the desired type of request object
+ * @return the matching request object, or null if none
+ * of that type is available
+ */
+ @SuppressWarnings("unchecked")
+ public static T getNativeRequest(ServletRequest request, Class requiredType) {
+ if (requiredType != null) {
+ if (requiredType.isInstance(request)) {
+ return (T) request;
+ }
+ else if (request instanceof ServletRequestWrapper) {
+ return getNativeRequest(((ServletRequestWrapper) request).getRequest(), requiredType);
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Return an appropriate response object of the specified type, if available,
+ * unwrapping the given response as far as necessary.
+ * @param response the servlet response to introspect
+ * @param requiredType the desired type of response object
+ * @return the matching response object, or null if none
+ * of that type is available
+ */
+ @SuppressWarnings("unchecked")
+ public static T getNativeResponse(ServletResponse response, Class requiredType) {
+ if (requiredType != null) {
+ if (requiredType.isInstance(response)) {
+ return (T) response;
+ }
+ else if (response instanceof ServletResponseWrapper) {
+ return getNativeResponse(((ServletResponseWrapper) response).getResponse(), requiredType);
+ }
+ }
+ return null;
+ }
+
/**
* Determine whether the given request is an include request,
* that is, not a top-level HTTP request coming in from the outside.
diff --git a/org.springframework.web/src/test/java/org/springframework/http/converter/FormHttpMessageConverterTests.java b/org.springframework.web/src/test/java/org/springframework/http/converter/FormHttpMessageConverterTests.java
index 75fbf892e3..83ffd70b42 100644
--- a/org.springframework.web/src/test/java/org/springframework/http/converter/FormHttpMessageConverterTests.java
+++ b/org.springframework.web/src/test/java/org/springframework/http/converter/FormHttpMessageConverterTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2010 the original author or authors.
+ * Copyright 2002-2011 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.
@@ -30,7 +30,6 @@ import org.apache.commons.fileupload.FileItemFactory;
import org.apache.commons.fileupload.FileUpload;
import org.apache.commons.fileupload.RequestContext;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
-import static org.junit.Assert.*;
import org.junit.Before;
import org.junit.Test;
@@ -45,6 +44,8 @@ import org.springframework.http.converter.xml.XmlAwareFormHttpMessageConverter;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
+import static org.junit.Assert.*;
+
/**
* @author Arjen Poutsma
*/
@@ -60,13 +61,13 @@ public class FormHttpMessageConverterTests {
@Test
public void canRead() {
assertTrue(converter.canRead(MultiValueMap.class, new MediaType("application", "x-www-form-urlencoded")));
- assertFalse(converter.canRead(MultiValueMap.class, new MediaType("multipart","form-data")));
+ assertFalse(converter.canRead(MultiValueMap.class, new MediaType("multipart", "form-data")));
}
@Test
public void canWrite() {
assertTrue(converter.canWrite(MultiValueMap.class, new MediaType("application", "x-www-form-urlencoded")));
- assertTrue(converter.canWrite(MultiValueMap.class, new MediaType("multipart","form-data")));
+ assertTrue(converter.canWrite(MultiValueMap.class, new MediaType("multipart", "form-data")));
assertTrue(converter.canWrite(MultiValueMap.class, MediaType.ALL));
}
@@ -77,7 +78,7 @@ public class FormHttpMessageConverterTests {
Charset iso88591 = Charset.forName("ISO-8859-1");
MockHttpInputMessage inputMessage = new MockHttpInputMessage(body.getBytes(iso88591));
inputMessage.getHeaders().setContentType(new MediaType("application", "x-www-form-urlencoded", iso88591));
- MultiValueMap result = (MultiValueMap) converter.read(null, inputMessage);
+ MultiValueMap result = converter.read(null, inputMessage);
assertEquals("Invalid result", 3, result.size());
assertEquals("Invalid result", "value 1", result.getFirst("name 1"));
@@ -97,19 +98,21 @@ public class FormHttpMessageConverterTests {
body.add("name 3", null);
MockHttpOutputMessage outputMessage = new MockHttpOutputMessage();
converter.write(body, MediaType.APPLICATION_FORM_URLENCODED, outputMessage);
- Charset iso88591 = Charset.forName("ISO-8859-1");
assertEquals("Invalid result", "name+1=value+1&name+2=value+2%2B1&name+2=value+2%2B2&name+3",
- outputMessage.getBodyAsString(iso88591));
+ outputMessage.getBodyAsString(Charset.forName("UTF-8")));
assertEquals("Invalid content-type", new MediaType("application", "x-www-form-urlencoded"),
outputMessage.getHeaders().getContentType());
+ assertEquals("Invalid content-length", outputMessage.getBodyAsBytes().length,
+ outputMessage.getHeaders().getContentLength());
}
-
+
@Test
public void writeMultipart() throws Exception {
MultiValueMap parts = new LinkedMultiValueMap();
parts.add("name 1", "value 1");
parts.add("name 2", "value 2+1");
parts.add("name 2", "value 2+2");
+
Resource logo = new ClassPathResource("/org/springframework/http/converter/logo.jpg");
parts.add("logo", logo);
Source xml = new StreamSource(new StringReader(""));
@@ -122,7 +125,7 @@ public class FormHttpMessageConverterTests {
converter.write(parts, MediaType.MULTIPART_FORM_DATA, outputMessage);
final MediaType contentType = outputMessage.getHeaders().getContentType();
- assertNotNull(contentType.getParameter("boundary"));
+ assertNotNull("No boundary found", contentType.getParameter("boundary"));
// see if Commons FileUpload can read what we wrote
FileItemFactory fileItemFactory = new DiskFileItemFactory();
@@ -157,6 +160,7 @@ public class FormHttpMessageConverterTests {
}
private static class MockHttpOutputMessageRequestContext implements RequestContext {
+
private final MockHttpOutputMessage outputMessage;
private MockHttpOutputMessageRequestContext(MockHttpOutputMessage outputMessage) {
@@ -182,5 +186,4 @@ public class FormHttpMessageConverterTests {
}
}
-
}