Merge branch '5.2.x'

# Conflicts:
#	build.gradle
#	src/docs/asciidoc/core/core-aop-api.adoc
This commit is contained in:
Juergen Hoeller 2020-09-14 22:22:02 +02:00
commit 07b3e92bae
9 changed files with 69 additions and 50 deletions

View File

@ -334,7 +334,7 @@ configure([rootProject] + javaProjects) { project ->
} }
checkstyle { checkstyle {
toolVersion = "8.36" toolVersion = "8.36.1"
configDirectory.set(rootProject.file("src/checkstyle")) configDirectory.set(rootProject.file("src/checkstyle"))
} }

View File

@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -159,8 +159,6 @@ public class MimeMessageHelper {
private static final String HEADER_PRIORITY = "X-Priority"; private static final String HEADER_PRIORITY = "X-Priority";
private static final String HEADER_CONTENT_ID = "Content-ID";
private final MimeMessage mimeMessage; private final MimeMessage mimeMessage;
@ -175,6 +173,8 @@ public class MimeMessageHelper {
private FileTypeMap fileTypeMap; private FileTypeMap fileTypeMap;
private boolean encodeFilenames = true;
private boolean validateAddresses = false; private boolean validateAddresses = false;
@ -464,7 +464,7 @@ public class MimeMessageHelper {
* Set the Java Activation Framework {@code FileTypeMap} to use * Set the Java Activation Framework {@code FileTypeMap} to use
* for determining the content type of inline content and attachments * for determining the content type of inline content and attachments
* that get added to the message. * that get added to the message.
* <p>Default is the {@code FileTypeMap} that the underlying * <p>The default is the {@code FileTypeMap} that the underlying
* MimeMessage carries, if any, or the Activation Framework's default * MimeMessage carries, if any, or the Activation Framework's default
* {@code FileTypeMap} instance else. * {@code FileTypeMap} instance else.
* @see #addInline * @see #addInline
@ -480,18 +480,40 @@ public class MimeMessageHelper {
/** /**
* Return the {@code FileTypeMap} used by this MimeMessageHelper. * Return the {@code FileTypeMap} used by this MimeMessageHelper.
* @see #setFileTypeMap
*/ */
public FileTypeMap getFileTypeMap() { public FileTypeMap getFileTypeMap() {
return this.fileTypeMap; return this.fileTypeMap;
} }
/**
* Set whether to encode attachment filenames passed to this helper's
* {@code #addAttachment} methods.
* <p>The default is {@code true} for compatibility with older email clients;
* turn this to {@code false} for standard MIME behavior. On a related note,
* check out JavaMail's {@code mail.mime.encodefilename} system property.
* @since 5.2.9
* @see #addAttachment(String, DataSource)
* @see MimeBodyPart#setFileName(String)
*/
public void setEncodeFilenames(boolean encodeFilenames) {
this.encodeFilenames = encodeFilenames;
}
/**
* Return whether to encode attachment filenames passed to this helper's
* {@code #addAttachment} methods.
* @since 5.2.9
* @see #setEncodeFilenames
*/
public boolean isEncodeFilenames() {
return this.encodeFilenames;
}
/** /**
* Set whether to validate all addresses which get passed to this helper. * Set whether to validate all addresses which get passed to this helper.
* Default is "false". * <p>The default is {@code false}.
* <p>Note that this is by default just available for JavaMail >= 1.3.
* You can override the default {@code validateAddress method} for
* validation on older JavaMail versions (or for custom validation).
* @see #validateAddress * @see #validateAddress
*/ */
public void setValidateAddresses(boolean validateAddresses) { public void setValidateAddresses(boolean validateAddresses) {
@ -500,6 +522,7 @@ public class MimeMessageHelper {
/** /**
* Return whether this helper will validate all addresses passed to it. * Return whether this helper will validate all addresses passed to it.
* @see #setValidateAddresses
*/ */
public boolean isValidateAddresses() { public boolean isValidateAddresses() {
return this.validateAddresses; return this.validateAddresses;
@ -508,10 +531,8 @@ public class MimeMessageHelper {
/** /**
* Validate the given mail address. * Validate the given mail address.
* Called by all of MimeMessageHelper's address setters and adders. * Called by all of MimeMessageHelper's address setters and adders.
* <p>Default implementation invokes {@code InternetAddress.validate()}, * <p>The default implementation invokes {@link InternetAddress#validate()},
* provided that address validation is activated for the helper instance. * provided that address validation is activated for the helper instance.
* <p>Note that this method will just work on JavaMail >= 1.3. You can override
* it for validation on older JavaMail versions or for custom validation.
* @param address the address to validate * @param address the address to validate
* @throws AddressException if validation failed * @throws AddressException if validation failed
* @see #isValidateAddresses() * @see #isValidateAddresses()
@ -525,7 +546,8 @@ public class MimeMessageHelper {
/** /**
* Validate all given mail addresses. * Validate all given mail addresses.
* Default implementation simply delegates to validateAddress for each address. * <p>The default implementation simply delegates to {@link #validateAddress}
* for each address.
* @param addresses the addresses to validate * @param addresses the addresses to validate
* @throws AddressException if validation failed * @throws AddressException if validation failed
* @see #validateAddress(InternetAddress) * @see #validateAddress(InternetAddress)
@ -885,9 +907,7 @@ public class MimeMessageHelper {
Assert.notNull(dataSource, "DataSource must not be null"); Assert.notNull(dataSource, "DataSource must not be null");
MimeBodyPart mimeBodyPart = new MimeBodyPart(); MimeBodyPart mimeBodyPart = new MimeBodyPart();
mimeBodyPart.setDisposition(MimeBodyPart.INLINE); mimeBodyPart.setDisposition(MimeBodyPart.INLINE);
// We're using setHeader here to remain compatible with JavaMail 1.2, mimeBodyPart.setContentID("<" + contentId + ">");
// rather than JavaMail 1.3's setContentID.
mimeBodyPart.setHeader(HEADER_CONTENT_ID, "<" + contentId + ">");
mimeBodyPart.setDataHandler(new DataHandler(dataSource)); mimeBodyPart.setDataHandler(new DataHandler(dataSource));
getMimeMultipart().addBodyPart(mimeBodyPart); getMimeMultipart().addBodyPart(mimeBodyPart);
} }
@ -997,7 +1017,8 @@ public class MimeMessageHelper {
try { try {
MimeBodyPart mimeBodyPart = new MimeBodyPart(); MimeBodyPart mimeBodyPart = new MimeBodyPart();
mimeBodyPart.setDisposition(MimeBodyPart.ATTACHMENT); mimeBodyPart.setDisposition(MimeBodyPart.ATTACHMENT);
mimeBodyPart.setFileName(MimeUtility.encodeText(attachmentFilename)); mimeBodyPart.setFileName(isEncodeFilenames() ?
MimeUtility.encodeText(attachmentFilename) : attachmentFilename);
mimeBodyPart.setDataHandler(new DataHandler(dataSource)); mimeBodyPart.setDataHandler(new DataHandler(dataSource));
getRootMimeMultipart().addBodyPart(mimeBodyPart); getRootMimeMultipart().addBodyPart(mimeBodyPart);
} }

View File

@ -103,6 +103,7 @@ public final class StringDecoder extends AbstractDataBufferDecoder<String> {
return this.defaultCharset; return this.defaultCharset;
} }
@Override @Override
public boolean canDecode(ResolvableType elementType, @Nullable MimeType mimeType) { public boolean canDecode(ResolvableType elementType, @Nullable MimeType mimeType) {
return (elementType.resolve() == String.class && super.canDecode(elementType, mimeType)); return (elementType.resolve() == String.class && super.canDecode(elementType, mimeType));
@ -167,7 +168,6 @@ public final class StringDecoder extends AbstractDataBufferDecoder<String> {
/** /**
* Finds the first match and longest delimiter, {@link EndFrameBuffer} just after it. * Finds the first match and longest delimiter, {@link EndFrameBuffer} just after it.
*
* @param dataBuffer the buffer to find delimiters in * @param dataBuffer the buffer to find delimiters in
* @param matcher used to find the first delimiters * @param matcher used to find the first delimiters
* @return a flux of buffers, containing {@link EndFrameBuffer} after each delimiter that was * @return a flux of buffers, containing {@link EndFrameBuffer} after each delimiter that was
@ -221,7 +221,6 @@ public final class StringDecoder extends AbstractDataBufferDecoder<String> {
} }
DataBuffer result = dataBuffers.get(0).factory().join(dataBuffers); DataBuffer result = dataBuffers.get(0).factory().join(dataBuffers);
if (stripDelimiter && matchingDelimiter != null) { if (stripDelimiter && matchingDelimiter != null) {
result.writePosition(result.writePosition() - matchingDelimiter.length); result.writePosition(result.writePosition() - matchingDelimiter.length);
} }
@ -229,8 +228,6 @@ public final class StringDecoder extends AbstractDataBufferDecoder<String> {
} }
/** /**
* Create a {@code StringDecoder} for {@code "text/plain"}. * Create a {@code StringDecoder} for {@code "text/plain"}.
* @param stripDelimiter this flag is ignored * @param stripDelimiter this flag is ignored
@ -293,8 +290,7 @@ public final class StringDecoder extends AbstractDataBufferDecoder<String> {
private static final DataBuffer BUFFER = DefaultDataBufferFactory.sharedInstance.wrap(new byte[0]); private static final DataBuffer BUFFER = DefaultDataBufferFactory.sharedInstance.wrap(new byte[0]);
private byte[] delimiter; private final byte[] delimiter;
public EndFrameBuffer(byte[] delimiter) { public EndFrameBuffer(byte[] delimiter) {
super(BUFFER); super(BUFFER);
@ -304,7 +300,6 @@ public final class StringDecoder extends AbstractDataBufferDecoder<String> {
public byte[] delimiter() { public byte[] delimiter() {
return this.delimiter; return this.delimiter;
} }
} }
@ -313,7 +308,6 @@ public final class StringDecoder extends AbstractDataBufferDecoder<String> {
@SuppressWarnings("MismatchedQueryAndUpdateOfCollection") @SuppressWarnings("MismatchedQueryAndUpdateOfCollection")
private final LimitedDataBufferList list; private final LimitedDataBufferList list;
LimitChecker(int maxInMemorySize) { LimitChecker(int maxInMemorySize) {
this.list = new LimitedDataBufferList(maxInMemorySize); this.list = new LimitedDataBufferList(maxInMemorySize);
} }

View File

@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -30,9 +30,9 @@ import org.springframework.core.convert.converter.Converter;
*/ */
final class StringToBooleanConverter implements Converter<String, Boolean> { final class StringToBooleanConverter implements Converter<String, Boolean> {
private static final Set<String> trueValues = new HashSet<>(4); private static final Set<String> trueValues = new HashSet<>(8);
private static final Set<String> falseValues = new HashSet<>(4); private static final Set<String> falseValues = new HashSet<>(8);
static { static {
trueValues.add("true"); trueValues.add("true");
@ -46,6 +46,7 @@ final class StringToBooleanConverter implements Converter<String, Boolean> {
falseValues.add("0"); falseValues.add("0");
} }
@Override @Override
public Boolean convert(String source) { public Boolean convert(String source) {
String value = source.trim(); String value = source.trim();

View File

@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -19,6 +19,7 @@ package org.springframework.core.convert.support;
import java.util.UUID; import java.util.UUID;
import org.springframework.core.convert.converter.Converter; import org.springframework.core.convert.converter.Converter;
import org.springframework.lang.Nullable;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
/** /**
@ -31,6 +32,7 @@ import org.springframework.util.StringUtils;
final class StringToUUIDConverter implements Converter<String, UUID> { final class StringToUUIDConverter implements Converter<String, UUID> {
@Override @Override
@Nullable
public UUID convert(String source) { public UUID convert(String source) {
return (StringUtils.hasText(source) ? UUID.fromString(source.trim()) : null); return (StringUtils.hasText(source) ? UUID.fromString(source.trim()) : null);
} }

View File

@ -562,7 +562,7 @@ public final class ContentDisposition {
private static class BuilderImpl implements Builder { private static class BuilderImpl implements Builder {
private String type; private final String type;
@Nullable @Nullable
private String name; private String name;

View File

@ -861,7 +861,7 @@ public class HttpHeaders implements MultiValueMap<String, String>, Serializable
public void setContentDispositionFormData(String name, @Nullable String filename) { public void setContentDispositionFormData(String name, @Nullable String filename) {
Assert.notNull(name, "Name must not be null"); Assert.notNull(name, "Name must not be null");
ContentDisposition.Builder disposition = ContentDisposition.builder("form-data").name(name); ContentDisposition.Builder disposition = ContentDisposition.builder("form-data").name(name);
if (filename != null) { if (StringUtils.hasText(filename)) {
disposition.filename(filename); disposition.filename(filename);
} }
setContentDisposition(disposition.build()); setContentDisposition(disposition.build());
@ -888,7 +888,7 @@ public class HttpHeaders implements MultiValueMap<String, String>, Serializable
*/ */
public ContentDisposition getContentDisposition() { public ContentDisposition getContentDisposition() {
String contentDisposition = getFirst(CONTENT_DISPOSITION); String contentDisposition = getFirst(CONTENT_DISPOSITION);
if (contentDisposition != null) { if (StringUtils.hasText(contentDisposition)) {
return ContentDisposition.parse(contentDisposition); return ContentDisposition.parse(contentDisposition);
} }
return ContentDisposition.empty(); return ContentDisposition.empty();

View File

@ -103,13 +103,13 @@ The `MethodMatcher` interface is normally more important. The complete interface
The `matches(Method, Class)` method is used to test whether this pointcut ever The `matches(Method, Class)` method is used to test whether this pointcut ever
matches a given method on a target class. This evaluation can be performed when an AOP matches a given method on a target class. This evaluation can be performed when an AOP
proxy is created to avoid the need for a test on every method invocation. If the proxy is created to avoid the need for a test on every method invocation. If the
two-argument `matches` method returns `true` for a given method, and the `isRuntime()` method two-argument `matches` method returns `true` for a given method, and the `isRuntime()`
for the MethodMatcher returns `true`, the three-argument matches method is invoked on method for the MethodMatcher returns `true`, the three-argument matches method is
every method invocation. This lets a pointcut look at the arguments passed to the invoked on every method invocation. This lets a pointcut look at the arguments passed
method invocation immediately before the target advice starts. to the method invocation immediately before the target advice starts.
Most `MethodMatcher` implementations are static, meaning that their `isRuntime()` method returns `false`. Most `MethodMatcher` implementations are static, meaning that their `isRuntime()` method
In this case, the three-argument `matches` method is never invoked. returns `false`. In this case, the three-argument `matches` method is never invoked.
TIP: If possible, try to make pointcuts static, allowing the AOP framework to cache the TIP: If possible, try to make pointcuts static, allowing the AOP framework to cache the
results of pointcut evaluation when an AOP proxy is created. results of pointcut evaluation when an AOP proxy is created.
@ -145,20 +145,20 @@ See the <<aop, previous chapter>> for a discussion of supported AspectJ pointcut
[[aop-api-pointcuts-impls]] [[aop-api-pointcuts-impls]]
=== Convenience Pointcut Implementations === Convenience Pointcut Implementations
Spring provides several convenient pointcut implementations. You can use some of them directly. Spring provides several convenient pointcut implementations. You can use some of them
Others are intended to be subclassed in application-specific pointcuts. directly; others are intended to be subclassed in application-specific pointcuts.
[[aop-api-pointcuts-static]] [[aop-api-pointcuts-static]]
==== Static Pointcuts ==== Static Pointcuts
Static pointcuts are based on the method and the target class and cannot take into account the Static pointcuts are based on the method and the target class and cannot take into account
method's arguments. Static pointcuts suffice -- and are best -- for most usages. the method's arguments. Static pointcuts suffice -- and are best -- for most usages.
Spring can evaluate a static pointcut only once, when a method is first Spring can evaluate a static pointcut only once, when a method is first invoked.
invoked. After that, there is no need to evaluate the pointcut again with each method After that, there is no need to evaluate the pointcut again with each method invocation.
invocation.
The rest of this section describes some of the static pointcut implementations that are included with Spring. The rest of this section describes some of the static pointcut implementations that are
included with Spring.
[[aop-api-pointcuts-regex]] [[aop-api-pointcuts-regex]]
===== Regular Expression Pointcuts ===== Regular Expression Pointcuts
@ -168,9 +168,9 @@ frameworks besides Spring make this possible.
`org.springframework.aop.support.JdkRegexpMethodPointcut` is a generic regular `org.springframework.aop.support.JdkRegexpMethodPointcut` is a generic regular
expression pointcut that uses the regular expression support in the JDK. expression pointcut that uses the regular expression support in the JDK.
With the `JdkRegexpMethodPointcut` class, you can provide a list of pattern strings. If With the `JdkRegexpMethodPointcut` class, you can provide a list of pattern strings.
any of these is a match, the pointcut evaluates to `true`. (So, the result is If any of these is a match, the pointcut evaluates to `true`. (As a consequence,
effectively the union of these patterns.) the resulting pointcut is effectively the union of the specified patterns.)
The following example shows how to use `JdkRegexpMethodPointcut`: The following example shows how to use `JdkRegexpMethodPointcut`:

View File

@ -4424,7 +4424,8 @@ which these `BeanFactoryPostProcessor` instances run by setting the `order` prop
However, you can only set this property if the `BeanFactoryPostProcessor` implements the However, you can only set this property if the `BeanFactoryPostProcessor` implements the
`Ordered` interface. If you write your own `BeanFactoryPostProcessor`, you should `Ordered` interface. If you write your own `BeanFactoryPostProcessor`, you should
consider implementing the `Ordered` interface, too. See the javadoc of the consider implementing the `Ordered` interface, too. See the javadoc of the
{api-spring-framework}/beans/factory/config/BeanFactoryPostProcessor.html[`BeanFactoryPostProcessor`] and {api-spring-framework}/core/Ordered.html[`Ordered`] interfaces for more details. {api-spring-framework}/beans/factory/config/BeanFactoryPostProcessor.html[`BeanFactoryPostProcessor`]
and {api-spring-framework}/core/Ordered.html[`Ordered`] interfaces for more details.
[NOTE] [NOTE]
==== ====