Merge branch '3.2.x' into master

Conflicts:
	gradle.properties
	spring-beans/src/main/java/org/springframework/beans/factory/support/StaticListableBeanFactory.java
	spring-context-support/src/main/java/org/springframework/cache/ehcache/EhCacheManagerFactoryBean.java
	spring-core/src/main/java/org/springframework/core/convert/support/StringToEnumConverterFactory.java
	spring-core/src/main/java/org/springframework/core/env/ReadOnlySystemAttributesMap.java
	spring-jdbc/src/main/java/org/springframework/jdbc/datasource/LazyConnectionDataSourceProxy.java
	spring-jdbc/src/main/java/org/springframework/jdbc/support/lob/AbstractLobHandler.java
	spring-web/src/main/java/org/springframework/http/client/BufferingClientHttpRequestWrapper.java
	spring-web/src/main/java/org/springframework/http/client/SimpleBufferingClientHttpRequest.java
	spring-web/src/main/java/org/springframework/http/converter/BufferedImageHttpMessageConverter.java
	spring-web/src/main/java/org/springframework/http/converter/FormHttpMessageConverter.java
This commit is contained in:
Chris Beams
2013-03-04 15:41:15 +01:00
1450 changed files with 17678 additions and 42998 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 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.
@@ -125,7 +125,9 @@ public enum HttpStatus {
/**
* {@code 302 Moved Temporarily}.
* @see <a href="http://tools.ietf.org/html/rfc1945#section-9.3">HTTP/1.0</a>
* @deprecated In favor of {@link #FOUND} which will be returned from {@code HttpStatus.valueOf(302)}
*/
@Deprecated
MOVED_TEMPORARILY(302, "Moved Temporarily"),
/**
* {@code 303 See Other}.

View File

@@ -0,0 +1,51 @@
/*
* Copyright 2002-2013 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.http;
/**
* Exception thrown from {@link MediaType#parseMediaType(String)} in case of
* encountering an invalid media type specification String.
*
* @author Juergen Hoeller
* @since 3.2.2
*/
@SuppressWarnings("serial")
public class InvalidMediaTypeException extends IllegalArgumentException {
private String mediaType;
/**
* Create a new InvalidMediaTypeException for the given media type.
* @param mediaType the offending media type
* @param msg a detail message indicating the invalid part
*/
public InvalidMediaTypeException(String mediaType, String msg) {
super("Invalid media type \"" + mediaType + "\": " + msg);
this.mediaType = mediaType;
}
/**
* Return the offending media type.
*/
public String getMediaType() {
return this.mediaType;
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 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.
@@ -17,6 +17,7 @@
package org.springframework.http;
import java.nio.charset.Charset;
import java.nio.charset.UnsupportedCharsetException;
import java.util.ArrayList;
import java.util.BitSet;
import java.util.Collection;
@@ -321,8 +322,8 @@ public class MediaType implements Comparable<MediaType> {
* @throws IllegalArgumentException if any of the parameters contain illegal characters
*/
public MediaType(String type, String subtype, Map<String, String> parameters) {
Assert.hasLength(type, "'type' must not be empty");
Assert.hasLength(subtype, "'subtype' must not be empty");
Assert.hasLength(type, "type must not be empty");
Assert.hasLength(subtype, "subtype must not be empty");
checkToken(type);
checkToken(subtype);
this.type = type.toLowerCase(Locale.ENGLISH);
@@ -347,11 +348,11 @@ public class MediaType implements Comparable<MediaType> {
* @throws IllegalArgumentException in case of illegal characters
* @see <a href="http://tools.ietf.org/html/rfc2616#section-2.2">HTTP 1.1, section 2.2</a>
*/
private void checkToken(String s) {
for (int i=0; i < s.length(); i++ ) {
char ch = s.charAt(i);
private void checkToken(String token) {
for (int i=0; i < token.length(); i++ ) {
char ch = token.charAt(i);
if (!TOKEN.get(ch)) {
throw new IllegalArgumentException("Invalid token character '" + ch + "' in token \"" + s + "\"");
throw new IllegalArgumentException("Invalid token character '" + ch + "' in token \"" + token + "\"");
}
}
}
@@ -681,7 +682,7 @@ public class MediaType implements Comparable<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
* @throws InvalidMediaTypeException if the string cannot be parsed
*/
public static MediaType parseMediaType(String mediaType) {
Assert.hasLength(mediaType, "'mediaType' must not be empty");
@@ -694,15 +695,15 @@ public class MediaType implements Comparable<MediaType> {
}
int subIndex = fullType.indexOf('/');
if (subIndex == -1) {
throw new IllegalArgumentException("\"" + mediaType + "\" does not contain '/'");
throw new InvalidMediaTypeException(mediaType, "does not contain '/'");
}
if (subIndex == fullType.length() - 1) {
throw new IllegalArgumentException("\"" + mediaType + "\" does not contain subtype after '/'");
throw new InvalidMediaTypeException(mediaType, "does not contain subtype after '/'");
}
String type = fullType.substring(0, subIndex);
String subtype = fullType.substring(subIndex + 1, fullType.length());
if (WILDCARD_TYPE.equals(type) && !WILDCARD_TYPE.equals(subtype)) {
throw new IllegalArgumentException("A wildcard type is legal only in '*/*' (all media types).");
throw new InvalidMediaTypeException(mediaType, "wildcard type is legal only in '*/*' (all media types)");
}
Map<String, String> parameters = null;
@@ -719,7 +720,15 @@ public class MediaType implements Comparable<MediaType> {
}
}
return new MediaType(type, subtype, parameters);
try {
return new MediaType(type, subtype, parameters);
}
catch (UnsupportedCharsetException ex) {
throw new InvalidMediaTypeException(mediaType, "unsupported charset '" + ex.getCharsetName() + "'");
}
catch (IllegalArgumentException ex) {
throw new InvalidMediaTypeException(mediaType, ex.getMessage());
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 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,7 +23,7 @@ import java.net.URI;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.util.Assert;
import org.springframework.util.FileCopyUtils;
import org.springframework.util.StreamUtils;
/**
* Simple implementation of {@link ClientHttpRequest} that wraps another request.
@@ -53,8 +53,7 @@ final class BufferingClientHttpRequestWrapper extends AbstractBufferingClientHtt
@Override
protected ClientHttpResponse executeInternal(HttpHeaders headers, byte[] bufferedOutput) throws IOException {
this.request.getHeaders().putAll(headers);
OutputStream body = this.request.getBody();
FileCopyUtils.copy(bufferedOutput, body);
StreamUtils.copy(bufferedOutput, this.request.getBody());
ClientHttpResponse response = this.request.execute();
return new BufferingClientHttpResponseWrapper(response);
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 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,7 @@ import java.io.InputStream;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.util.FileCopyUtils;
import org.springframework.util.StreamUtils;
/**
* Simple implementation of {@link ClientHttpResponse} that reads the request's body into memory,
@@ -61,7 +62,7 @@ final class BufferingClientHttpResponseWrapper implements ClientHttpResponse {
public InputStream getBody() throws IOException {
if (this.body == null) {
this.body = FileCopyUtils.copyToByteArray(this.response.getBody());
this.body = StreamUtils.copyToByteArray(this.response.getBody());
}
return new ByteArrayInputStream(this.body);
}

View File

@@ -74,4 +74,4 @@ final class CommonsClientHttpResponse extends AbstractClientHttpResponse {
this.httpMethod.releaseConnection();
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 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.
@@ -24,7 +24,7 @@ import java.util.List;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpRequest;
import org.springframework.util.FileCopyUtils;
import org.springframework.util.StreamUtils;
/**
* Wrapper for a {@link ClientHttpRequest} that has support for {@link ClientHttpRequestInterceptor}s.
@@ -86,7 +86,7 @@ class InterceptingClientHttpRequest extends AbstractBufferingClientHttpRequest {
delegate.getHeaders().putAll(request.getHeaders());
if (body.length > 0) {
FileCopyUtils.copy(body, delegate.getBody());
StreamUtils.copy(body, delegate.getBody());
}
return delegate.execute();
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 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.
@@ -39,9 +39,12 @@ final class SimpleBufferingClientHttpRequest extends AbstractBufferingClientHttp
private final HttpURLConnection connection;
private final boolean outputStreaming;
SimpleBufferingClientHttpRequest(HttpURLConnection connection) {
SimpleBufferingClientHttpRequest(HttpURLConnection connection, boolean outputStreaming) {
this.connection = connection;
this.outputStreaming = outputStreaming;
}
@@ -67,7 +70,7 @@ final class SimpleBufferingClientHttpRequest extends AbstractBufferingClientHttp
}
}
if (this.connection.getDoOutput()) {
if (this.connection.getDoOutput() && this.outputStreaming) {
this.connection.setFixedLengthStreamingMode(bufferedOutput.length);
}
this.connection.connect();

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 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.
@@ -50,6 +50,8 @@ public class SimpleClientHttpRequestFactory implements ClientHttpRequestFactory
private int readTimeout = -1;
private boolean outputStreaming = true;
/**
* Set the {@link Proxy} to use for this request factory.
@@ -104,15 +106,31 @@ public class SimpleClientHttpRequestFactory implements ClientHttpRequestFactory
this.readTimeout = readTimeout;
}
/**
* Set if the underlying URLConnection can be set to 'output streaming' mode. When
* output streaming is enabled, authentication and redirection cannot be handled
* automatically. If output streaming is disabled the
* {@link HttpURLConnection#setFixedLengthStreamingMode(int)
* setFixedLengthStreamingMode} and
* {@link HttpURLConnection#setChunkedStreamingMode(int) setChunkedStreamingMode}
* methods of the underlying connection will never be called.
* <p>Default is {@code true}.
* @param outputStreaming if output streaming is enabled
*/
public void setOutputStreaming(boolean outputStreaming) {
this.outputStreaming = outputStreaming;
}
public ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod) throws IOException {
HttpURLConnection connection = openConnection(uri.toURL(), this.proxy);
prepareConnection(connection, httpMethod.name());
if (this.bufferRequestBody) {
return new SimpleBufferingClientHttpRequest(connection);
return new SimpleBufferingClientHttpRequest(connection, this.outputStreaming);
}
else {
return new SimpleStreamingClientHttpRequest(connection, this.chunkSize);
return new SimpleStreamingClientHttpRequest(connection, this.chunkSize,
this.outputStreaming);
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 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,7 +16,6 @@
package org.springframework.http.client;
import java.io.FilterOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.HttpURLConnection;
@@ -27,6 +26,7 @@ import java.util.Map;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.util.StreamUtils;
/**
* {@link ClientHttpRequest} implementation that uses standard J2SE facilities to execute streaming requests.
@@ -44,10 +44,14 @@ final class SimpleStreamingClientHttpRequest extends AbstractClientHttpRequest {
private OutputStream body;
private final boolean outputStreaming;
SimpleStreamingClientHttpRequest(HttpURLConnection connection, int chunkSize) {
SimpleStreamingClientHttpRequest(HttpURLConnection connection, int chunkSize,
boolean outputStreaming) {
this.connection = connection;
this.chunkSize = chunkSize;
this.outputStreaming = outputStreaming;
}
public HttpMethod getMethod() {
@@ -66,18 +70,20 @@ final class SimpleStreamingClientHttpRequest extends AbstractClientHttpRequest {
@Override
protected OutputStream getBodyInternal(HttpHeaders headers) throws IOException {
if (this.body == null) {
int contentLength = (int) headers.getContentLength();
if (contentLength >= 0) {
this.connection.setFixedLengthStreamingMode(contentLength);
}
else {
this.connection.setChunkedStreamingMode(this.chunkSize);
if(this.outputStreaming) {
int contentLength = (int) headers.getContentLength();
if (contentLength >= 0) {
this.connection.setFixedLengthStreamingMode(contentLength);
}
else {
this.connection.setChunkedStreamingMode(this.chunkSize);
}
}
writeHeaders(headers);
this.connection.connect();
this.body = this.connection.getOutputStream();
}
return new NonClosingOutputStream(this.body);
return StreamUtils.nonClosing(this.body);
}
private void writeHeaders(HttpHeaders headers) {
@@ -106,26 +112,4 @@ final class SimpleStreamingClientHttpRequest extends AbstractClientHttpRequest {
return new SimpleClientHttpResponse(this.connection);
}
private static class NonClosingOutputStream extends FilterOutputStream {
private NonClosingOutputStream(OutputStream out) {
super(out);
}
@Override
public void write(byte[] b) throws IOException {
super.write(b);
}
@Override
public void write(byte[] b, int off, int let) throws IOException {
out.write(b, off, let);
}
@Override
public void close() throws IOException {
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 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.
@@ -132,7 +132,7 @@ public class BufferedImageHttpMessageConverter implements HttpMessageConverter<B
}
private boolean isWritable(MediaType mediaType) {
if (mediaType == null) {
if (mediaType == null || MediaType.ALL.equals(mediaType)) {
return true;
}
Iterator<ImageWriter> imageWriters = ImageIO.getImageWritersByMIMEType(mediaType.toString());
@@ -191,7 +191,7 @@ public class BufferedImageHttpMessageConverter implements HttpMessageConverter<B
public void write(BufferedImage image, MediaType contentType, HttpOutputMessage outputMessage)
throws IOException, HttpMessageNotWritableException {
if (contentType == null) {
if (contentType == null || contentType.isWildcardType() || contentType.isWildcardSubtype()) {
contentType = getDefaultContentType();
}
Assert.notNull(contentType,

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 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,7 +22,7 @@ import java.io.IOException;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.MediaType;
import org.springframework.util.FileCopyUtils;
import org.springframework.util.StreamUtils;
/**
* Implementation of {@link HttpMessageConverter} that can read and write byte arrays.
@@ -49,14 +49,9 @@ public class ByteArrayHttpMessageConverter extends AbstractHttpMessageConverter<
@Override
public byte[] readInternal(Class clazz, HttpInputMessage inputMessage) throws IOException {
long contentLength = inputMessage.getHeaders().getContentLength();
if (contentLength >= 0) {
ByteArrayOutputStream bos = new ByteArrayOutputStream((int) contentLength);
FileCopyUtils.copy(inputMessage.getBody(), bos);
return bos.toByteArray();
}
else {
return FileCopyUtils.copyToByteArray(inputMessage.getBody());
}
ByteArrayOutputStream bos = new ByteArrayOutputStream(contentLength >= 0 ? (int) contentLength : StreamUtils.BUFFER_SIZE);
StreamUtils.copy(inputMessage.getBody(), bos);
return bos.toByteArray();
}
@Override
@@ -66,7 +61,7 @@ public class ByteArrayHttpMessageConverter extends AbstractHttpMessageConverter<
@Override
protected void writeInternal(byte[] bytes, HttpOutputMessage outputMessage) throws IOException {
FileCopyUtils.copy(bytes, outputMessage.getBody());
StreamUtils.copy(bytes, outputMessage.getBody());
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 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.
@@ -17,7 +17,6 @@
package org.springframework.http.converter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
@@ -37,9 +36,9 @@ import org.springframework.http.HttpInputMessage;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.MediaType;
import org.springframework.util.Assert;
import org.springframework.util.FileCopyUtils;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.util.StreamUtils;
import org.springframework.util.StringUtils;
/**
@@ -170,7 +169,7 @@ public class FormHttpMessageConverter implements HttpMessageConverter<MultiValue
MediaType contentType = inputMessage.getHeaders().getContentType();
Charset charset = contentType.getCharSet() != null ? contentType.getCharSet() : this.charset;
String body = FileCopyUtils.copyToString(new InputStreamReader(inputMessage.getBody(), charset));
String body = StreamUtils.copyToString(inputMessage.getBody(), charset);
String[] pairs = StringUtils.tokenizeToStringArray(body, "&");
@@ -246,7 +245,7 @@ public class FormHttpMessageConverter implements HttpMessageConverter<MultiValue
}
byte[] bytes = builder.toString().getBytes(charset.name());
outputMessage.getHeaders().setContentLength(bytes.length);
FileCopyUtils.copy(bytes, outputMessage.getBody());
StreamUtils.copy(bytes, outputMessage.getBody());
}
private void writeMultipart(MultiValueMap<String, Object> parts, HttpOutputMessage outputMessage)
@@ -265,10 +264,12 @@ public class FormHttpMessageConverter implements HttpMessageConverter<MultiValue
for (Map.Entry<String, List<Object>> entry : parts.entrySet()) {
String name = entry.getKey();
for (Object part : entry.getValue()) {
writeBoundary(boundary, os);
HttpEntity entity = getEntity(part);
writePart(name, entity, os);
writeNewLine(os);
if (part != null) {
writeBoundary(boundary, os);
HttpEntity entity = getEntity(part);
writePart(name, entity, os);
writeNewLine(os);
}
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2011 the original author or authors.
* Copyright 2002-2013 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.
@@ -18,6 +18,7 @@ package org.springframework.http.converter;
import java.io.IOException;
import java.io.InputStream;
import javax.activation.FileTypeMap;
import javax.activation.MimetypesFileTypeMap;
@@ -28,7 +29,7 @@ import org.springframework.http.HttpInputMessage;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.MediaType;
import org.springframework.util.ClassUtils;
import org.springframework.util.FileCopyUtils;
import org.springframework.util.StreamUtils;
import org.springframework.util.StringUtils;
/**
@@ -61,7 +62,7 @@ public class ResourceHttpMessageConverter extends AbstractHttpMessageConverter<R
protected Resource readInternal(Class<? extends Resource> clazz, HttpInputMessage inputMessage)
throws IOException, HttpMessageNotReadableException {
byte[] body = FileCopyUtils.copyToByteArray(inputMessage.getBody());
byte[] body = StreamUtils.copyToByteArray(inputMessage.getBody());
return new ByteArrayResource(body);
}
@@ -84,7 +85,7 @@ public class ResourceHttpMessageConverter extends AbstractHttpMessageConverter<R
protected void writeInternal(Resource resource, HttpOutputMessage outputMessage)
throws IOException, HttpMessageNotWritableException {
FileCopyUtils.copy(resource.getInputStream(), outputMessage.getBody());
StreamUtils.copy(resource.getInputStream(), outputMessage.getBody());
outputMessage.getBody().flush();
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 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.
@@ -17,8 +17,6 @@
package org.springframework.http.converter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.util.ArrayList;
@@ -27,7 +25,7 @@ import java.util.List;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.MediaType;
import org.springframework.util.FileCopyUtils;
import org.springframework.util.StreamUtils;
/**
* Implementation of {@link HttpMessageConverter} that can read and write strings.
@@ -84,7 +82,7 @@ public class StringHttpMessageConverter extends AbstractHttpMessageConverter<Str
@Override
protected String readInternal(Class<? extends String> clazz, HttpInputMessage inputMessage) throws IOException {
Charset charset = getContentTypeCharset(inputMessage.getHeaders().getContentType());
return FileCopyUtils.copyToString(new InputStreamReader(inputMessage.getBody(), charset));
return StreamUtils.copyToString(inputMessage.getBody(), charset);
}
@Override
@@ -105,7 +103,7 @@ public class StringHttpMessageConverter extends AbstractHttpMessageConverter<Str
outputMessage.getHeaders().setAcceptCharset(getAcceptedCharsets());
}
Charset charset = getContentTypeCharset(outputMessage.getHeaders().getContentType());
FileCopyUtils.copy(s, new OutputStreamWriter(outputMessage.getBody(), charset));
StreamUtils.copy(s, charset, outputMessage.getBody());
}
/**

View File

@@ -43,5 +43,4 @@ public class RssChannelHttpMessageConverter extends AbstractWireFeedHttpMessageC
return Channel.class.isAssignableFrom(clazz);
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 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.
@@ -18,6 +18,7 @@ package org.springframework.web.accept;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
@@ -55,6 +56,7 @@ public class ContentNegotiationManager implements ContentNegotiationStrategy, Me
private final Set<MediaTypeFileExtensionResolver> fileExtensionResolvers =
new LinkedHashSet<MediaTypeFileExtensionResolver>();
/**
* Create an instance with the given ContentNegotiationStrategy instances.
* <p>Each instance is checked to see if it is also an implementation of
@@ -72,12 +74,29 @@ public class ContentNegotiationManager implements ContentNegotiationStrategy, Me
}
/**
* Create an instance with a {@link HeaderContentNegotiationStrategy}.
* Create an instance with the given ContentNegotiationStrategy instances.
* <p>Each instance is checked to see if it is also an implementation of
* MediaTypeFileExtensionResolver, and if so it is registered as such.
* @param strategies one more more ContentNegotiationStrategy instances
*/
public ContentNegotiationManager(Collection<ContentNegotiationStrategy> strategies) {
Assert.notEmpty(strategies, "At least one ContentNegotiationStrategy is expected");
this.contentNegotiationStrategies.addAll(strategies);
for (ContentNegotiationStrategy strategy : this.contentNegotiationStrategies) {
if (strategy instanceof MediaTypeFileExtensionResolver) {
this.fileExtensionResolvers.add((MediaTypeFileExtensionResolver) strategy);
}
}
}
/**
* Create a default instance with a {@link HeaderContentNegotiationStrategy}.
*/
public ContentNegotiationManager() {
this(new HeaderContentNegotiationStrategy());
}
/**
* Add MediaTypeFileExtensionResolver instances.
* <p>Note that some {@link ContentNegotiationStrategy} implementations also

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 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.
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.web.accept;
import java.util.ArrayList;
@@ -22,7 +23,6 @@ import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import javax.servlet.ServletContext;
import org.springframework.beans.factory.FactoryBean;
@@ -39,13 +39,13 @@ import org.springframework.web.context.ServletContextAware;
* <p>By default strategies for checking the extension of the request path and
* the {@code Accept} header are registered. The path extension check will perform
* lookups through the {@link ServletContext} and the Java Activation Framework
* (if present) unless {@linkplain #setMediaTypes(Properties) media types} are configured.
* (if present) unless {@linkplain #setMediaTypes media types} are configured.
*
* @author Rossen Stoyanchev
* @since 3.2
*/
public class ContentNegotiationManagerFactoryBean
implements FactoryBean<ContentNegotiationManager>, InitializingBean, ServletContextAware {
implements FactoryBean<ContentNegotiationManager>, ServletContextAware, InitializingBean {
private boolean favorPathExtension = true;
@@ -65,6 +65,7 @@ public class ContentNegotiationManagerFactoryBean
private ServletContext servletContext;
/**
* Indicate whether the extension of the request path should be used to determine
* the requested media type with the <em>highest priority</em>.
@@ -81,7 +82,6 @@ public class ContentNegotiationManagerFactoryBean
* <p>When this mapping is not set or when an extension is not found, the Java
* Action Framework, if available, may be used if enabled via
* {@link #setFavorPathExtension(boolean)}.
*
* @see #addMediaType(String, MediaType)
* @see #addMediaTypes(Map)
*/
@@ -121,9 +121,8 @@ public class ContentNegotiationManagerFactoryBean
* to map from file extensions to media types. This is used only when
* {@link #setFavorPathExtension(boolean)} is set to {@code true}.
* <p>The default value is {@code true}.
*
* @see #parameterName
* @see #setMediaTypes(Properties)
* @see #setParameterName
* @see #setMediaTypes
*/
public void setUseJaf(boolean useJaf) {
this.useJaf = useJaf;
@@ -138,8 +137,7 @@ public class ContentNegotiationManagerFactoryBean
* {@code "application/pdf"} regardless of the {@code Accept} header.
* <p>To use this option effectively you must also configure the MediaType
* type mappings via {@link #setMediaTypes(Properties)}.
*
* @see #setParameterName(String)
* @see #setParameterName
*/
public void setFavorParameter(boolean favorParameter) {
this.favorParameter = favorParameter;
@@ -180,7 +178,8 @@ public class ContentNegotiationManagerFactoryBean
this.servletContext = servletContext;
}
public void afterPropertiesSet() throws Exception {
public void afterPropertiesSet() {
List<ContentNegotiationStrategy> strategies = new ArrayList<ContentNegotiationStrategy>();
if (this.favorPathExtension) {
@@ -210,8 +209,12 @@ public class ContentNegotiationManagerFactoryBean
strategies.add(new FixedContentNegotiationStrategy(this.defaultContentType));
}
ContentNegotiationStrategy[] array = strategies.toArray(new ContentNegotiationStrategy[strategies.size()]);
this.contentNegotiationManager = new ContentNegotiationManager(array);
this.contentNegotiationManager = new ContentNegotiationManager(strategies);
}
public ContentNegotiationManager getObject() {
return this.contentNegotiationManager;
}
public Class<?> getObjectType() {
@@ -222,8 +225,4 @@ public class ContentNegotiationManagerFactoryBean
return true;
}
public ContentNegotiationManager getObject() throws Exception {
return this.contentNegotiationManager;
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 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.
@@ -55,14 +55,14 @@ public @interface CookieValue {
* in case the header is missing in the request. Switch this to
* {@code false} if you prefer a {@code null} in case of the
* missing header.
* <p>Alternatively, provide a {@link #defaultValue() defaultValue},
* which implicitly sets this flag to {@code false}.
* <p>Alternatively, provide a {@link #defaultValue}, which implicitly sets
* this flag to {@code false}.
*/
boolean required() default true;
/**
* The default value to use as a fallback. Supplying a default value implicitly
* sets {@link #required()} to false.
* sets {@link #required} to {@code false}.
*/
String defaultValue() default ValueConstants.DEFAULT_NONE;

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 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.
@@ -49,14 +49,14 @@ public @interface RequestHeader {
* <p>Default is {@code true}, leading to an exception thrown in case
* of the header missing in the request. Switch this to {@code false}
* if you prefer a {@code null} in case of the header missing.
* <p>Alternatively, provide a {@link #defaultValue() defaultValue},
* which implicitely sets this flag to {@code false}.
* <p>Alternatively, provide a {@link #defaultValue}, which implicitly sets
* this flag to {@code false}.
*/
boolean required() default true;
/**
* The default value to use as a fallback. Supplying a default value implicitely
* sets {@link #required()} to false.
* The default value to use as a fallback. Supplying a default value implicitly
* sets {@link #required} to {@code false}.
*/
String defaultValue() default ValueConstants.DEFAULT_NONE;

View File

@@ -266,6 +266,7 @@ public @interface RequestMapping {
* Ant-style path patterns are also supported (e.g. "/myPath/*.do").
* At the method level, relative paths (e.g. "edit.do") are supported
* within the primary mapping expressed at the type level.
* Path mapping URIs may contain placeholders (e.g. "/${connect}")
* <p>In a Portlet environment: the mapped portlet modes
* (i.e. "EDIT", "VIEW", "HELP" or any custom modes).
* <p><b>Supported at the type level as well as at the method level!</b>

View File

@@ -68,8 +68,9 @@ public @interface RequestParam {
boolean required() default true;
/**
* The default value to use as a fallback. Supplying a default value implicitly
* sets {@link #required()} to false.
* The default value to use as a fallback when the request parameter value
* is not provided or empty. Supplying a default value implicitly sets
* {@link #required()} to false.
*/
String defaultValue() default ValueConstants.DEFAULT_NONE;

View File

@@ -36,4 +36,4 @@ import java.lang.annotation.Target;
@Documented
public @interface ResponseBody {
}
}

View File

@@ -37,4 +37,4 @@ public interface WebDataBinderFactory {
*/
WebDataBinder createBinder(NativeWebRequest webRequest, Object target, String objectName) throws Exception;
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 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.
@@ -71,11 +71,6 @@ public interface ConfigurableWebApplicationContext extends WebApplicationContext
*/
ServletConfig getServletConfig();
/**
* Return the {@link ConfigurableWebEnvironment} used by this web application context.
*/
ConfigurableWebEnvironment getEnvironment();
/**
* Set the namespace for this web application context,
* to be used for building a default context config location.

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 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,11 +23,11 @@ import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;
import javax.servlet.ServletContext;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.access.BeanFactoryLocator;
import org.springframework.beans.factory.access.BeanFactoryReference;
@@ -38,6 +38,7 @@ import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.access.ContextSingletonBeanFactoryLocator;
import org.springframework.core.GenericTypeResolver;
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.support.PropertiesLoaderUtils;
import org.springframework.util.Assert;
@@ -280,7 +281,18 @@ public class ContextLoader {
this.context = createWebApplicationContext(servletContext);
}
if (this.context instanceof ConfigurableWebApplicationContext) {
configureAndRefreshWebApplicationContext((ConfigurableWebApplicationContext)this.context, servletContext);
ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) this.context;
if (!cwac.isActive()) {
// The context has not yet been refreshed -> provide services such as
// setting the parent context, setting the application context id, etc
if (cwac.getParent() == null) {
// The context instance was injected without an explicit parent ->
// determine parent for root web application context, if any.
ApplicationContext parent = loadParentContext(servletContext);
cwac.setParent(parent);
}
configureAndRefreshWebApplicationContext(cwac, servletContext);
}
}
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);
@@ -333,9 +345,7 @@ public class ContextLoader {
throw new ApplicationContextException("Custom context class [" + contextClass.getName() +
"] is not of type [" + ConfigurableWebApplicationContext.class.getName() + "]");
}
ConfigurableWebApplicationContext wac =
(ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);
return wac;
return (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);
}
/**
@@ -370,10 +380,6 @@ public class ContextLoader {
}
}
// Determine parent for root web application context, if any.
ApplicationContext parent = loadParentContext(sc);
wac.setParent(parent);
wac.setServletContext(sc);
String initParameter = sc.getInitParameter(CONFIG_LOCATION_PARAM);
if (initParameter != null) {
@@ -472,11 +478,11 @@ public class ContextLoader {
Class<?> contextClass = applicationContext.getClass();
ArrayList<ApplicationContextInitializer<ConfigurableApplicationContext>> initializerInstances =
new ArrayList<ApplicationContextInitializer<ConfigurableApplicationContext>>();
new ArrayList<ApplicationContextInitializer<ConfigurableApplicationContext>>();
for (Class<ApplicationContextInitializer<ConfigurableApplicationContext>> initializerClass : initializerClasses) {
Class<?> initializerContextClass =
GenericTypeResolver.resolveTypeArgument(initializerClass, ApplicationContextInitializer.class);
GenericTypeResolver.resolveTypeArgument(initializerClass, ApplicationContextInitializer.class);
Assert.isAssignable(initializerContextClass, contextClass, String.format(
"Could not add context initializer [%s] as its generic parameter [%s] " +
"is not assignable from the type of application context used by this " +
@@ -485,7 +491,10 @@ public class ContextLoader {
initializerInstances.add(BeanUtils.instantiateClass(initializerClass));
}
applicationContext.getEnvironment().initPropertySources(servletContext, null);
ConfigurableEnvironment env = applicationContext.getEnvironment();
if (env instanceof ConfigurableWebEnvironment) {
((ConfigurableWebEnvironment)env).initPropertySources(servletContext, null);
}
Collections.sort(initializerInstances, new AnnotationAwareOrderComparator());
for (ApplicationContextInitializer<ConfigurableApplicationContext> initializer : initializerInstances) {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 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,13 +32,13 @@ import org.springframework.web.context.request.NativeWebRequest;
* <p>Subclasses can extend this class to easily associate additional data or
* behavior with the {@link DeferredResult}. For example, one might want to
* associate the user used to create the {@link DeferredResult} by extending the
* class and adding an addition property for the user. In this way, the user
* class and adding an additional property for the user. In this way, the user
* could easily be accessed later without the need to use a data structure to do
* the mapping.
*
* <p>An example of associating additional behavior to this class might be
* realized by extending the class to implement an additional interface. For
* example, one might want to implement a {@link Comparable} so that when the
* example, one might want to implement {@link Comparable} so that when the
* {@link DeferredResult} is added to a {@link PriorityQueue} it is handled in
* the correct order.
*

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 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.
@@ -37,9 +37,9 @@ import org.springframework.web.util.UrlPathHelper;
* as an SPI and not typically used directly by application classes.
*
* <p>An async scenario starts with request processing as usual in a thread (T1).
* Concurrent request handling can be innitiated by calling
* {@linkplain #startCallableProcessing(Callable, Object...) startCallableProcessing} or
* {@linkplain #startDeferredResultProcessing(DeferredResult, Object...) startDeferredResultProcessing}
* Concurrent request handling can be initiated by calling
* {@link #startCallableProcessing(Callable, Object...) startCallableProcessing} or
* {@link #startDeferredResultProcessing(DeferredResult, Object...) startDeferredResultProcessing},
* both of which produce a result in a separate thread (T2). The result is saved
* and the request dispatched to the container, to resume processing with the saved
* result in a third thread (T3). Within the dispatched thread (T3), the saved
@@ -263,7 +263,7 @@ public final class WebAsyncManager {
* the timeout value of the {@code AsyncWebRequest} before delegating to
* {@link #startCallableProcessing(Callable, Object...)}.
*
* @param webAsyncTask an WebAsyncTask containing the target {@code Callable}
* @param webAsyncTask a WebAsyncTask containing the target {@code Callable}
* @param processingContext additional context to save that can be accessed
* via {@link #getConcurrentResultContext()}
* @throws Exception If concurrent processing failed to start

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 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.
@@ -46,7 +46,7 @@ public class WebAsyncTask<V> {
/**
* Create an {@code WebAsyncTask} wrapping the given {@link Callable}.
* Create a {@code WebAsyncTask} wrapping the given {@link Callable}.
* @param callable the callable for concurrent handling
*/
public WebAsyncTask(Callable<V> callable) {
@@ -54,7 +54,7 @@ public class WebAsyncTask<V> {
}
/**
* Create an {@code WebAsyncTask} with a timeout value and a {@link Callable}.
* Create a {@code WebAsyncTask} with a timeout value and a {@link Callable}.
* @param timeout timeout value in milliseconds
* @param callable the callable for concurrent handling
*/
@@ -63,7 +63,7 @@ public class WebAsyncTask<V> {
}
/**
* Create an {@code WebAsyncTask} with a timeout value, an executor name, and a {@link Callable}.
* Create a {@code WebAsyncTask} with a timeout value, an executor name, and a {@link Callable}.
* @param timeout timeout value in milliseconds; ignored if {@code null}
* @param callable the callable for concurrent handling
*/
@@ -73,7 +73,7 @@ public class WebAsyncTask<V> {
}
/**
* Create an {@code WebAsyncTask} with a timeout value, an executor instance, and a Callable.
* Create a {@code WebAsyncTask} with a timeout value, an executor instance, and a Callable.
* @param timeout timeout value in milliseconds; ignored if {@code null}
* @param callable the callable for concurrent handling
*/
@@ -113,7 +113,7 @@ public class WebAsyncTask<V> {
return this.executor;
}
else if (this.executorName != null) {
Assert.state(this.beanFactory != null, "A BeanFactory is required to look up an task executor bean");
Assert.state(this.beanFactory != null, "A BeanFactory is required to look up a task executor bean");
return this.beanFactory.getBean(this.executorName, AsyncTaskExecutor.class);
}
else {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 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.
@@ -27,7 +27,6 @@ import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.ui.context.Theme;
import org.springframework.ui.context.ThemeSource;
import org.springframework.ui.context.support.UiApplicationContextUtils;
import org.springframework.util.Assert;
import org.springframework.web.context.ConfigurableWebApplicationContext;
import org.springframework.web.context.ConfigurableWebEnvironment;
import org.springframework.web.context.ServletConfigAware;
@@ -157,15 +156,6 @@ public abstract class AbstractRefreshableWebApplicationContext extends AbstractR
return new StandardServletEnvironment();
}
@Override
public ConfigurableWebEnvironment getEnvironment() {
ConfigurableEnvironment env = super.getEnvironment();
Assert.isInstanceOf(ConfigurableWebEnvironment.class, env,
"ConfigurableWebApplicationContext environment must be of type " +
"ConfigurableWebEnvironment");
return (ConfigurableWebEnvironment) env;
}
/**
* Register request/session scopes, a {@link ServletContextAwareProcessor}, etc.
*/
@@ -212,7 +202,11 @@ public abstract class AbstractRefreshableWebApplicationContext extends AbstractR
@Override
protected void initPropertySources() {
super.initPropertySources();
this.getEnvironment().initPropertySources(this.servletContext, this.servletConfig);
ConfigurableEnvironment env = this.getEnvironment();
if (env instanceof ConfigurableWebEnvironment) {
((ConfigurableWebEnvironment)env).initPropertySources(
this.servletContext, this.servletConfig);
}
}
public Theme getTheme(String themeName) {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 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.
@@ -147,15 +147,6 @@ public class GenericWebApplicationContext extends GenericApplicationContext
return new StandardServletEnvironment();
}
@Override
public ConfigurableWebEnvironment getEnvironment() {
ConfigurableEnvironment env = super.getEnvironment();
Assert.isInstanceOf(ConfigurableWebEnvironment.class, env,
"ConfigurableWebApplicationContext environment must be of type " +
"ConfigurableWebEnvironment");
return (ConfigurableWebEnvironment) env;
}
/**
* Register ServletContextAwareProcessor.
* @see ServletContextAwareProcessor
@@ -202,7 +193,11 @@ public class GenericWebApplicationContext extends GenericApplicationContext
@Override
protected void initPropertySources() {
super.initPropertySources();
this.getEnvironment().initPropertySources(this.servletContext, null);
ConfigurableEnvironment env = this.getEnvironment();
if (env instanceof ConfigurableWebEnvironment) {
((ConfigurableWebEnvironment)env).initPropertySources(
this.servletContext, null);
}
}
public Theme getTheme(String themeName) {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 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.
@@ -27,9 +27,7 @@ import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.ui.context.Theme;
import org.springframework.ui.context.ThemeSource;
import org.springframework.ui.context.support.UiApplicationContextUtils;
import org.springframework.util.Assert;
import org.springframework.web.context.ConfigurableWebApplicationContext;
import org.springframework.web.context.ConfigurableWebEnvironment;
import org.springframework.web.context.ServletConfigAware;
import org.springframework.web.context.ServletContextAware;
@@ -169,15 +167,6 @@ public class StaticWebApplicationContext extends StaticApplicationContext
return new StandardServletEnvironment();
}
@Override
public ConfigurableWebEnvironment getEnvironment() {
ConfigurableEnvironment env = super.getEnvironment();
Assert.isInstanceOf(ConfigurableWebEnvironment.class, env,
"ConfigurableWebApplication environment must be of type " +
"ConfigurableWebEnvironment");
return (ConfigurableWebEnvironment) env;
}
/**
* Initialize the theme capability.
*/

View File

@@ -69,4 +69,4 @@ public abstract class HandlerMethodSelector {
return handlerMethods;
}
}
}

View File

@@ -71,4 +71,4 @@ public abstract class AbstractCookieValueMethodArgumentResolver extends Abstract
super(annotation.value(), annotation.required(), annotation.defaultValue());
}
}
}
}

View File

@@ -92,6 +92,9 @@ public abstract class AbstractNamedValueMethodArgumentResolver implements Handle
}
arg = handleNullValue(namedValueInfo.name, arg, paramType);
}
else if ("".equals(arg) && (namedValueInfo.defaultValue != null)) {
arg = resolveDefaultValue(namedValueInfo.defaultValue);
}
if (binderFactory != null) {
WebDataBinder binder = binderFactory.createBinder(webRequest, null, namedValueInfo.name);

View File

@@ -76,4 +76,4 @@ public class ExpressionValueMethodArgumentResolver extends AbstractNamedValueMet
super("@Value", false, annotation.value());
}
}
}
}

View File

@@ -243,4 +243,4 @@ public final class ModelFactory {
!(value instanceof Map) && !BeanUtils.isSimpleValueType(value.getClass()));
}
}
}

View File

@@ -87,4 +87,4 @@ public class RequestHeaderMethodArgumentResolver extends AbstractNamedValueMetho
super(annotation.value(), annotation.required(), annotation.defaultValue());
}
}
}
}

View File

@@ -212,4 +212,4 @@ public class RequestParamMethodArgumentResolver extends AbstractNamedValueMethod
super(annotation.value(), annotation.required(), annotation.defaultValue());
}
}
}
}

View File

@@ -62,4 +62,4 @@ public interface HandlerMethodArgumentResolver {
NativeWebRequest webRequest,
WebDataBinderFactory binderFactory) throws Exception;
}
}

View File

@@ -58,4 +58,4 @@ public interface HandlerMethodReturnValueHandler {
ModelAndViewContainer mavContainer,
NativeWebRequest webRequest) throws Exception;
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 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.
@@ -17,6 +17,7 @@
package org.springframework.web.util;
import java.io.ByteArrayOutputStream;
import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URISyntaxException;
@@ -38,9 +39,11 @@ import org.springframework.util.StringUtils;
* Extension of {@link UriComponents} for hierarchical URIs.
*
* @author Arjen Poutsma
* @author Phillip Webb
* @since 3.1.3
* @see <a href="http://tools.ietf.org/html/rfc3986#section-1.2.3">Hierarchical URIs</a>
*/
@SuppressWarnings("serial")
final class HierarchicalUriComponents extends UriComponents {
private static final char PATH_DELIMITER = '/';
@@ -405,7 +408,10 @@ final class HierarchicalUriComponents extends UriComponents {
else {
String path = getPath();
if (StringUtils.hasLength(path) && path.charAt(0) != PATH_DELIMITER) {
path = PATH_DELIMITER + path;
// Only prefix the path delimiter if something exists before it
if(getScheme() != null || getUserInfo() != null || getHost() != null || getPort() != -1) {
path = PATH_DELIMITER + path;
}
}
return new URI(getScheme(), getUserInfo(), getHost(), getPort(), path, getQuery(),
getFragment());
@@ -425,28 +431,15 @@ final class HierarchicalUriComponents extends UriComponents {
return false;
}
HierarchicalUriComponents other = (HierarchicalUriComponents) obj;
if (ObjectUtils.nullSafeEquals(getScheme(), other.getScheme())) {
return false;
}
if (ObjectUtils.nullSafeEquals(getUserInfo(), other.getUserInfo())) {
return false;
}
if (ObjectUtils.nullSafeEquals(getHost(), other.getHost())) {
return false;
}
if (this.port != other.port) {
return false;
}
if (!this.path.equals(other.path)) {
return false;
}
if (!this.queryParams.equals(other.queryParams)) {
return false;
}
if (ObjectUtils.nullSafeEquals(getFragment(), other.getFragment())) {
return false;
}
return true;
boolean rtn = true;
rtn &= ObjectUtils.nullSafeEquals(getScheme(), other.getScheme());
rtn &= ObjectUtils.nullSafeEquals(getUserInfo(), other.getUserInfo());
rtn &= ObjectUtils.nullSafeEquals(getHost(), other.getHost());
rtn &= getPort() == other.getPort();
rtn &= this.path.equals(other.path);
rtn &= this.queryParams.equals(other.queryParams);
rtn &= ObjectUtils.nullSafeEquals(getFragment(), other.getFragment());
return rtn;
}
@Override
@@ -614,7 +607,7 @@ final class HierarchicalUriComponents extends UriComponents {
/**
* Defines the contract for path (segments).
*/
interface PathComponent {
interface PathComponent extends Serializable {
String getPath();

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2008 the original author or authors.
* Copyright 2002-2013 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,21 +21,21 @@ package org.springframework.web.util;
* Escapes based on the JavaScript 1.5 recommendation.
*
* <p>Reference:
* <a href="http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Guide:Literals#String_Literals">
* Core JavaScript 1.5 Guide
* </a>
* <a href="https://developer.mozilla.org/en-US/docs/JavaScript/Guide/Values,_variables,_and_literals#String_literals">
* JavaScript Guide</a> on Mozilla Developer Network.
*
* @author Juergen Hoeller
* @author Rob Harrop
* @author Rossen Stoyanchev
* @since 1.1.1
*/
public class JavaScriptUtils {
/**
* Turn special characters into escaped characters conforming to JavaScript.
* Handles complete character set defined in HTML 4.01 recommendation.
* Turn JavaScript special characters into escaped characters.
*
* @param input the input string
* @return the escaped string
* @return the string with escaped characters
*/
public static String javaScriptEscape(String input) {
if (input == null) {
@@ -73,6 +73,27 @@ public class JavaScriptUtils {
else if (c == '\f') {
filtered.append("\\f");
}
else if (c == '\b') {
filtered.append("\\b");
}
// No '\v' in Java, use octal value for VT ascii char
else if (c == '\013') {
filtered.append("\\v");
}
else if (c == '<') {
filtered.append("\\u003C");
}
else if (c == '>') {
filtered.append("\\u003E");
}
// Unicode for PS (line terminator in ECMA-262)
else if (c == '\u2028') {
filtered.append("\\u2028");
}
// Unicode for LS (line terminator in ECMA-262)
else if (c == '\u2029') {
filtered.append("\\u2029");
}
else {
filtered.append(c);
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 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.
@@ -17,12 +17,10 @@
package org.springframework.web.util;
import java.io.FileNotFoundException;
import javax.servlet.ServletContext;
import org.springframework.util.Log4jConfigurer;
import org.springframework.util.ResourceUtils;
import org.springframework.util.SystemPropertyUtils;
/**
* Convenience class that performs custom log4j initialization for web environments,
@@ -90,6 +88,7 @@ import org.springframework.util.SystemPropertyUtils;
* context-param at all) without worrying.
*
* @author Juergen Hoeller
* @author Marten Deinum
* @since 12.08.2003
* @see org.springframework.util.Log4jConfigurer
* @see Log4jConfigListener
@@ -122,9 +121,8 @@ public abstract class Log4jWebConfigurer {
if (location != null) {
// Perform actual log4j initialization; else rely on log4j's default initialization.
try {
// Resolve system property placeholders before potentially
// resolving a real path.
location = SystemPropertyUtils.resolvePlaceholders(location);
// Resolve property placeholders before potentially resolving a real path.
location = ServletContextPropertyUtils.resolvePlaceholders(location, servletContext);
// Leave a URL (e.g. "classpath:" or "file:") as-is.
if (!ResourceUtils.isUrl(location)) {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 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,9 +30,11 @@ import org.springframework.util.ObjectUtils;
* Extension of {@link UriComponents} for opaque URIs.
*
* @author Arjen Poutsma
* @author Phillip Webb
* @since 3.2
* @see <a href="http://tools.ietf.org/html/rfc3986#section-1.2.3">Hierarchical vs Opaque URIs</a>
*/
@SuppressWarnings("serial")
final class OpaqueUriComponents extends UriComponents {
private static final MultiValueMap<String, String> QUERY_PARAMS_NONE = new LinkedMultiValueMap<String, String>(0);
@@ -144,18 +146,11 @@ final class OpaqueUriComponents extends UriComponents {
}
OpaqueUriComponents other = (OpaqueUriComponents) obj;
if (ObjectUtils.nullSafeEquals(getScheme(), other.getScheme())) {
return false;
}
if (ObjectUtils.nullSafeEquals(this.ssp, other.ssp)) {
return false;
}
if (ObjectUtils.nullSafeEquals(getFragment(), other.getFragment())) {
return false;
}
return true;
boolean rtn = true;
rtn &= ObjectUtils.nullSafeEquals(getScheme(), other.getScheme());
rtn &= ObjectUtils.nullSafeEquals(this.ssp, other.ssp);
rtn &= ObjectUtils.nullSafeEquals(getFragment(), other.getFragment());
return rtn;
}
@Override

View File

@@ -0,0 +1,113 @@
/*
* Copyright 2002-2013 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.web.util;
import javax.servlet.ServletContext;
import org.springframework.util.PropertyPlaceholderHelper;
import org.springframework.util.SystemPropertyUtils;
/**
* Helper class for resolving placeholders in texts. Usually applied to file paths.
*
* <p>A text may contain {@code ${...}} placeholders, to be resolved as servlet context
* init parameters or system properties: e.g. {@code ${user.dir}}. Default values can
* be supplied using the ":" separator between key and value.
*
* @author Juergen Hoeller
* @author Marten Deinum
* @since 3.2.2
* @see SystemPropertyUtils
* @see ServletContext#getInitParameter(String)
*/
public abstract class ServletContextPropertyUtils {
private static final PropertyPlaceholderHelper strictHelper =
new PropertyPlaceholderHelper(SystemPropertyUtils.PLACEHOLDER_PREFIX,
SystemPropertyUtils.PLACEHOLDER_SUFFIX, SystemPropertyUtils.VALUE_SEPARATOR, false);
private static final PropertyPlaceholderHelper nonStrictHelper =
new PropertyPlaceholderHelper(SystemPropertyUtils.PLACEHOLDER_PREFIX,
SystemPropertyUtils.PLACEHOLDER_SUFFIX, SystemPropertyUtils.VALUE_SEPARATOR, true);
/**
* Resolve ${...} placeholders in the given text, replacing them with corresponding
* servlet context init parameter or system property values.
* @param text the String to resolve
* @param servletContext the servletContext to use for lookups.
* @return the resolved String
* @see SystemPropertyUtils#PLACEHOLDER_PREFIX
* @see SystemPropertyUtils#PLACEHOLDER_SUFFIX
* @see SystemPropertyUtils#resolvePlaceholders(String, boolean)
* @throws IllegalArgumentException if there is an unresolvable placeholder
*/
public static String resolvePlaceholders(String text, ServletContext servletContext) {
return resolvePlaceholders(text, servletContext, false);
}
/**
* Resolve ${...} placeholders in the given text, replacing them with corresponding
* servlet context init parameter or system property values. Unresolvable placeholders
* with no default value are ignored and passed through unchanged if the flag is set to true.
* @param text the String to resolve
* @param servletContext the servletContext to use for lookups.
* @param ignoreUnresolvablePlaceholders flag to determine is unresolved placeholders are ignored
* @return the resolved String
* @see SystemPropertyUtils#PLACEHOLDER_PREFIX
* @see SystemPropertyUtils#PLACEHOLDER_SUFFIX
* @see SystemPropertyUtils#resolvePlaceholders(String, boolean)
* @throws IllegalArgumentException if there is an unresolvable placeholder and the flag is false
*/
public static String resolvePlaceholders(String text, ServletContext servletContext, boolean ignoreUnresolvablePlaceholders) {
PropertyPlaceholderHelper helper = (ignoreUnresolvablePlaceholders ? nonStrictHelper : strictHelper);
return helper.replacePlaceholders(text, new ServletContextPlaceholderResolver(text, servletContext));
}
private static class ServletContextPlaceholderResolver implements PropertyPlaceholderHelper.PlaceholderResolver {
private final String text;
private final ServletContext servletContext;
public ServletContextPlaceholderResolver(String text, ServletContext servletContext) {
this.text = text;
this.servletContext = servletContext;
}
public String resolvePlaceholder(String placeholderName) {
try {
String propVal = this.servletContext.getInitParameter(placeholderName);
if (propVal == null) {
// Fall back to system properties.
propVal = System.getProperty(placeholderName);
if (propVal == null) {
// Fall back to searching the system environment.
propVal = System.getenv(placeholderName);
}
}
return propVal;
}
catch (Throwable ex) {
System.err.println("Could not resolve placeholder '" + placeholderName + "' in [" +
this.text + "] as ServletContext init-parameter or system property: " + ex);
return null;
}
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 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.web.util;
import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.util.Arrays;
@@ -38,7 +39,7 @@ import org.springframework.util.MultiValueMap;
* @since 3.1
* @see UriComponentsBuilder
*/
public abstract class UriComponents {
public abstract class UriComponents implements Serializable {
private static final String DEFAULT_ENCODING = "UTF-8";

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 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.
@@ -18,7 +18,7 @@ package org.springframework.web.util;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
@@ -29,6 +29,7 @@ import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.util.HierarchicalUriComponents.PathComponent;
/**
* Builder for {@link UriComponents}.
@@ -46,6 +47,7 @@ import org.springframework.util.StringUtils;
*
* @author Arjen Poutsma
* @author Rossen Stoyanchev
* @author Phillip Webb
* @since 3.1
* @see #newInstance()
* @see #fromPath(String)
@@ -53,7 +55,7 @@ import org.springframework.util.StringUtils;
*/
public class UriComponentsBuilder {
private static final Pattern QUERY_PARAM_PATTERN = Pattern.compile("([^&=]+)=?([^&]+)?");
private static final Pattern QUERY_PARAM_PATTERN = Pattern.compile("([^&=]+)(=?)([^&]+)?");
private static final String SCHEME_PATTERN = "([^:/?#]+):";
@@ -91,7 +93,7 @@ public class UriComponentsBuilder {
private int port = -1;
private PathComponentBuilder pathBuilder = NULL_PATH_COMPONENT_BUILDER;
private CompositePathComponentBuilder pathBuilder = new CompositePathComponentBuilder();
private final MultiValueMap<String, String> queryParams = new LinkedMultiValueMap<String, String>();
@@ -334,7 +336,7 @@ public class UriComponentsBuilder {
this.port = uri.getPort();
}
if (StringUtils.hasLength(uri.getRawPath())) {
this.pathBuilder = new FullPathComponentBuilder(uri.getRawPath());
this.pathBuilder = new CompositePathComponentBuilder(uri.getRawPath());
}
if (StringUtils.hasLength(uri.getRawQuery())) {
this.queryParams.clear();
@@ -352,7 +354,7 @@ public class UriComponentsBuilder {
this.userInfo = null;
this.host = null;
this.port = -1;
this.pathBuilder = NULL_PATH_COMPONENT_BUILDER;
this.pathBuilder = new CompositePathComponentBuilder();
this.queryParams.clear();
}
@@ -436,12 +438,7 @@ public class UriComponentsBuilder {
* @return this UriComponentsBuilder
*/
public UriComponentsBuilder path(String path) {
if (path != null) {
this.pathBuilder = this.pathBuilder.appendPath(path);
}
else {
this.pathBuilder = NULL_PATH_COMPONENT_BUILDER;
}
this.pathBuilder.addPath(path);
resetSchemeSpecificPart();
return this;
}
@@ -453,22 +450,21 @@ public class UriComponentsBuilder {
* @return this UriComponentsBuilder
*/
public UriComponentsBuilder replacePath(String path) {
this.pathBuilder = NULL_PATH_COMPONENT_BUILDER;
path(path);
this.pathBuilder = new CompositePathComponentBuilder(path);
resetSchemeSpecificPart();
return this;
}
/**
* Appends the given path segments to the existing path of this builder. Each given path segments may contain URI
* template variables.
* Appends the given path segments to the existing path of this builder. Each given
* path segments may contain URI template variables.
*
* @param pathSegments the URI path segments
* @return this UriComponentsBuilder
*/
public UriComponentsBuilder pathSegment(String... pathSegments) throws IllegalArgumentException {
Assert.notNull(pathSegments, "'segments' must not be null");
this.pathBuilder = this.pathBuilder.appendPathSegments(pathSegments);
this.pathBuilder.addPathSegments(pathSegments);
resetSchemeSpecificPart();
return this;
}
@@ -496,8 +492,10 @@ public class UriComponentsBuilder {
Matcher m = QUERY_PARAM_PATTERN.matcher(query);
while (m.find()) {
String name = m.group(1);
String value = m.group(2);
queryParam(name, value);
String eq = m.group(2);
String value = m.group(3);
queryParam(name, (value != null ? value :
(StringUtils.hasLength(eq) ? "" : null)));
}
}
else {
@@ -588,131 +586,122 @@ public class UriComponentsBuilder {
return this;
}
/**
* Represents a builder for {@link HierarchicalUriComponents.PathComponent}
*/
private interface PathComponentBuilder {
HierarchicalUriComponents.PathComponent build();
PathComponentBuilder appendPath(String path);
PathComponentBuilder appendPathSegments(String... pathSegments);
PathComponent build();
}
/**
* Represents a builder for full string paths.
*/
private static class FullPathComponentBuilder implements PathComponentBuilder {
private static class CompositePathComponentBuilder implements PathComponentBuilder {
private final StringBuilder path;
private LinkedList<PathComponentBuilder> componentBuilders = new LinkedList<PathComponentBuilder>();
private FullPathComponentBuilder(String path) {
this.path = new StringBuilder(path);
public CompositePathComponentBuilder() {
}
public HierarchicalUriComponents.PathComponent build() {
return new HierarchicalUriComponents.FullPathComponent(path.toString());
public CompositePathComponentBuilder(String path) {
addPath(path);
}
public PathComponentBuilder appendPath(String path) {
this.path.append(path);
return this;
public void addPathSegments(String... pathSegments) {
if (!ObjectUtils.isEmpty(pathSegments)) {
PathSegmentComponentBuilder psBuilder = getLastBuilder(PathSegmentComponentBuilder.class);
FullPathComponentBuilder fpBuilder = getLastBuilder(FullPathComponentBuilder.class);
if (psBuilder == null) {
psBuilder = new PathSegmentComponentBuilder();
this.componentBuilders.add(psBuilder);
if (fpBuilder != null) {
fpBuilder.removeTrailingSlash();
}
}
psBuilder.append(pathSegments);
}
}
public PathComponentBuilder appendPathSegments(String... pathSegments) {
PathComponentCompositeBuilder builder = new PathComponentCompositeBuilder(this);
builder.appendPathSegments(pathSegments);
return builder;
}
}
/**
* Represents a builder for paths segment paths.
*/
private static class PathSegmentComponentBuilder implements PathComponentBuilder {
private final List<String> pathSegments = new ArrayList<String>();
private PathSegmentComponentBuilder(String... pathSegments) {
this.pathSegments.addAll(removeEmptyPathSegments(pathSegments));
public void addPath(String path) {
if (StringUtils.hasText(path)) {
PathSegmentComponentBuilder psBuilder = getLastBuilder(PathSegmentComponentBuilder.class);
FullPathComponentBuilder fpBuilder = getLastBuilder(FullPathComponentBuilder.class);
if (psBuilder != null) {
path = path.startsWith("/") ? path : "/" + path;
}
if (fpBuilder == null) {
fpBuilder = new FullPathComponentBuilder();
this.componentBuilders.add(fpBuilder);
}
fpBuilder.append(path);
}
}
private Collection<String> removeEmptyPathSegments(String... pathSegments) {
List<String> result = new ArrayList<String>();
for (String segment : pathSegments) {
if (StringUtils.hasText(segment)) {
result.add(segment);
@SuppressWarnings("unchecked")
private <T> T getLastBuilder(Class<T> builderClass) {
if (!this.componentBuilders.isEmpty()) {
PathComponentBuilder last = this.componentBuilders.getLast();
if (builderClass.isInstance(last)) {
return (T) last;
}
}
return result;
return null;
}
public HierarchicalUriComponents.PathComponent build() {
return new HierarchicalUriComponents.PathSegmentComponent(pathSegments);
}
public PathComponentBuilder appendPath(String path) {
PathComponentCompositeBuilder builder = new PathComponentCompositeBuilder(this);
builder.appendPath(path);
return builder;
}
public PathComponentBuilder appendPathSegments(String... pathSegments) {
this.pathSegments.addAll(removeEmptyPathSegments(pathSegments));
return this;
}
}
/**
* Represents a builder for a collection of PathComponents.
*/
private static class PathComponentCompositeBuilder implements PathComponentBuilder {
private final List<PathComponentBuilder> pathComponentBuilders = new ArrayList<PathComponentBuilder>();
private PathComponentCompositeBuilder(PathComponentBuilder builder) {
pathComponentBuilders.add(builder);
}
public HierarchicalUriComponents.PathComponent build() {
List<HierarchicalUriComponents.PathComponent> pathComponents =
new ArrayList<HierarchicalUriComponents.PathComponent>(pathComponentBuilders.size());
for (PathComponentBuilder pathComponentBuilder : pathComponentBuilders) {
pathComponents.add(pathComponentBuilder.build());
public PathComponent build() {
int size = this.componentBuilders.size();
List<PathComponent> components = new ArrayList<PathComponent>(size);
for (int i = 0; i < size; i++) {
PathComponent pathComponent = this.componentBuilders.get(i).build();
if (pathComponent != null) {
components.add(pathComponent);
}
}
return new HierarchicalUriComponents.PathComponentComposite(pathComponents);
}
public PathComponentBuilder appendPath(String path) {
this.pathComponentBuilders.add(new FullPathComponentBuilder(path));
return this;
}
public PathComponentBuilder appendPathSegments(String... pathSegments) {
this.pathComponentBuilders.add(new PathSegmentComponentBuilder(pathSegments));
return this;
if (components.isEmpty()) {
return HierarchicalUriComponents.NULL_PATH_COMPONENT;
}
if (components.size() == 1) {
return components.get(0);
}
return new HierarchicalUriComponents.PathComponentComposite(components);
}
}
private static class FullPathComponentBuilder implements PathComponentBuilder {
/**
* Represents a builder for an empty path.
*/
private static PathComponentBuilder NULL_PATH_COMPONENT_BUILDER = new PathComponentBuilder() {
private StringBuilder path = new StringBuilder();
public HierarchicalUriComponents.PathComponent build() {
return HierarchicalUriComponents.NULL_PATH_COMPONENT;
public void append(String path) {
this.path.append(path);
}
public PathComponentBuilder appendPath(String path) {
return new FullPathComponentBuilder(path);
public PathComponent build() {
if (this.path.length() == 0) {
return null;
}
String path = this.path.toString().replace("//", "/");
return new HierarchicalUriComponents.FullPathComponent(path);
}
public PathComponentBuilder appendPathSegments(String... pathSegments) {
return new PathSegmentComponentBuilder(pathSegments);
public void removeTrailingSlash() {
int index = this.path.length() - 1;
if (this.path.charAt(index) == '/') {
this.path.deleteCharAt(index);
}
}
};
}
private static class PathSegmentComponentBuilder implements PathComponentBuilder {
private List<String> pathSegments = new LinkedList<String>();
public void append(String... pathSegments) {
for (String pathSegment : pathSegments) {
if (StringUtils.hasText(pathSegment)) {
this.pathSegments.add(pathSegment);
}
}
}
public PathComponent build() {
return this.pathSegments.isEmpty() ?
null : new HierarchicalUriComponents.PathSegmentComponent(this.pathSegments);
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 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,7 +32,7 @@ import org.springframework.util.Assert;
/**
* Represents a URI template. A URI template is a URI-like String that contains variables enclosed
* by braces ({@code {}, {@code }}), which can be expanded to produce an actual URI.
* by braces ({@code {}}), which can be expanded to produce an actual URI.
*
* <p>See {@link #expand(Map)}, {@link #expand(Object[])}, and {@link #match(String)} for example usages.
*

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 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.
@@ -27,6 +27,8 @@ import javax.servlet.http.HttpServletRequest;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.util.StringUtils;
/**
@@ -439,10 +441,8 @@ public class UrlPathHelper {
* @return the updated URI string
*/
public String removeSemicolonContent(String requestUri) {
if (this.removeSemicolonContent) {
return removeSemicolonContentInternal(requestUri);
}
return removeJsessionid(requestUri);
return this.removeSemicolonContent ?
removeSemicolonContentInternal(requestUri) : removeJsessionid(requestUri);
}
private String removeSemicolonContentInternal(String requestUri) {
@@ -491,6 +491,33 @@ public class UrlPathHelper {
}
}
/**
* Decode the given matrix variables via
* {@link #decodeRequestString(HttpServletRequest, String)} unless
* {@link #setUrlDecode(boolean)} is set to {@code true} in which case it is
* assumed the URL path from which the variables were extracted is already
* decoded through a call to
* {@link #getLookupPathForRequest(HttpServletRequest)}.
*
* @param request current HTTP request
* @param vars URI variables extracted from the URL path
* @return the same Map or a new Map instance
*/
public MultiValueMap<String, String> decodeMatrixVariables(HttpServletRequest request, MultiValueMap<String, String> vars) {
if (this.urlDecode) {
return vars;
}
else {
MultiValueMap<String, String> decodedVars = new LinkedMultiValueMap <String, String>(vars.size());
for (String key : vars.keySet()) {
for (String value : vars.get(key)) {
decodedVars.add(key, decodeInternal(request, value));
}
}
return decodedVars;
}
}
private boolean shouldRemoveTrailingServletPathSlash(HttpServletRequest request) {
if (request.getAttribute(WEBSPHERE_URI_ATTRIBUTE) == null) {
// Regular servlet container: behaves as expected in any case,