Compare commits

...

20 Commits

Author SHA1 Message Date
Spring Buildmaster 8e0d8f99e2 Release version 4.3.30.RELEASE 2020-12-09 08:31:43 +00:00
Juergen Hoeller 0b076b28f1 Remove duplicate "property" in PropertyCacheKey.toString()
Closes gh-26237
2020-12-08 15:14:28 +01:00
Juergen Hoeller 0abb17af9d Polishing (aligned with 5.1.x) 2020-12-08 15:14:08 +01:00
Juergen Hoeller d5a80d2777 Polishing (aligned with 5.2.x) 2020-12-02 17:52:40 +01:00
Rossen Stoyanchev 07455c8a27 ContentCachingResponseWrapper skips contentLength for chunked responses
Closes gh-26182
2020-12-01 20:28:00 +00:00
Juergen Hoeller c45c67203c Add Maven Central repository (aligned with 5.1.x) 2020-11-26 16:10:26 +01:00
Juergen Hoeller aeb83fe1a3 Remove misleading default note on ISO.DATE_TIME
Closes gh-26134

(cherry picked from commit 86f9716fef)
2020-11-26 16:09:13 +01:00
Rossen Stoyanchev 0bf002dbe1 Fix 401 errors from artifactory 2020-11-16 13:49:41 +00:00
Rossen Stoyanchev 4ff521d769 UrlPathHelper.removeJsessionid correctly appends remainder
Closes gh-26079
2020-11-16 11:31:24 +00:00
Juergen Hoeller 9107aed878 Refined SqlParameterSource batchUpdate tests (plus related polishing)
See gh-26071
2020-11-12 14:43:11 +01:00
Juergen Hoeller 4ba174311b Polishing 2020-11-09 14:22:06 +01:00
Juergen Hoeller 09c8586ee4 Polishing 2020-11-05 19:05:47 +01:00
Juergen Hoeller 8212151f16 Suppress NotWritablePropertyException in case of ignoreUnknown=true
Closes gh-25986
2020-11-05 19:05:39 +01:00
Juergen Hoeller 65577671bc Polishing 2020-10-26 18:28:49 +01:00
Rossen Stoyanchev d1d37534bf Reinstate removal of jsessionid from lookup path
Closes gh-25864
2020-10-13 16:55:44 +01:00
Juergen Hoeller 45322a72a5 Polishing 2020-10-13 01:22:39 +02:00
Juergen Hoeller 678ea4ece7 Avoid creation of unused logger instance in AbstractMediaTypeExpression
Closes gh-25901
2020-10-13 01:20:34 +02:00
Juergen Hoeller bacf6ca37b Polishing 2020-10-07 15:03:26 +02:00
Juergen Hoeller 95c0f1108f Construct StringWriter instances with appropriate initial size
Closes gh-25789
2020-10-07 15:02:50 +02:00
Spring Buildmaster 06c76d8075 Next Development Version 2020-09-15 10:51:10 +00:00
47 changed files with 490 additions and 269 deletions
+3 -1
View File
@@ -1,5 +1,6 @@
buildscript {
repositories {
gradlePluginPortal()
maven { url "https://repo.spring.io/plugins-release" }
}
dependencies {
@@ -129,7 +130,8 @@ configure(allprojects) { project ->
}
repositories {
maven { url "https://repo.spring.io/libs-release" }
mavenCentral()
maven { url "https://repo.spring.io/libs-spring-framework-build" }
}
dependencies {
+1 -1
View File
@@ -1 +1 @@
version=4.3.29.BUILD-SNAPSHOT
version=4.3.30.RELEASE
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2020 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.
@@ -212,10 +212,12 @@ public class MethodInvocationProceedingJoinPoint implements ProceedingJoinPoint,
@Override
public String[] getParameterNames() {
if (this.parameterNames == null) {
this.parameterNames = parameterNameDiscoverer.getParameterNames(getMethod());
String[] parameterNames = this.parameterNames;
if (parameterNames == null) {
parameterNames = parameterNameDiscoverer.getParameterNames(getMethod());
this.parameterNames = parameterNames;
}
return this.parameterNames;
return parameterNames;
}
@Override
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2020 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.
@@ -431,9 +431,12 @@ public abstract class AbstractNestablePropertyAccessor extends AbstractPropertyA
}
return;
}
else {
throw createNotWritablePropertyException(tokens.canonicalName);
if (this.suppressNotWritablePropertyException) {
// Optimization for common ignoreUnknown=true scenario since the
// exception would be caught and swallowed higher up anyway...
return;
}
throw createNotWritablePropertyException(tokens.canonicalName);
}
Object oldValue = null;
@@ -815,7 +818,6 @@ public abstract class AbstractNestablePropertyAccessor extends AbstractPropertyA
* @param propertyPath property path, which may be nested
* @return a property accessor for the target bean
*/
@SuppressWarnings("unchecked") // avoid nested generic
protected AbstractNestablePropertyAccessor getPropertyAccessorForPropertyPath(String propertyPath) {
int pos = PropertyAccessorUtils.getFirstNestedPropertySeparatorIndex(propertyPath);
// Handle nested properties recursively.
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2020 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.
@@ -38,6 +38,8 @@ public abstract class AbstractPropertyAccessor extends TypeConverterSupport impl
private boolean autoGrowNestedPaths = false;
boolean suppressNotWritablePropertyException = false;
@Override
public void setExtractOldValueForEditor(boolean extractOldValueForEditor) {
@@ -87,30 +89,41 @@ public abstract class AbstractPropertyAccessor extends TypeConverterSupport impl
List<PropertyAccessException> propertyAccessExceptions = null;
List<PropertyValue> propertyValues = (pvs instanceof MutablePropertyValues ?
((MutablePropertyValues) pvs).getPropertyValueList() : Arrays.asList(pvs.getPropertyValues()));
for (PropertyValue pv : propertyValues) {
try {
// This method may throw any BeansException, which won't be caught
if (ignoreUnknown) {
this.suppressNotWritablePropertyException = true;
}
try {
for (PropertyValue pv : propertyValues) {
// setPropertyValue may throw any BeansException, which won't be caught
// here, if there is a critical failure such as no matching field.
// We can attempt to deal only with less serious exceptions.
setPropertyValue(pv);
}
catch (NotWritablePropertyException ex) {
if (!ignoreUnknown) {
throw ex;
try {
setPropertyValue(pv);
}
// Otherwise, just ignore it and continue...
}
catch (NullValueInNestedPathException ex) {
if (!ignoreInvalid) {
throw ex;
catch (NotWritablePropertyException ex) {
if (!ignoreUnknown) {
throw ex;
}
// Otherwise, just ignore it and continue...
}
// Otherwise, just ignore it and continue...
}
catch (PropertyAccessException ex) {
if (propertyAccessExceptions == null) {
propertyAccessExceptions = new LinkedList<PropertyAccessException>();
catch (NullValueInNestedPathException ex) {
if (!ignoreInvalid) {
throw ex;
}
// Otherwise, just ignore it and continue...
}
propertyAccessExceptions.add(ex);
catch (PropertyAccessException ex) {
if (propertyAccessExceptions == null) {
propertyAccessExceptions = new LinkedList<PropertyAccessException>();
}
propertyAccessExceptions.add(ex);
}
}
}
finally {
if (ignoreUnknown) {
this.suppressNotWritablePropertyException = false;
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2020 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.
@@ -69,7 +69,7 @@ public class BeanWrapperImpl extends AbstractNestablePropertyAccessor implements
private CachedIntrospectionResults cachedIntrospectionResults;
/**
* The security context used for invoking the property methods
* The security context used for invoking the property methods.
*/
private AccessControlContext acc;
@@ -95,7 +95,7 @@ public class BeanWrapperImpl extends AbstractNestablePropertyAccessor implements
/**
* Create a new BeanWrapperImpl for the given object.
* @param object object wrapped by this BeanWrapper
* @param object the object wrapped by this BeanWrapper
*/
public BeanWrapperImpl(Object object) {
super(object);
@@ -112,7 +112,7 @@ public class BeanWrapperImpl extends AbstractNestablePropertyAccessor implements
/**
* Create a new BeanWrapperImpl for the given object,
* registering a nested path that the object is in.
* @param object object wrapped by this BeanWrapper
* @param object the object wrapped by this BeanWrapper
* @param nestedPath the nested path of the object
* @param rootObject the root object at the top of the path
*/
@@ -123,7 +123,7 @@ public class BeanWrapperImpl extends AbstractNestablePropertyAccessor implements
/**
* Create a new BeanWrapperImpl for the given object,
* registering a nested path that the object is in.
* @param object object wrapped by this BeanWrapper
* @param object the object wrapped by this BeanWrapper
* @param nestedPath the nested path of the object
* @param parent the containing BeanWrapper (must not be {@code null})
*/
@@ -164,7 +164,7 @@ public class BeanWrapperImpl extends AbstractNestablePropertyAccessor implements
}
/**
* Obtain a lazily initializted CachedIntrospectionResults instance
* Obtain a lazily initialized CachedIntrospectionResults instance
* for the wrapped object.
*/
private CachedIntrospectionResults getCachedIntrospectionResults() {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2020 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.
@@ -51,7 +51,7 @@ public class DirectFieldAccessor extends AbstractNestablePropertyAccessor {
/**
* Create a new DirectFieldAccessor for the given object.
* @param object object wrapped by this DirectFieldAccessor
* @param object the object wrapped by this DirectFieldAccessor
*/
public DirectFieldAccessor(Object object) {
super(object);
@@ -60,7 +60,7 @@ public class DirectFieldAccessor extends AbstractNestablePropertyAccessor {
/**
* Create a new DirectFieldAccessor for the given object,
* registering a nested path that the object is in.
* @param object object wrapped by this DirectFieldAccessor
* @param object the object wrapped by this DirectFieldAccessor
* @param nestedPath the nested path of the object
* @param parent the containing DirectFieldAccessor (must not be {@code null})
*/
@@ -90,8 +90,7 @@ public class DirectFieldAccessor extends AbstractNestablePropertyAccessor {
@Override
protected NotWritablePropertyException createNotWritablePropertyException(String propertyName) {
PropertyMatches matches = PropertyMatches.forField(propertyName, getRootClass());
throw new NotWritablePropertyException(
getRootClass(), getNestedPath() + propertyName,
throw new NotWritablePropertyException(getRootClass(), getNestedPath() + propertyName,
matches.buildErrorMessage(), matches.getPossibleMatches());
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2020 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 abstract class FreeMarkerTemplateUtils {
public static String processTemplateIntoString(Template template, Object model)
throws IOException, TemplateException {
StringWriter result = new StringWriter();
StringWriter result = new StringWriter(1024);
template.process(model, result);
return result.toString();
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2020 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.
@@ -105,7 +105,6 @@ public @interface DateTimeFormat {
/**
* The most common ISO DateTime Format {@code yyyy-MM-dd'T'HH:mm:ss.SSSZ},
* e.g. "2000-10-31T01:30:00.000-05:00".
* <p>This is the default if no annotation value is specified.
*/
DATE_TIME,
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -35,10 +35,11 @@ import org.springframework.jndi.JndiTemplate;
*
* @author Juergen Hoeller
* @since 4.0
* @see javax.enterprise.concurrent.ManagedScheduledExecutorService
*/
public class DefaultManagedTaskScheduler extends ConcurrentTaskScheduler implements InitializingBean {
private JndiLocatorDelegate jndiLocator = new JndiLocatorDelegate();
private final JndiLocatorDelegate jndiLocator = new JndiLocatorDelegate();
private String jndiName = "java:comp/DefaultManagedScheduledExecutorService";
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 the original author or authors.
* Copyright 2002-2020 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.
@@ -503,7 +503,7 @@ public class GenericConversionService implements ConfigurableConversionService {
private final Set<GenericConverter> globalConverters = new LinkedHashSet<GenericConverter>();
private final Map<ConvertiblePair, ConvertersForPair> converters =
new LinkedHashMap<ConvertiblePair, ConvertersForPair>(36);
new LinkedHashMap<ConvertiblePair, ConvertersForPair>(256);
public void add(GenericConverter converter) {
Set<ConvertiblePair> convertibleTypes = converter.getConvertibleTypes();
@@ -514,8 +514,7 @@ public class GenericConversionService implements ConfigurableConversionService {
}
else {
for (ConvertiblePair convertiblePair : convertibleTypes) {
ConvertersForPair convertersForPair = getMatchableConverters(convertiblePair);
convertersForPair.add(converter);
getMatchableConverters(convertiblePair).add(converter);
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -40,9 +40,13 @@ import java.io.Writer;
* @author Juergen Hoeller
* @since 06.10.2003
* @see StreamUtils
* @see FileSystemUtils
*/
public abstract class FileCopyUtils {
/**
* The default buffer size used when copying bytes.
*/
public static final int BUFFER_SIZE = StreamUtils.BUFFER_SIZE;
@@ -184,15 +188,15 @@ public abstract class FileCopyUtils {
Assert.notNull(out, "No Writer specified");
try {
int byteCount = 0;
int charCount = 0;
char[] buffer = new char[BUFFER_SIZE];
int bytesRead = -1;
while ((bytesRead = in.read(buffer)) != -1) {
out.write(buffer, 0, bytesRead);
byteCount += bytesRead;
int charsRead;
while ((charsRead = in.read(buffer)) != -1) {
out.write(buffer, 0, charsRead);
charCount += charsRead;
}
out.flush();
return byteCount;
return charCount;
}
finally {
try {
@@ -209,7 +213,7 @@ public abstract class FileCopyUtils {
}
/**
* Copy the contents of the given String to the given output Writer.
* Copy the contents of the given String to the given Writer.
* Closes the writer when done.
* @param in the String to copy from
* @param out the Writer to copy to
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2020 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.
@@ -193,7 +193,7 @@ public class MimeType implements Comparable<MimeType>, Serializable {
* @see <a href="https://tools.ietf.org/html/rfc2616#section-2.2">HTTP 1.1, section 2.2</a>
*/
private void checkToken(String token) {
for (int i = 0; i < token.length(); i++ ) {
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 \"" + token + "\"");
@@ -206,8 +206,7 @@ public class MimeType implements Comparable<MimeType>, Serializable {
Assert.hasLength(value, "'value' must not be empty");
checkToken(attribute);
if (PARAM_CHARSET.equals(attribute)) {
value = unquote(value);
Charset.forName(value);
Charset.forName(unquote(value));
}
else if (!isQuotedString(value)) {
checkToken(value);
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -43,6 +43,9 @@ import java.nio.charset.Charset;
*/
public abstract class StreamUtils {
/**
* The default buffer size used when copying bytes.
*/
public static final int BUFFER_SIZE = 4096;
private static final byte[] EMPTY_CONTENT = new byte[0];
@@ -50,7 +53,7 @@ public abstract class StreamUtils {
/**
* Copy the contents of the given InputStream into a new byte array.
* Leaves the stream open when done.
* <p>Leaves the stream open when done.
* @param in the stream to copy from (may be {@code null} or empty)
* @return the new byte array that has been copied to (possibly empty)
* @throws IOException in case of I/O errors
@@ -67,8 +70,9 @@ public abstract class StreamUtils {
/**
* Copy the contents of the given InputStream into a String.
* Leaves the stream open when done.
* <p>Leaves the stream open when done.
* @param in the InputStream to copy from (may be {@code null} or empty)
* @param charset the {@link Charset} to use to decode the bytes
* @return the String that has been copied to (possibly empty)
* @throws IOException in case of I/O errors
*/
@@ -77,19 +81,19 @@ public abstract class StreamUtils {
return "";
}
StringBuilder out = new StringBuilder();
StringBuilder out = new StringBuilder(BUFFER_SIZE);
InputStreamReader reader = new InputStreamReader(in, charset);
char[] buffer = new char[BUFFER_SIZE];
int bytesRead = -1;
while ((bytesRead = reader.read(buffer)) != -1) {
out.append(buffer, 0, bytesRead);
int charsRead;
while ((charsRead = reader.read(buffer)) != -1) {
out.append(buffer, 0, charsRead);
}
return out.toString();
}
/**
* Copy the contents of the given byte array to the given OutputStream.
* Leaves the stream open when done.
* <p>Leaves the stream open when done.
* @param in the byte array to copy from
* @param out the OutputStream to copy to
* @throws IOException in case of I/O errors
@@ -99,11 +103,12 @@ public abstract class StreamUtils {
Assert.notNull(out, "No OutputStream specified");
out.write(in);
out.flush();
}
/**
* Copy the contents of the given String to the given output OutputStream.
* Leaves the stream open when done.
* Copy the contents of the given String to the given OutputStream.
* <p>Leaves the stream open when done.
* @param in the String to copy from
* @param charset the Charset
* @param out the OutputStream to copy to
@@ -111,7 +116,7 @@ public abstract class StreamUtils {
*/
public static void copy(String in, Charset charset, OutputStream out) throws IOException {
Assert.notNull(in, "No input String specified");
Assert.notNull(charset, "No charset specified");
Assert.notNull(charset, "No Charset specified");
Assert.notNull(out, "No OutputStream specified");
Writer writer = new OutputStreamWriter(out, charset);
@@ -121,7 +126,7 @@ public abstract class StreamUtils {
/**
* Copy the contents of the given InputStream to the given OutputStream.
* Leaves both streams open when done.
* <p>Leaves both streams open when done.
* @param in the InputStream to copy from
* @param out the OutputStream to copy to
* @return the number of bytes copied
@@ -133,7 +138,7 @@ public abstract class StreamUtils {
int byteCount = 0;
byte[] buffer = new byte[BUFFER_SIZE];
int bytesRead = -1;
int bytesRead;
while ((bytesRead = in.read(buffer)) != -1) {
out.write(buffer, 0, bytesRead);
byteCount += bytesRead;
@@ -165,7 +170,7 @@ public abstract class StreamUtils {
}
long bytesToCopy = end - start + 1;
byte[] buffer = new byte[StreamUtils.BUFFER_SIZE];
byte[] buffer = new byte[(int) Math.min(StreamUtils.BUFFER_SIZE, bytesToCopy)];
while (bytesToCopy > 0) {
int bytesRead = in.read(buffer);
if (bytesRead == -1) {
@@ -185,7 +190,7 @@ public abstract class StreamUtils {
/**
* Drain the remaining content of the given InputStream.
* Leaves the InputStream open when done.
* <p>Leaves the InputStream open when done.
* @param in the InputStream to drain
* @return the number of bytes read
* @throws IOException in case of I/O errors
@@ -255,7 +260,7 @@ public abstract class StreamUtils {
@Override
public void write(byte[] b, int off, int let) throws IOException {
// It is critical that we override this method for performance
out.write(b, off, let);
this.out.write(b, off, let);
}
@Override
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2020 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.
@@ -45,7 +45,7 @@ import org.springframework.util.StringUtils;
/**
* A powerful {@link PropertyAccessor} that uses reflection to access properties
* for reading and possibly also for writing.
* for reading and possibly also for writing on a target instance.
*
* <p>A property can be referenced through a public getter method (when being read)
* or a public setter method (when being written), and also as a public field.
@@ -98,8 +98,8 @@ public class ReflectivePropertyAccessor implements PropertyAccessor {
}
/**
* Create a new property accessor for reading and possibly writing.
* @param allowWrite whether to also allow for write operations
* Create a new property accessor for reading and possibly also writing.
* @param allowWrite whether to allow write operations on a target instance
* @since 4.3.15
* @see #canWrite
*/
@@ -619,8 +619,8 @@ public class ReflectivePropertyAccessor implements PropertyAccessor {
@Override
public String toString() {
return "CacheKey [clazz=" + this.clazz.getName() + ", property=" + this.property + ", " +
this.property + ", targetIsClass=" + this.targetIsClass + "]";
return "PropertyCacheKey [clazz=" + this.clazz.getName() + ", property=" + this.property +
", targetIsClass=" + this.targetIsClass + "]";
}
@Override
@@ -644,6 +644,9 @@ public class ReflectivePropertyAccessor implements PropertyAccessor {
*/
public static class OptimalPropertyAccessor implements CompilablePropertyAccessor {
/**
* The member being accessed.
*/
public final Member member;
private final TypeDescriptor typeDescriptor;
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2020 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.
@@ -31,7 +31,6 @@ import java.util.Set;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.jdbc.support.nativejdbc.NativeJdbcExtractor;
import org.springframework.util.Assert;
/**
* Helper class that efficiently creates multiple {@link PreparedStatementCreator}
@@ -201,10 +200,9 @@ public class PreparedStatementCreatorFactory {
public PreparedStatementCreatorImpl(String actualSql, List<?> parameters) {
this.actualSql = actualSql;
Assert.notNull(parameters, "Parameters List must not be null");
this.parameters = parameters;
if (this.parameters.size() != declaredParameters.size()) {
// account for named parameters being used multiple times
if (parameters.size() != declaredParameters.size()) {
// Account for named parameters being used multiple times
Set<String> names = new HashSet<String>();
for (int i = 0; i < parameters.size(); i++) {
Object param = parameters.get(i);
@@ -278,7 +276,7 @@ public class PreparedStatementCreatorFactory {
Collection<?> entries = (Collection<?>) in;
for (Object entry : entries) {
if (entry instanceof Object[]) {
Object[] valueArray = ((Object[])entry);
Object[] valueArray = ((Object[]) entry);
for (Object argValue : valueArray) {
StatementCreatorUtils.setParameterValue(psToUse, sqlColIndx++, declaredParameter, argValue);
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2020 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.
@@ -34,7 +34,7 @@ public interface SqlProvider {
/**
* Return the SQL string for this object, i.e.
* typically the SQL used for creating statements.
* @return the SQL string, or {@code null}
* @return the SQL string, or {@code null} if not available
*/
String getSql();
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2008 the original author or authors.
* Copyright 2002-2020 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.
@@ -28,11 +28,11 @@ import java.util.List;
*/
public class ParsedSql {
private String originalSql;
private final String originalSql;
private List<String> parameterNames = new ArrayList<String>();
private final List<String> parameterNames = new ArrayList<String>();
private List<int[]> parameterIndexes = new ArrayList<int[]>();
private final List<int[]> parameterIndexes = new ArrayList<int[]>();
private int namedParameterCount;
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2020 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.
@@ -26,6 +26,7 @@ import org.springframework.jdbc.core.SqlParameterValue;
* in particular with {@link NamedParameterJdbcTemplate}.
*
* @author Thomas Risberg
* @author Juergen Hoeller
* @since 2.5
*/
public class SqlParameterSourceUtils {
@@ -67,16 +68,12 @@ public class SqlParameterSourceUtils {
* @param source the source of parameter values and type information
* @param parameterName the name of the parameter
* @return the value object
* @see SqlParameterValue
*/
public static Object getTypedValue(SqlParameterSource source, String parameterName) {
int sqlType = source.getSqlType(parameterName);
if (sqlType != SqlParameterSource.TYPE_UNKNOWN) {
if (source.getTypeName(parameterName) != null) {
return new SqlParameterValue(sqlType, source.getTypeName(parameterName), source.getValue(parameterName));
}
else {
return new SqlParameterValue(sqlType, source.getValue(parameterName));
}
return new SqlParameterValue(sqlType, source.getTypeName(parameterName), source.getValue(parameterName));
}
else {
return source.getValue(parameterName);
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2020 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.
@@ -431,10 +431,11 @@ public class NamedParameterJdbcTemplateTests {
@Test
public void testBatchUpdateWithSqlParameterSourcePlusTypeInfo() throws Exception {
SqlParameterSource[] ids = new SqlParameterSource[2];
ids[0] = new MapSqlParameterSource().addValue("id", 100, Types.NUMERIC);
ids[1] = new MapSqlParameterSource().addValue("id", 200, Types.NUMERIC);
final int[] rowsAffected = new int[] {1, 2};
SqlParameterSource[] ids = new SqlParameterSource[3];
ids[0] = new MapSqlParameterSource().addValue("id", null, Types.NULL);
ids[1] = new MapSqlParameterSource().addValue("id", 100, Types.NUMERIC);
ids[2] = new MapSqlParameterSource().addValue("id", 200, Types.NUMERIC);
final int[] rowsAffected = new int[] {1, 2, 3};
given(preparedStatement.executeBatch()).willReturn(rowsAffected);
given(connection.getMetaData()).willReturn(databaseMetaData);
@@ -442,13 +443,15 @@ public class NamedParameterJdbcTemplateTests {
int[] actualRowsAffected = namedParameterTemplate.batchUpdate(
"UPDATE NOSUCHTABLE SET DATE_DISPATCHED = SYSDATE WHERE ID = :id", ids);
assertTrue("executed 2 updates", actualRowsAffected.length == 2);
assertTrue("executed 3 updates", actualRowsAffected.length == 3);
assertEquals(rowsAffected[0], actualRowsAffected[0]);
assertEquals(rowsAffected[1], actualRowsAffected[1]);
assertEquals(rowsAffected[2], actualRowsAffected[2]);
verify(connection).prepareStatement("UPDATE NOSUCHTABLE SET DATE_DISPATCHED = SYSDATE WHERE ID = ?");
verify(preparedStatement).setNull(1, Types.NULL);
verify(preparedStatement).setObject(1, 100, Types.NUMERIC);
verify(preparedStatement).setObject(1, 200, Types.NUMERIC);
verify(preparedStatement, times(2)).addBatch();
verify(preparedStatement, times(3)).addBatch();
verify(preparedStatement, atLeastOnce()).close();
verify(connection, atLeastOnce()).close();
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 the original author or authors.
* Copyright 2002-2020 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.
@@ -117,7 +117,7 @@ public class MappingJackson2MessageConverter implements SmartMessageConverter, B
/**
* Specify the encoding to use when converting to and from text-based
* message body content. The default encoding will be "UTF-8".
* <p>When reading from a a text-based message, an encoding may have been
* <p>When reading from a text-based message, an encoding may have been
* suggested through a special JMS property which will then be preferred
* over the encoding set on this MessageConverter instance.
* @see #setEncodingPropertyName
@@ -283,13 +283,13 @@ public class MappingJackson2MessageConverter implements SmartMessageConverter, B
* @return the resulting message
* @throws JMSException if thrown by JMS methods
* @throws IOException in case of I/O errors
* @see Session#createBytesMessage
* @since 4.3
* @see Session#createBytesMessage
*/
protected TextMessage mapToTextMessage(Object object, Session session, ObjectWriter objectWriter)
throws JMSException, IOException {
StringWriter writer = new StringWriter();
StringWriter writer = new StringWriter(1024);
objectWriter.writeValue(writer, object);
return session.createTextMessage(writer.toString());
}
@@ -386,7 +386,7 @@ public class MappingJackson2MessageConverter implements SmartMessageConverter, B
* sets the resulting value (either a mapped id or the raw Java class name)
* into the configured type id message property.
* @param object the payload object to set a type id for
* @param message the JMS Message to set the type id on
* @param message the JMS Message on which to set the type id property
* @throws JMSException if thrown by JMS methods
* @see #getJavaTypeForMessage(javax.jms.Message)
* @see #setTypeIdPropertyName(String)
@@ -482,7 +482,7 @@ public class MappingJackson2MessageConverter implements SmartMessageConverter, B
* <p>The default implementation parses the configured type id property name
* and consults the configured type id mapping. This can be overridden with
* a different strategy, e.g. doing some heuristics based on message origin.
* @param message the JMS Message to set the type id on
* @param message the JMS Message from which to get the type id property
* @throws JMSException if thrown by JMS methods
* @see #setTypeIdOnMessage(Object, javax.jms.Message)
* @see #setTypeIdPropertyName(String)
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2020 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,8 +46,6 @@ import org.springframework.util.Assert;
* @author Arjen Poutsma
* @author Juergen Hoeller
* @since 3.0
* @see org.springframework.jms.core.JmsTemplate#convertAndSend
* @see org.springframework.jms.core.JmsTemplate#receiveAndConvert
*/
public class MarshallingMessageConverter implements MessageConverter, InitializingBean {
@@ -210,7 +208,7 @@ public class MarshallingMessageConverter implements MessageConverter, Initializi
protected TextMessage marshalToTextMessage(Object object, Session session, Marshaller marshaller)
throws JMSException, IOException, XmlMappingException {
StringWriter writer = new StringWriter();
StringWriter writer = new StringWriter(1024);
Result result = new StreamResult(writer);
marshaller.marshal(object, result);
return session.createTextMessage(writer.toString());
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2020 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.
@@ -149,20 +149,6 @@ public abstract class AbstractMessageConverter implements SmartMessageConverter
}
/**
* Returns the default content type for the payload. Called when
* {@link #toMessage(Object, MessageHeaders)} is invoked without message headers or
* without a content type header.
* <p>By default, this returns the first element of the {@link #getSupportedMimeTypes()
* supportedMimeTypes}, if any. Can be overridden in sub-classes.
* @param payload the payload being converted to message
* @return the content type, or {@code null} if not known
*/
protected MimeType getDefaultContentType(Object payload) {
List<MimeType> mimeTypes = getSupportedMimeTypes();
return (!mimeTypes.isEmpty() ? mimeTypes.get(0) : null);
}
@Override
public final Object fromMessage(Message<?> message, Class<?> targetClass) {
return fromMessage(message, targetClass, null);
@@ -176,10 +162,6 @@ public abstract class AbstractMessageConverter implements SmartMessageConverter
return convertFromInternal(message, targetClass, conversionHint);
}
protected boolean canConvertFrom(Message<?> message, Class<?> targetClass) {
return (supports(targetClass) && supportsMimeType(message.getHeaders()));
}
@Override
public final Message<?> toMessage(Object payload, MessageHeaders headers) {
return toMessage(payload, headers, null);
@@ -213,6 +195,11 @@ public abstract class AbstractMessageConverter implements SmartMessageConverter
return builder.build();
}
protected boolean canConvertFrom(Message<?> message, Class<?> targetClass) {
return (supports(targetClass) && supportsMimeType(message.getHeaders()));
}
protected boolean canConvertTo(Object payload, MessageHeaders headers) {
Class<?> clazz = (payload != null ? payload.getClass() : null);
return (supports(clazz) && supportsMimeType(headers));
@@ -238,6 +225,21 @@ public abstract class AbstractMessageConverter implements SmartMessageConverter
return (this.contentTypeResolver != null ? this.contentTypeResolver.resolve(headers) : null);
}
/**
* Return the default content type for the payload. Called when
* {@link #toMessage(Object, MessageHeaders)} is invoked without
* message headers or without a content type header.
* <p>By default, this returns the first element of the
* {@link #getSupportedMimeTypes() supportedMimeTypes}, if any.
* Can be overridden in subclasses.
* @param payload the payload being converted to a message
* @return the content type, or {@code null} if not known
*/
protected MimeType getDefaultContentType(Object payload) {
List<MimeType> mimeTypes = getSupportedMimeTypes();
return (!mimeTypes.isEmpty() ? mimeTypes.get(0) : null);
}
/**
* Whether the given class is supported by this converter.
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2020 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.
@@ -140,12 +140,13 @@ public class MappingJackson2MessageConverter extends AbstractMessageConverter {
}
}
@Override
protected boolean canConvertFrom(Message<?> message, Class<?> targetClass) {
if (targetClass == null || !supportsMimeType(message.getHeaders())) {
return false;
}
JavaType javaType = this.objectMapper.constructType(targetClass);
JavaType javaType = this.objectMapper.getTypeFactory().constructType(targetClass);
AtomicReference<Throwable> causeRef = new AtomicReference<Throwable>();
if (this.objectMapper.canDeserialize(javaType, causeRef)) {
return true;
@@ -221,6 +222,7 @@ public class MappingJackson2MessageConverter extends AbstractMessageConverter {
}
}
else {
// Assuming a text-based source payload
if (view != null) {
return this.objectMapper.readerWithView(view).forType(javaType).readValue(payload.toString());
}
@@ -243,10 +245,9 @@ public class MappingJackson2MessageConverter extends AbstractMessageConverter {
}
Type genericParameterType = param.getNestedGenericParameterType();
Class<?> contextClass = param.getContainingClass();
Type type = getJavaType(genericParameterType, contextClass);
return this.objectMapper.getTypeFactory().constructType(type);
return getJavaType(genericParameterType, contextClass);
}
return this.objectMapper.constructType(targetClass);
return this.objectMapper.getTypeFactory().constructType(targetClass);
}
private JavaType getJavaType(Type type, Class<?> contextClass) {
@@ -329,7 +330,8 @@ public class MappingJackson2MessageConverter extends AbstractMessageConverter {
payload = out.toByteArray();
}
else {
Writer writer = new StringWriter();
// Assuming a text-based target payload
Writer writer = new StringWriter(1024);
if (view != null) {
this.objectMapper.writerWithView(view).writeValue(writer, payload);
}
@@ -387,7 +389,7 @@ public class MappingJackson2MessageConverter extends AbstractMessageConverter {
* @return the JSON encoding to use (never {@code null})
*/
protected JsonEncoding getJsonEncoding(MimeType contentType) {
if ((contentType != null) && (contentType.getCharset() != null)) {
if (contentType != null && contentType.getCharset() != null) {
Charset charset = contentType.getCharset();
for (JsonEncoding encoding : JsonEncoding.values()) {
if (charset.name().equals(encoding.getJavaName())) {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2020 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.
@@ -45,6 +45,8 @@ import org.springframework.util.MimeType;
*
* @author Arjen Poutsma
* @since 4.2
* @see Marshaller
* @see Unmarshaller
*/
public class MarshallingMessageConverter extends AbstractMessageConverter {
@@ -58,7 +60,8 @@ public class MarshallingMessageConverter extends AbstractMessageConverter {
* {@link #setUnmarshaller(Unmarshaller)} to be invoked separately.
*/
public MarshallingMessageConverter() {
this(new MimeType("application", "xml"), new MimeType("text", "xml"), new MimeType("application", "*+xml"));
this(new MimeType("application", "xml"), new MimeType("text", "xml"),
new MimeType("application", "*+xml"));
}
/**
@@ -154,7 +157,7 @@ public class MarshallingMessageConverter extends AbstractMessageConverter {
return new StreamSource(new ByteArrayInputStream((byte[]) payload));
}
else {
return new StreamSource(new StringReader((String) payload));
return new StreamSource(new StringReader(payload.toString()));
}
}
@@ -163,13 +166,13 @@ public class MarshallingMessageConverter extends AbstractMessageConverter {
Assert.notNull(this.marshaller, "Property 'marshaller' is required");
try {
if (byte[].class == getSerializedPayloadClass()) {
ByteArrayOutputStream out = new ByteArrayOutputStream();
ByteArrayOutputStream out = new ByteArrayOutputStream(1024);
Result result = new StreamResult(out);
this.marshaller.marshal(payload, result);
payload = out.toByteArray();
}
else {
Writer writer = new StringWriter();
Writer writer = new StringWriter(1024);
Result result = new StreamResult(writer);
this.marshaller.marshal(payload, result);
payload = writer.toString();
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2020 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.
@@ -146,8 +146,9 @@ public abstract class AbstractNamedValueMethodArgumentResolver implements Handle
if (info.name.isEmpty()) {
name = parameter.getParameterName();
if (name == null) {
throw new IllegalArgumentException("Name for argument type [" + parameter.getParameterType().getName() +
"] not available, and parameter name information not found in class file either.");
throw new IllegalArgumentException(
"Name for argument of type [" + parameter.getNestedParameterType().getName() +
"] not specified, and parameter name information not found in class file either.");
}
}
String defaultValue = (ValueConstants.DEFAULT_NONE.equals(info.defaultValue) ? null : info.defaultValue);
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2020 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.
@@ -223,8 +223,8 @@ public class StompBrokerRelayRegistration extends AbstractBrokerRegistration {
}
@Override
protected StompBrokerRelayMessageHandler getMessageHandler(SubscribableChannel brokerChannel) {
StompBrokerRelayMessageHandler handler = new StompBrokerRelayMessageHandler(
getClientInboundChannel(), getClientOutboundChannel(),
brokerChannel, getDestinationPrefixes());
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2020 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.
@@ -654,8 +654,10 @@ public class DefaultStompSession implements ConnectionHandlingStompSession {
if (conn != null) {
conn.send(HEARTBEAT).addCallback(
new ListenableFutureCallback<Void>() {
@Override
public void onSuccess(Void result) {
}
@Override
public void onFailure(Throwable ex) {
handleFailure(ex);
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 the original author or authors.
* Copyright 2002-2020 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.
@@ -52,14 +52,14 @@ public class NativeMessageHeaderAccessor extends MessageHeaderAccessor {
/**
* A protected constructor to create new headers.
* Protected constructor to create a new instance.
*/
protected NativeMessageHeaderAccessor() {
this((Map<String, List<String>>) null);
}
/**
* A protected constructor to create new headers.
* Protected constructor to create an instance with the given native headers.
* @param nativeHeaders native headers to create the message with (may be {@code null})
*/
protected NativeMessageHeaderAccessor(Map<String, List<String>> nativeHeaders) {
@@ -69,7 +69,7 @@ public class NativeMessageHeaderAccessor extends MessageHeaderAccessor {
}
/**
* A protected constructor accepting the headers of an existing message to copy.
* Protected constructor that copies headers from another message.
*/
protected NativeMessageHeaderAccessor(Message<?> message) {
super(message);
@@ -84,13 +84,17 @@ public class NativeMessageHeaderAccessor extends MessageHeaderAccessor {
}
}
/**
* Subclasses can use this method to access the "native" headers sub-map.
*/
@SuppressWarnings("unchecked")
private Map<String, List<String>> getNativeHeaders() {
return (Map<String, List<String>>) getHeader(NATIVE_HEADERS);
}
/**
* Return a copy of the native header values or an empty map.
* Return a copy of the native headers sub-map, or an empty map.
*/
public Map<String, List<String>> toNativeHeaderMap() {
Map<String, List<String>> map = getNativeHeaders();
@@ -112,6 +116,7 @@ public class NativeMessageHeaderAccessor extends MessageHeaderAccessor {
/**
* Whether the native header map contains the give header name.
* @param headerName the name of the header
*/
public boolean containsNativeHeader(String headerName) {
Map<String, List<String>> map = getNativeHeaders();
@@ -119,7 +124,9 @@ public class NativeMessageHeaderAccessor extends MessageHeaderAccessor {
}
/**
* @return all values for the specified native header or {@code null}.
* Return all values for the specified native header, if present.
* @param headerName the name of the header
* @return the associated values, or {@code null} if none
*/
public List<String> getNativeHeader(String headerName) {
Map<String, List<String>> map = getNativeHeaders();
@@ -127,13 +134,15 @@ public class NativeMessageHeaderAccessor extends MessageHeaderAccessor {
}
/**
* @return the first value for the specified native header of {@code null}.
* Return the first value for the specified native header, if present.
* @param headerName the name of the header
* @return the associated value, or {@code null} if none
*/
public String getFirstNativeHeader(String headerName) {
Map<String, List<String>> map = getNativeHeaders();
if (map != null) {
List<String> values = map.get(headerName);
if (values != null) {
if (!CollectionUtils.isEmpty(values)) {
return values.get(0);
}
}
@@ -142,6 +151,8 @@ public class NativeMessageHeaderAccessor extends MessageHeaderAccessor {
/**
* Set the specified native header value replacing existing values.
* <p>In order for this to work, the accessor must be {@link #isMutable()
* mutable}. See {@link MessageHeaderAccessor} for details.
*/
public void setNativeHeader(String name, String value) {
Assert.state(isMutable(), "Already immutable");
@@ -167,6 +178,10 @@ public class NativeMessageHeaderAccessor extends MessageHeaderAccessor {
/**
* Add the specified native header value to existing values.
* <p>In order for this to work, the accessor must be {@link #isMutable()
* mutable}. See {@link MessageHeaderAccessor} for details.
* @param name the name of the header
* @param value the header value to set
*/
public void addNativeHeader(String name, String value) {
Assert.state(isMutable(), "Already immutable");
@@ -187,6 +202,10 @@ public class NativeMessageHeaderAccessor extends MessageHeaderAccessor {
setModified(true);
}
/**
* Add the specified native headers to existing values.
* @param headers the headers to set
*/
public void addNativeHeaders(MultiValueMap<String, String> headers) {
if (headers == null) {
return;
@@ -198,21 +217,36 @@ public class NativeMessageHeaderAccessor extends MessageHeaderAccessor {
}
}
public List<String> removeNativeHeader(String name) {
/**
* Remove the specified native header value replacing existing values.
* <p>In order for this to work, the accessor must be {@link #isMutable()
* mutable}. See {@link MessageHeaderAccessor} for details.
* @param headerName the name of the header
* @return the associated values, or {@code null} if the header was not present
*/
public List<String> removeNativeHeader(String headerName) {
Assert.state(isMutable(), "Already immutable");
Map<String, List<String>> nativeHeaders = getNativeHeaders();
if (nativeHeaders == null) {
if (CollectionUtils.isEmpty(nativeHeaders)) {
return null;
}
return nativeHeaders.remove(name);
return nativeHeaders.remove(headerName);
}
/**
* Return the first value for the specified native header,
* or {@code null} if none.
* @param headerName the name of the header
* @param headers the headers map to introspect
* @return the associated value, or {@code null} if none
*/
@SuppressWarnings("unchecked")
public static String getFirstNativeHeader(String headerName, Map<String, Object> headers) {
Map<String, List<String>> map = (Map<String, List<String>>) headers.get(NATIVE_HEADERS);
if (map != null) {
List<String> values = map.get(headerName);
if (values != null) {
if (!CollectionUtils.isEmpty(values)) {
return values.get(0);
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2020 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.messaging.converter;
import java.io.IOException;
import java.lang.reflect.Method;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
@@ -74,7 +73,7 @@ public class MappingJackson2MessageConverterTests {
}
@Test
public void fromMessage() throws Exception {
public void fromMessage() {
MappingJackson2MessageConverter converter = new MappingJackson2MessageConverter();
String payload = "{\"bytes\":\"AQI=\",\"array\":[\"Foo\",\"Bar\"],\"number\":42,\"string\":\"Foo\",\"bool\":true,\"fraction\":42.0}";
Message<?> message = MessageBuilder.withPayload(payload.getBytes(UTF_8)).build();
@@ -89,7 +88,7 @@ public class MappingJackson2MessageConverterTests {
}
@Test
public void fromMessageUntyped() throws Exception {
public void fromMessageUntyped() {
MappingJackson2MessageConverter converter = new MappingJackson2MessageConverter();
String payload = "{\"bytes\":\"AQI=\",\"array\":[\"Foo\",\"Bar\"],"
+ "\"number\":42,\"string\":\"Foo\",\"bool\":true,\"fraction\":42.0}";
@@ -106,7 +105,7 @@ public class MappingJackson2MessageConverterTests {
}
@Test(expected = MessageConversionException.class)
public void fromMessageInvalidJson() throws Exception {
public void fromMessageInvalidJson() {
MappingJackson2MessageConverter converter = new MappingJackson2MessageConverter();
String payload = "FooBar";
Message<?> message = MessageBuilder.withPayload(payload.getBytes(UTF_8)).build();
@@ -114,7 +113,7 @@ public class MappingJackson2MessageConverterTests {
}
@Test
public void fromMessageValidJsonWithUnknownProperty() throws IOException {
public void fromMessageValidJsonWithUnknownProperty() {
MappingJackson2MessageConverter converter = new MappingJackson2MessageConverter();
String payload = "{\"string\":\"string\",\"unknownProperty\":\"value\"}";
Message<?> message = MessageBuilder.withPayload(payload.getBytes(UTF_8)).build();
@@ -151,7 +150,7 @@ public class MappingJackson2MessageConverterTests {
}
@Test
public void toMessage() throws Exception {
public void toMessage() {
MappingJackson2MessageConverter converter = new MappingJackson2MessageConverter();
MyBean payload = new MyBean();
payload.setString("Foo");
@@ -239,11 +238,14 @@ public class MappingJackson2MessageConverterTests {
return bean;
}
public void jsonViewPayload(@JsonView(MyJacksonView2.class) JacksonViewBean payload) {}
public void jsonViewPayload(@JsonView(MyJacksonView2.class) JacksonViewBean payload) {
}
void handleList(List<Long> payload) {}
void handleList(List<Long> payload) {
}
void handleMessage(Message<MyBean> message) {}
void handleMessage(Message<MyBean> message) {
}
public static class MyBean {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2020 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 org.springframework.http.HttpOutputMessage;
import org.springframework.http.MediaType;
/**
* Strategy interface that specifies a converter that can convert from and to HTTP requests and responses.
* Strategy interface for converting from and to HTTP requests and responses.
*
* @author Arjen Poutsma
* @author Juergen Hoeller
@@ -52,7 +52,7 @@ public interface HttpMessageConverter<T> {
/**
* Return the list of {@link MediaType} objects supported by this converter.
* @return the list of supported media types
* @return the list of supported media types, potentially an immutable copy
*/
List<MediaType> getSupportedMediaTypes();
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2020 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.
@@ -126,7 +126,6 @@ public abstract class AbstractNamedValueMethodArgumentResolver implements Handle
catch (TypeMismatchException ex) {
throw new MethodArgumentTypeMismatchException(arg, ex.getRequiredType(),
namedValueInfo.name, parameter, ex.getCause());
}
}
@@ -165,8 +164,8 @@ public abstract class AbstractNamedValueMethodArgumentResolver implements Handle
name = parameter.getParameterName();
if (name == null) {
throw new IllegalArgumentException(
"Name for argument type [" + parameter.getNestedParameterType().getName() +
"] not available, and parameter name information not found in class file either.");
"Name for argument of type [" + parameter.getNestedParameterType().getName() +
"] not specified, and parameter name information not found in class file either.");
}
}
String defaultValue = (ValueConstants.DEFAULT_NONE.equals(info.defaultValue) ? null : info.defaultValue);
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2020 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.
@@ -47,12 +47,12 @@ import org.springframework.web.method.HandlerMethod;
*/
public class InvocableHandlerMethod extends HandlerMethod {
private WebDataBinderFactory dataBinderFactory;
private HandlerMethodArgumentResolverComposite argumentResolvers = new HandlerMethodArgumentResolverComposite();
private HandlerMethodArgumentResolverComposite resolvers = new HandlerMethodArgumentResolverComposite();
private ParameterNameDiscoverer parameterNameDiscoverer = new DefaultParameterNameDiscoverer();
private WebDataBinderFactory dataBinderFactory;
/**
* Create an instance from a {@code HandlerMethod}.
@@ -82,20 +82,11 @@ public class InvocableHandlerMethod extends HandlerMethod {
}
/**
* Set the {@link WebDataBinderFactory} to be passed to argument resolvers allowing them to create
* a {@link WebDataBinder} for data binding and type conversion purposes.
* @param dataBinderFactory the data binder factory.
*/
public void setDataBinderFactory(WebDataBinderFactory dataBinderFactory) {
this.dataBinderFactory = dataBinderFactory;
}
/**
* Set {@link HandlerMethodArgumentResolver}s to use to use for resolving method argument values.
*/
public void setHandlerMethodArgumentResolvers(HandlerMethodArgumentResolverComposite argumentResolvers) {
this.argumentResolvers = argumentResolvers;
this.resolvers = argumentResolvers;
}
/**
@@ -107,6 +98,14 @@ public class InvocableHandlerMethod extends HandlerMethod {
this.parameterNameDiscoverer = parameterNameDiscoverer;
}
/**
* Set the {@link WebDataBinderFactory} to be passed to argument resolvers allowing them
* to create a {@link WebDataBinder} for data binding and type conversion purposes.
*/
public void setDataBinderFactory(WebDataBinderFactory dataBinderFactory) {
this.dataBinderFactory = dataBinderFactory;
}
/**
* Invoke the method after resolving its argument values in the context of the given request.
@@ -153,9 +152,9 @@ public class InvocableHandlerMethod extends HandlerMethod {
if (args[i] != null) {
continue;
}
if (this.argumentResolvers.supportsParameter(parameter)) {
if (this.resolvers.supportsParameter(parameter)) {
try {
args[i] = this.argumentResolvers.resolveArgument(
args[i] = this.resolvers.resolveArgument(
parameter, mavContainer, request, this.dataBinderFactory);
continue;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 the original author or authors.
* Copyright 2002-2020 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.
@@ -26,7 +26,7 @@ import org.springframework.web.multipart.MultipartResolver;
*
* <p>This may be because the request is not a multipart/form-data request,
* because the part is not present in the request, or because the web
* application is not configured correctly for processing multipart requests,
* application is not configured correctly for processing multipart requests,
* e.g. no {@link MultipartResolver}.
*
* @author Rossen Stoyanchev
@@ -35,17 +35,24 @@ import org.springframework.web.multipart.MultipartResolver;
@SuppressWarnings("serial")
public class MissingServletRequestPartException extends ServletException {
private final String partName;
private final String requestPartName;
public MissingServletRequestPartException(String partName) {
super("Required request part '" + partName + "' is not present");
this.partName = partName;
/**
* Constructor for MissingServletRequestPartException.
* @param requestPartName the name of the missing part of the multipart request
*/
public MissingServletRequestPartException(String requestPartName) {
super("Required request part '" + requestPartName + "' is not present");
this.requestPartName = requestPartName;
}
/**
* Return the name of the offending part of the multipart request.
*/
public String getRequestPartName() {
return this.partName;
return this.requestPartName;
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 the original author or authors.
* Copyright 2002-2020 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.
@@ -45,59 +45,62 @@ public class RequestPartServletServerHttpRequest extends ServletServerHttpReques
private final MultipartHttpServletRequest multipartRequest;
private final String partName;
private final String requestPartName;
private final HttpHeaders headers;
private final HttpHeaders multipartHeaders;
/**
* Create a new {@code RequestPartServletServerHttpRequest} instance.
* @param request the current servlet request
* @param partName the name of the part to adapt to the {@link ServerHttpRequest} contract
* @param requestPartName the name of the part to adapt to the {@link ServerHttpRequest} contract
* @throws MissingServletRequestPartException if the request part cannot be found
* @throws MultipartException if MultipartHttpServletRequest cannot be initialized
*/
public RequestPartServletServerHttpRequest(HttpServletRequest request, String partName)
public RequestPartServletServerHttpRequest(HttpServletRequest request, String requestPartName)
throws MissingServletRequestPartException {
super(request);
this.multipartRequest = MultipartResolutionDelegate.asMultipartHttpServletRequest(request);
this.partName = partName;
this.requestPartName = requestPartName;
this.headers = this.multipartRequest.getMultipartHeaders(this.partName);
if (this.headers == null) {
throw new MissingServletRequestPartException(partName);
HttpHeaders multipartHeaders = this.multipartRequest.getMultipartHeaders(requestPartName);
if (multipartHeaders == null) {
throw new MissingServletRequestPartException(requestPartName);
}
this.multipartHeaders = multipartHeaders;
}
@Override
public HttpHeaders getHeaders() {
return this.headers;
return this.multipartHeaders;
}
@Override
public InputStream getBody() throws IOException {
// Prefer Servlet Part resolution to cover file as well as parameter streams
if (this.multipartRequest instanceof StandardMultipartHttpServletRequest) {
try {
return this.multipartRequest.getPart(this.partName).getInputStream();
return this.multipartRequest.getPart(this.requestPartName).getInputStream();
}
catch (Exception ex) {
throw new MultipartException("Could not parse multipart servlet request", ex);
throw new MultipartException("Failed to retrieve request part '" + this.requestPartName + "'", ex);
}
}
else {
MultipartFile file = this.multipartRequest.getFile(this.partName);
if (file != null) {
return file.getInputStream();
}
else {
String paramValue = this.multipartRequest.getParameter(this.partName);
return new ByteArrayInputStream(paramValue.getBytes(determineEncoding()));
}
// Spring-style distinction between MultipartFile and String parameters
MultipartFile file = this.multipartRequest.getFile(this.requestPartName);
if (file != null) {
return file.getInputStream();
}
String paramValue = this.multipartRequest.getParameter(this.requestPartName);
if (paramValue != null) {
return new ByteArrayInputStream(paramValue.getBytes(determineEncoding()));
}
throw new IllegalStateException("No body available for request part '" + this.requestPartName + "'");
}
private String determineEncoding() {
@@ -26,6 +26,8 @@ import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
import org.springframework.http.HttpHeaders;
import org.springframework.util.ClassUtils;
import org.springframework.util.FastByteArrayOutputStream;
/**
@@ -41,6 +43,11 @@ import org.springframework.util.FastByteArrayOutputStream;
*/
public class ContentCachingResponseWrapper extends HttpServletResponseWrapper {
/** Checking for Servlet 3.0+ HttpServletResponse.getHeader(String) */
private static final boolean servlet3Present =
ClassUtils.hasMethod(HttpServletResponse.class, "getHeader", String.class);
private final FastByteArrayOutputStream content = new FastByteArrayOutputStream(1024);
private final ServletOutputStream outputStream = new ResponseServletOutputStream();
@@ -214,7 +221,13 @@ public class ContentCachingResponseWrapper extends HttpServletResponseWrapper {
if (this.content.size() > 0) {
HttpServletResponse rawResponse = (HttpServletResponse) getResponse();
if ((complete || this.contentLength != null) && !rawResponse.isCommitted()) {
rawResponse.setContentLength(complete ? this.content.size() : this.contentLength);
boolean hasTransferEncoding = false;
if (servlet3Present) {
hasTransferEncoding = (rawResponse.getHeader(HttpHeaders.TRANSFER_ENCODING) != null);
}
if (!hasTransferEncoding) {
rawResponse.setContentLength(complete ? this.content.size() : this.contentLength);
}
this.contentLength = null;
}
this.content.writeTo(rawResponse.getOutputStream());
@@ -213,7 +213,7 @@ public class UriComponentsBuilder implements Cloneable {
}
builder.scheme(scheme);
if (opaque) {
String ssp = uri.substring(scheme.length()).substring(1);
String ssp = uri.substring(scheme.length() + 1);
if (StringUtils.hasLength(fragment)) {
ssp = ssp.substring(0, ssp.length() - (fragment.length() + 1));
}
@@ -521,7 +521,8 @@ public class UrlPathHelper {
* @return the updated URI string
*/
public String removeSemicolonContent(String requestUri) {
return (this.removeSemicolonContent ? removeSemicolonContentInternal(requestUri) : requestUri);
return (this.removeSemicolonContent ?
removeSemicolonContentInternal(requestUri) : removeJsessionid(requestUri));
}
private String removeSemicolonContentInternal(String requestUri) {
@@ -535,6 +536,22 @@ public class UrlPathHelper {
return requestUri;
}
private String removeJsessionid(String requestUri) {
String key = ";jsessionid=";
int index = requestUri.toLowerCase().indexOf(key);
if (index == -1) {
return requestUri;
}
String start = requestUri.substring(0, index);
for (int i = index + key.length(); i < requestUri.length(); i++) {
char c = requestUri.charAt(i);
if (c == ';' || c == '/') {
return start + requestUri.substring(i);
}
}
return start;
}
/**
* Decode the given URI path variables via {@link #decodeRequestString} unless
* {@link #setUrlDecode} is set to {@code true} in which case it is assumed
@@ -639,7 +656,13 @@ public class UrlPathHelper {
* <li>{@code defaultEncoding=}{@link WebUtils#DEFAULT_CHARACTER_ENCODING}
* </ul>
*/
public static final UrlPathHelper rawPathInstance = new UrlPathHelper();
public static final UrlPathHelper rawPathInstance = new UrlPathHelper() {
@Override
public String removeSemicolonContent(String requestUri) {
return requestUri;
}
};
static {
rawPathInstance.setAlwaysUseFullPath(true);
@@ -0,0 +1,72 @@
/*
* Copyright 2002-2020 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
*
* https://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.filter;
import java.nio.charset.StandardCharsets;
import javax.servlet.http.HttpServletResponse;
import org.junit.Test;
import org.springframework.http.HttpHeaders;
import org.springframework.mock.web.test.MockHttpServletResponse;
import org.springframework.util.FileCopyUtils;
import org.springframework.web.util.ContentCachingResponseWrapper;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
/**
* Unit tests for {@link ContentCachingResponseWrapper}.
* @author Rossen Stoyanchev
*/
public class ContentCachingResponseWrapperTests {
@Test
public void copyBodyToResponse() throws Exception {
byte[] responseBody = "Hello World".getBytes(StandardCharsets.UTF_8);
MockHttpServletResponse response = new MockHttpServletResponse();
ContentCachingResponseWrapper responseWrapper = new ContentCachingResponseWrapper(response);
responseWrapper.setStatus(HttpServletResponse.SC_OK);
FileCopyUtils.copy(responseBody, responseWrapper.getOutputStream());
responseWrapper.copyBodyToResponse();
assertEquals(200, response.getStatus());
assertTrue(response.getContentLength() > 0);
assertArrayEquals(responseBody, response.getContentAsByteArray());
}
@Test
public void copyBodyToResponseWithTransferEncoding() throws Exception {
byte[] responseBody = "6\r\nHello 5\r\nWorld0\r\n\r\n".getBytes(StandardCharsets.UTF_8);
MockHttpServletResponse response = new MockHttpServletResponse();
ContentCachingResponseWrapper responseWrapper = new ContentCachingResponseWrapper(response);
responseWrapper.setStatus(HttpServletResponse.SC_OK);
responseWrapper.setHeader(HttpHeaders.TRANSFER_ENCODING, "chunked");
FileCopyUtils.copy(responseBody, responseWrapper.getOutputStream());
responseWrapper.copyBodyToResponse();
assertEquals(200, response.getStatus());
assertEquals("chunked", response.getHeader(HttpHeaders.TRANSFER_ENCODING));
assertNull(response.getHeader(HttpHeaders.CONTENT_LENGTH));
assertArrayEquals(responseBody, response.getContentAsByteArray());
}
}
@@ -129,11 +129,19 @@ public class UrlPathHelperTests {
public void getRequestKeepSemicolonContent() {
helper.setRemoveSemicolonContent(false);
request.setRequestURI("/foo;a=b;c=d");
assertEquals("/foo;a=b;c=d", helper.getRequestUri(request));
testKeepSemicolonContent("/foo;a=b;c=d", "/foo;a=b;c=d");
testKeepSemicolonContent("/test;jsessionid=1234", "/test");
testKeepSemicolonContent("/test;JSESSIONID=1234", "/test");
testKeepSemicolonContent("/test;jsessionid=1234;a=b", "/test;a=b");
testKeepSemicolonContent("/test;a=b;jsessionid=1234;c=d", "/test;a=b;c=d");
testKeepSemicolonContent("/test;jsessionid=1234/anotherTest", "/test/anotherTest");
testKeepSemicolonContent("/test;jsessionid=;a=b", "/test;a=b");
testKeepSemicolonContent("/somethingLongerThan12;jsessionid=1234", "/somethingLongerThan12");
}
request.setRequestURI("/foo;jsessionid=c0o7fszeb1");
assertEquals("/foo;jsessionid=c0o7fszeb1", helper.getRequestUri(request));
private void testKeepSemicolonContent(String requestUri, String expectedPath) {
request.setRequestURI(requestUri);
assertEquals(expectedPath, helper.getRequestUri(request));
}
@Test
@@ -157,7 +157,7 @@ class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
ClassUtils.isPresent("javax.validation.Validator",
AnnotationDrivenBeanDefinitionParser.class.getClassLoader());
private static boolean romePresent =
private static final boolean romePresent =
ClassUtils.isPresent("com.rometools.rome.feed.WireFeed",
AnnotationDrivenBeanDefinitionParser.class.getClassLoader());
@@ -197,7 +197,7 @@ class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
handlerMappingDef.getPropertyValues().add("contentNegotiationManager", contentNegotiationManager);
if (element.hasAttribute("enable-matrix-variables")) {
Boolean enableMatrixVariables = Boolean.valueOf(element.getAttribute("enable-matrix-variables"));
boolean enableMatrixVariables = Boolean.parseBoolean(element.getAttribute("enable-matrix-variables"));
handlerMappingDef.getPropertyValues().add("removeSemicolonContent", !enableMatrixVariables);
}
else if (element.hasAttribute("enableMatrixVariables")) {
@@ -545,7 +545,7 @@ class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
}
}
if (convertersElement == null || Boolean.valueOf(convertersElement.getAttribute("register-defaults"))) {
if (convertersElement == null || Boolean.parseBoolean(convertersElement.getAttribute("register-defaults"))) {
messageConverters.setSource(source);
messageConverters.add(createConverterDefinition(ByteArrayHttpMessageConverter.class, source));
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2020 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.
@@ -80,7 +80,7 @@ class ResourcesBeanDefinitionParser implements BeanDefinitionParser {
private static final String RESOURCE_URL_PROVIDER = "mvcResourceUrlProvider";
private static final boolean isWebJarsAssetLocatorPresent = ClassUtils.isPresent(
private static final boolean webJarsPresent = ClassUtils.isPresent(
"org.webjars.WebJarAssetLocator", ResourcesBeanDefinitionParser.class.getClassLoader());
@@ -329,7 +329,7 @@ class ResourcesBeanDefinitionParser implements BeanDefinitionParser {
}
if (isAutoRegistration) {
if (isWebJarsAssetLocatorPresent) {
if (webJarsPresent) {
RootBeanDefinition webJarsResolverDef = new RootBeanDefinition(WebJarsResourceResolver.class);
webJarsResolverDef.setSource(source);
webJarsResolverDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 the original author or authors.
* Copyright 2002-2020 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,9 +16,6 @@
package org.springframework.web.servlet.mvc.condition;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.RequestMapping;
@@ -32,8 +29,6 @@ import org.springframework.web.bind.annotation.RequestMapping;
*/
abstract class AbstractMediaTypeExpression implements MediaTypeExpression, Comparable<AbstractMediaTypeExpression> {
protected final Log logger = LogFactory.getLog(getClass());
private final MediaType mediaType;
private final boolean isNegated;
@@ -73,15 +68,15 @@ abstract class AbstractMediaTypeExpression implements MediaTypeExpression, Compa
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
public boolean equals(Object other) {
if (this == other) {
return true;
}
if (obj != null && getClass() == obj.getClass()) {
AbstractMediaTypeExpression other = (AbstractMediaTypeExpression) obj;
return (this.mediaType.equals(other.mediaType) && this.isNegated == other.isNegated);
if (other == null || getClass() != other.getClass()) {
return false;
}
return false;
AbstractMediaTypeExpression otherExpr = (AbstractMediaTypeExpression) other;
return (this.mediaType.equals(otherExpr.mediaType) && this.isNegated == otherExpr.isNegated);
}
@Override
@@ -91,12 +86,10 @@ abstract class AbstractMediaTypeExpression implements MediaTypeExpression, Compa
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
if (this.isNegated) {
builder.append('!');
return '!' + this.mediaType.toString();
}
builder.append(this.mediaType.toString());
return builder.toString();
return this.mediaType.toString();
}
}
@@ -380,15 +380,16 @@ public class RequestResponseBodyMethodProcessorTests {
Collections.singletonList(new StringHttpMessageConverter()),
factory.getObject());
assertContentDisposition(processor, false, "/hello.json", "whitelisted extension");
assertContentDisposition(processor, false, "/hello.json", "safe extension");
assertContentDisposition(processor, false, "/hello.pdf", "registered extension");
assertContentDisposition(processor, true, "/hello.dataless", "uknown extension");
// path parameters
assertContentDisposition(processor, false, "/hello.json;a=b", "path param shouldn't cause issue");
assertContentDisposition(processor, true, "/hello.json;a=b;setup.dataless", "uknown ext in path params");
assertContentDisposition(processor, true, "/hello.dataless;a=b;setup.json", "uknown ext in filename");
assertContentDisposition(processor, false, "/hello.json;a=b;setup.json", "whitelisted extensions");
assertContentDisposition(processor, true, "/hello.json;a=b;setup.dataless", "unknown ext in path params");
assertContentDisposition(processor, true, "/hello.dataless;a=b;setup.json", "unknown ext in filename");
assertContentDisposition(processor, false, "/hello.json;a=b;setup.json", "safe extensions");
assertContentDisposition(processor, true, "/hello.json;jsessionid=foo.bar", "jsessionid shouldn't cause issue");
// encoded dot
assertContentDisposition(processor, true, "/hello%2Edataless;a=b;setup.json", "encoded dot in filename");
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2015 the original author or authors.
* Copyright 2002-2020 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.
@@ -86,6 +86,28 @@ public class UriTemplateServletAnnotationControllerHandlerMethodTests extends Ab
assertEquals("test-42-7", response.getContentAsString());
}
@Test // gh-25864
public void literalMappingWithPathParams() throws Exception {
initServletWithControllers(MultipleUriTemplateController.class);
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/data");
MockHttpServletResponse response = new MockHttpServletResponse();
getServlet().service(request, response);
assertEquals(200, response.getStatus());
assertEquals("test", response.getContentAsString());
request = new MockHttpServletRequest("GET", "/data;foo=bar");
response = new MockHttpServletResponse();
getServlet().service(request, response);
assertEquals(404, response.getStatus());
request = new MockHttpServletRequest("GET", "/data;jsessionid=123");
response = new MockHttpServletResponse();
getServlet().service(request, response);
assertEquals(200, response.getStatus());
assertEquals("test", response.getContentAsString());
}
@Test
public void multiple() throws Exception {
initServletWithControllers(MultipleUriTemplateController.class);
@@ -405,6 +427,10 @@ public class UriTemplateServletAnnotationControllerHandlerMethodTests extends Ab
writer.write("test-" + hotel + "-q" + qHotel + "-" + booking + "-" + other + "-q" + qOther);
}
@RequestMapping("/data")
void handleWithLiteralMapping(Writer writer) throws IOException {
writer.write("test");
}
}
@Controller
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2020 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.
@@ -114,6 +114,12 @@ public interface WebSocketSession extends Closeable {
/**
* Send a WebSocket message: either {@link TextMessage} or {@link BinaryMessage}.
* <p><strong>Note:</strong> The underlying standard WebSocket session (JSR-356) does
* not allow concurrent sending. Therefore sending must be synchronized. To ensure
* that, one option is to wrap the {@code WebSocketSession} with the
* {@link org.springframework.web.socket.handler.ConcurrentWebSocketSessionDecorator
* ConcurrentWebSocketSessionDecorator}.
* @see org.springframework.web.socket.handler.ConcurrentWebSocketSessionDecorator
*/
void sendMessage(WebSocketMessage<?> message) throws IOException;
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 the original author or authors.
* Copyright 2002-2018 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.
@@ -78,6 +78,7 @@ public class OriginHandshakeInterceptor implements HandshakeInterceptor {
}
/**
* Return the allowed {@code Origin} header values.
* @since 4.1.5
* @see #setAllowedOrigins
*/