mirror of
https://github.com/spring-projects/spring-framework
synced 2026-06-08 17:33:33 +00:00
Compare commits
20 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8e0d8f99e2 | |||
| 0b076b28f1 | |||
| 0abb17af9d | |||
| d5a80d2777 | |||
| 07455c8a27 | |||
| c45c67203c | |||
| aeb83fe1a3 | |||
| 0bf002dbe1 | |||
| 4ff521d769 | |||
| 9107aed878 | |||
| 4ba174311b | |||
| 09c8586ee4 | |||
| 8212151f16 | |||
| 65577671bc | |||
| d1d37534bf | |||
| 45322a72a5 | |||
| 678ea4ece7 | |||
| bacf6ca37b | |||
| 95c0f1108f | |||
| 06c76d8075 |
+3
-1
@@ -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
@@ -1 +1 @@
|
||||
version=4.3.29.BUILD-SNAPSHOT
|
||||
version=4.3.30.RELEASE
|
||||
|
||||
+6
-4
@@ -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
|
||||
|
||||
+6
-4
@@ -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.
|
||||
|
||||
+33
-20
@@ -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());
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -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
-2
@@ -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,
|
||||
|
||||
|
||||
+3
-2
@@ -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";
|
||||
|
||||
|
||||
+3
-4
@@ -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
|
||||
|
||||
+9
-6
@@ -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;
|
||||
|
||||
+4
-6
@@ -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;
|
||||
|
||||
|
||||
+4
-7
@@ -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);
|
||||
|
||||
+10
-7
@@ -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();
|
||||
}
|
||||
|
||||
+6
-6
@@ -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)
|
||||
|
||||
+2
-4
@@ -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());
|
||||
|
||||
+21
-19
@@ -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.
|
||||
|
||||
+9
-7
@@ -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())) {
|
||||
|
||||
+8
-5
@@ -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();
|
||||
|
||||
+4
-3
@@ -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);
|
||||
|
||||
+2
-2
@@ -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());
|
||||
|
||||
+3
-1
@@ -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);
|
||||
}
|
||||
|
||||
+46
-12
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
+12
-10
@@ -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 {
|
||||
|
||||
+3
-3
@@ -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();
|
||||
|
||||
|
||||
+3
-4
@@ -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);
|
||||
|
||||
+15
-16
@@ -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;
|
||||
}
|
||||
|
||||
+14
-7
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+25
-22
@@ -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() {
|
||||
|
||||
+14
-1
@@ -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);
|
||||
|
||||
+72
@@ -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
|
||||
|
||||
+3
-3
@@ -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));
|
||||
|
||||
|
||||
+3
-3
@@ -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);
|
||||
|
||||
+9
-16
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+5
-4
@@ -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");
|
||||
|
||||
+27
-1
@@ -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;
|
||||
|
||||
|
||||
+2
-1
@@ -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
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user