Merge branch 'master' into websocket-stomp

This commit is contained in:
Rossen Stoyanchev
2013-06-27 15:58:12 -04:00
307 changed files with 8375 additions and 4414 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.
@@ -412,8 +412,19 @@ public class HttpHeaders implements MultiValueMap<String, String>, Serializable
* Returns the value of the {@code IfModifiedSince} header.
* <p>The date is returned as the number of milliseconds since January 1, 1970 GMT. Returns -1 when the date is unknown.
* @return the header value
* @deprecated use {@link #getIfModifiedSince()}
*/
@Deprecated
public long getIfNotModifiedSince() {
return getIfModifiedSince();
}
/**
* Returns the value of the {@code If-Modified-Since} header.
* <p>The date is returned as the number of milliseconds since January 1, 1970 GMT. Returns -1 when the date is unknown.
* @return the header value
*/
public long getIfModifiedSince() {
return getFirstDate(IF_MODIFIED_SINCE);
}

View File

@@ -144,15 +144,15 @@ import java.util.concurrent.Callable;
* Such command objects along with their validation results will be exposed
* as model attributes, by default using the non-qualified command class name
* in property notation (e.g. "orderAddress" for type "mypackage.OrderAddress").
* Specify a parameter-level {@link ModelAttribute} annotation for declaring
* a specific model attribute name.
* Specify a parameter-level {@link ModelAttribute @ModelAttribute} annotation for
* declaring a specific model attribute name.
* <li>{@link org.springframework.validation.Errors} /
* {@link org.springframework.validation.BindingResult} validation results
* for a preceding command/form object (the immediate preceding argument).
* <li>{@link org.springframework.web.bind.support.SessionStatus} status handle
* for marking form processing as complete (triggering the cleanup of session
* attributes that have been indicated by the {@link SessionAttributes} annotation
* at the handler type level).
* attributes that have been indicated by the {@link SessionAttributes @SessionAttributes}
* annotation at the handler type level).
* <li>{@link org.springframework.web.util.UriComponentsBuilder}
* (Servlet-only, {@literal @MVC 3.1-only})
* for preparing a URL relative to the current request's host, port, scheme,
@@ -161,26 +161,26 @@ import java.util.concurrent.Callable;
*
* <p>The following return types are supported for handler methods:
* <ul>
* <li>A {@code ModelAndView} object (Servlet MVC or Portlet MVC),
* <li>A {@link ModelAndView} object (Servlet MVC or Portlet MVC),
* with the model implicitly enriched with command objects and the results
* of {@link ModelAttribute} annotated reference data accessor methods.
* of {@link ModelAttribute @ModelAttribute} annotated reference data accessor methods.
* <li>A {@link org.springframework.ui.Model Model} object, with the view name
* implicitly determined through a {@link org.springframework.web.servlet.RequestToViewNameTranslator}
* and the model implicitly enriched with command objects and the results
* of {@link ModelAttribute} annotated reference data accessor methods.
* of {@link ModelAttribute @ModelAttribute} annotated reference data accessor methods.
* <li>A {@link java.util.Map} object for exposing a model,
* with the view name implicitly determined through a
* {@link org.springframework.web.servlet.RequestToViewNameTranslator}
* and the model implicitly enriched with command objects and the results
* of {@link ModelAttribute} annotated reference data accessor methods.
* of {@link ModelAttribute @ModelAttribute} annotated reference data accessor methods.
* <li>A {@link org.springframework.web.servlet.View} object, with the
* model implicitly determined through command objects and
* {@link ModelAttribute} annotated reference data accessor methods.
* {@link ModelAttribute @ModelAttribute} annotated reference data accessor methods.
* The handler method may also programmatically enrich the model by
* declaring a {@link org.springframework.ui.Model} argument (see above).
* <li>A {@link String} value which is interpreted as view name,
* with the model implicitly determined through command objects and
* {@link ModelAttribute} annotated reference data accessor methods.
* {@link ModelAttribute @ModelAttribute} annotated reference data accessor methods.
* The handler method may also programmatically enrich the model by
* declaring a {@link org.springframework.ui.ModelMap} argument
* (see above).
@@ -198,7 +198,7 @@ import java.util.concurrent.Callable;
* <li>A {@link Callable} which is used by Spring MVC to obtain the return
* value asynchronously in a separate thread transparently managed by Spring MVC
* on behalf of the application.
* <li>A {@code org.springframework.web.context.request.async.DeferredResult}
* <li>A {@link org.springframework.web.context.request.async.DeferredResult}
* which the application uses to produce a return value in a separate
* thread of its own choosing, as an alternative to returning a Callable.
* <li>{@code void} if the method handles the response itself (by
@@ -211,10 +211,10 @@ import java.util.concurrent.Callable;
* only applicable in a Servlet environment).
* <li>Any other return type will be considered as single model attribute
* to be exposed to the view, using the attribute name specified through
* {@link ModelAttribute} at the method level (or the default attribute name
* based on the return type's class name otherwise). The model will be
* {@link ModelAttribute @ModelAttribute} at the method level (or the default attribute
* name based on the return type's class name otherwise). The model will be
* implicitly enriched with command objects and the results of
* {@link ModelAttribute} annotated reference data accessor methods.
* {@link ModelAttribute @ModelAttribute} annotated reference data accessor methods.
* </ul>
*
* <p><b>NOTE:</b> {@code @RequestMapping} will only be processed if an

View File

@@ -107,6 +107,22 @@ public class DeferredResult<T> {
return ((this.result != RESULT_NONE) || this.expired);
}
/**
* @return {@code true} if the DeferredResult has been set.
*/
public boolean hasResult() {
return this.result != RESULT_NONE;
}
/**
* @return the result or {@code null} if the result wasn't set; since the result can
* also be {@code null}, it is recommended to use {@link #hasResult()} first
* to check if there is a result prior to calling this method.
*/
public Object getResult() {
return hasResult() ? this.result : null;
}
/**
* Return the configured timeout value in milliseconds.
*/

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.
@@ -97,17 +97,11 @@ public abstract class AbstractNamedValueMethodArgumentResolver implements Handle
arg = resolveDefaultValue(namedValueInfo.defaultValue);
}
boolean emptyArgValue = "".equals(arg);
if (binderFactory != null) {
WebDataBinder binder = binderFactory.createBinder(webRequest, null, namedValueInfo.name);
arg = binder.convertIfNecessary(arg, paramType, parameter);
}
if (emptyArgValue && (arg == null)) {
handleMissingValue(namedValueInfo.name, parameter);
}
handleResolvedValue(arg, namedValueInfo.name, parameter, mavContainer, webRequest);
return arg;

View File

@@ -16,9 +16,6 @@
package org.springframework.http.client;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
@@ -43,8 +40,10 @@ import org.junit.BeforeClass;
import org.junit.Test;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.tests.web.FreePortScanner;
import org.springframework.util.FileCopyUtils;
import org.springframework.util.SocketUtils;
import static org.junit.Assert.*;
public abstract class AbstractHttpRequestFactoryTestCase {
@@ -56,7 +55,7 @@ public abstract class AbstractHttpRequestFactoryTestCase {
@BeforeClass
public static void startJettyServer() throws Exception {
int port = FreePortScanner.getFreePort();
int port = SocketUtils.findAvailableTcpPort();
jettyServer = new Server(port);
baseUrl = "http://localhost:" + port;

View File

@@ -1,99 +0,0 @@
/*
* Copyright 2002-2012 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.tests.web;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.util.Random;
import org.springframework.util.Assert;
/**
* Utility class that finds free BSD ports for use in testing scenario's.
*
* @author Ben Hale
* @author Arjen Poutsma
*/
public abstract class FreePortScanner {
private static final int MIN_SAFE_PORT = 1024;
private static final int MAX_PORT = 65535;
private static final Random random = new Random();
/**
* Returns the number of a free port in the default range.
*/
public static int getFreePort() {
return getFreePort(MIN_SAFE_PORT, MAX_PORT);
}
/**
* Returns the number of a free port in the given range.
*/
public static int getFreePort(int minPort, int maxPort) {
Assert.isTrue(minPort > 0, "'minPort' must be larger than 0");
Assert.isTrue(maxPort > minPort, "'maxPort' must be larger than minPort");
int portRange = maxPort - minPort;
int candidatePort;
int searchCounter = 0;
do {
if (++searchCounter > portRange) {
throw new IllegalStateException(
String.format("There were no ports available in the range %d to %d", minPort, maxPort));
}
candidatePort = getRandomPort(minPort, portRange);
}
while (!isPortAvailable(candidatePort));
return candidatePort;
}
private static int getRandomPort(int minPort, int portRange) {
return minPort + random.nextInt(portRange);
}
private static boolean isPortAvailable(int port) {
ServerSocket serverSocket;
try {
serverSocket = new ServerSocket();
}
catch (IOException ex) {
throw new IllegalStateException("Unable to create ServerSocket.", ex);
}
try {
InetSocketAddress sa = new InetSocketAddress(port);
serverSocket.bind(sa);
return true;
}
catch (IOException ex) {
return false;
}
finally {
try {
serverSocket.close();
}
catch (IOException ex) {
// ignore
}
}
}
}

View File

@@ -16,14 +16,6 @@
package org.springframework.web.client;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URI;
@@ -63,10 +55,12 @@ import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.tests.web.FreePortScanner;
import org.springframework.util.FileCopyUtils;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.util.SocketUtils;
import static org.junit.Assert.*;
/** @author Arjen Poutsma */
public class RestTemplateIntegrationTests {
@@ -83,7 +77,7 @@ public class RestTemplateIntegrationTests {
@BeforeClass
public static void startJettyServer() throws Exception {
int port = FreePortScanner.getFreePort();
int port = SocketUtils.findAvailableTcpPort();
jettyServer = new Server(port);
baseUrl = "http://localhost:" + port;
ServletContextHandler handler = new ServletContextHandler();
@@ -243,6 +237,7 @@ public class RestTemplateIntegrationTests {
}
@Test
@SuppressWarnings("unchecked")
public void exchangeGet() throws Exception {
HttpHeaders requestHeaders = new HttpHeaders();
requestHeaders.set("MyHeader", "MyValue");

View File

@@ -20,7 +20,7 @@ import org.junit.Test;
import org.springframework.web.context.request.async.DeferredResult.DeferredResultHandler;
import static org.junit.Assert.*;
import static org.mockito.BDDMockito.*;
import static org.mockito.Mockito.*;
/**
* DeferredResult tests.
@@ -69,6 +69,21 @@ public class DeferredResultTests {
verify(handler).handleResult("hello");
}
@Test
public void hasResult() {
DeferredResultHandler handler = mock(DeferredResultHandler.class);
DeferredResult<String> result = new DeferredResult<String>();
result.setResultHandler(handler);
assertFalse(result.hasResult());
assertNull(result.getResult());
result.setResult("hello");
assertEquals("hello", result.getResult());
}
@Test
public void onCompletion() throws Exception {
final StringBuilder sb = new StringBuilder();

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,6 +49,7 @@ import static org.junit.Assert.*;
import static org.mockito.BDDMockito.*;
import static org.mockito.Mockito.*;
/**
* Test fixture with {@link org.springframework.web.method.annotation.RequestParamMethodArgumentResolver}.
*
@@ -70,6 +71,7 @@ public class RequestParamMethodArgumentResolverTests {
private MethodParameter paramServlet30Part;
private MethodParameter paramRequestPartAnnot;
private MethodParameter paramRequired;
private MethodParameter paramNotRequired;
private NativeWebRequest webRequest;
@@ -81,8 +83,10 @@ public class RequestParamMethodArgumentResolverTests {
ParameterNameDiscoverer paramNameDiscoverer = new LocalVariableTableParameterNameDiscoverer();
Method method = getClass().getMethod("params", String.class, String[].class, Map.class, MultipartFile.class,
Map.class, String.class, MultipartFile.class, List.class, Part.class, MultipartFile.class, String.class);
Method method = getClass().getMethod("params", String.class, String[].class,
Map.class, MultipartFile.class, Map.class, String.class,
MultipartFile.class, List.class, Part.class, MultipartFile.class,
String.class, String.class);
paramNamedDefaultValueString = new MethodParameter(method, 0);
paramNamedStringArray = new MethodParameter(method, 1);
@@ -99,6 +103,7 @@ public class RequestParamMethodArgumentResolverTests {
paramServlet30Part.initParameterNameDiscovery(paramNameDiscoverer);
paramRequestPartAnnot = new MethodParameter(method, 9);
paramRequired = new MethodParameter(method, 10);
paramNotRequired = new MethodParameter(method, 11);
request = new MockHttpServletRequest();
webRequest = new ServletWebRequest(request, new MockHttpServletResponse());
@@ -243,9 +248,9 @@ public class RequestParamMethodArgumentResolverTests {
fail("Expected exception");
}
// SPR-10402
// SPR-10578
@Test(expected = MissingServletRequestParameterException.class)
@Test
public void missingRequestParamEmptyValueConvertedToNull() throws Exception {
WebDataBinder binder = new WebRequestDataBinder(null);
@@ -256,8 +261,25 @@ public class RequestParamMethodArgumentResolverTests {
this.request.addParameter("stringNotAnnot", "");
resolver.resolveArgument(paramStringNotAnnot, null, webRequest, binderFactory);
fail("Expected exception");
Object arg = resolver.resolveArgument(paramStringNotAnnot, null, webRequest, binderFactory);
assertNull(arg);
}
@Test
public void missingRequestParamEmptyValueNotRequired() throws Exception {
WebDataBinder binder = new WebRequestDataBinder(null);
binder.registerCustomEditor(String.class, new StringTrimmerEditor(true));
WebDataBinderFactory binderFactory = mock(WebDataBinderFactory.class);
given(binderFactory.createBinder(webRequest, null, "name")).willReturn(binder);
this.request.addParameter("name", "");
Object arg = resolver.resolveArgument(paramNotRequired, null, webRequest, binderFactory);
assertNull(arg);
}
@Test
@@ -311,7 +333,8 @@ public class RequestParamMethodArgumentResolverTests {
List<MultipartFile> multipartFileList,
Part servlet30Part,
@RequestPart MultipartFile requestPartAnnot,
@RequestParam(value = "name") String paramRequired) {
@RequestParam(value = "name") String paramRequired,
@RequestParam(value = "name", required=false) String paramNotRequired) {
}
}