diff --git a/spring-context/src/main/java/org/springframework/scheduling/concurrent/DefaultManagedTaskScheduler.java b/spring-context/src/main/java/org/springframework/scheduling/concurrent/DefaultManagedTaskScheduler.java index db35cf4a634..cae241e06ed 100644 --- a/spring-context/src/main/java/org/springframework/scheduling/concurrent/DefaultManagedTaskScheduler.java +++ b/spring-context/src/main/java/org/springframework/scheduling/concurrent/DefaultManagedTaskScheduler.java @@ -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. @@ -36,10 +36,11 @@ import org.springframework.lang.Nullable; * * @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(); @Nullable private String jndiName = "java:comp/DefaultManagedScheduledExecutorService"; diff --git a/spring-core/src/main/java/org/springframework/util/MimeType.java b/spring-core/src/main/java/org/springframework/util/MimeType.java index f4a7c18e3f5..f4d31157e5c 100644 --- a/spring-core/src/main/java/org/springframework/util/MimeType.java +++ b/spring-core/src/main/java/org/springframework/util/MimeType.java @@ -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, Serializable { * @see HTTP 1.1, section 2.2 */ 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, 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); @@ -401,7 +400,7 @@ public class MimeType implements Comparable, Serializable { /** * Determine if the parameters in this {@code MimeType} and the supplied * {@code MimeType} are equal, performing case-insensitive comparisons - * for {@link Charset}s. + * for {@link Charset Charsets}. * @since 4.2 */ private boolean parametersAreEqual(MimeType other) { @@ -542,6 +541,11 @@ public class MimeType implements Comparable, Serializable { } + /** + * Comparator to sort {@link MimeType MimeTypes} in order of specificity. + * + * @param the type of mime types that may be compared by this comparator + */ public static class SpecificityComparator implements Comparator { @Override diff --git a/spring-messaging/src/main/java/org/springframework/messaging/converter/AbstractMessageConverter.java b/spring-messaging/src/main/java/org/springframework/messaging/converter/AbstractMessageConverter.java index 6ac679d39ef..cb81b02b6f4 100644 --- a/spring-messaging/src/main/java/org/springframework/messaging/converter/AbstractMessageConverter.java +++ b/spring-messaging/src/main/java/org/springframework/messaging/converter/AbstractMessageConverter.java @@ -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. @@ -151,21 +151,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. - *

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 - */ - @Nullable - protected MimeType getDefaultContentType(Object payload) { - List mimeTypes = getSupportedMimeTypes(); - return (!mimeTypes.isEmpty() ? mimeTypes.get(0) : null); - } - @Override @Nullable public final Object fromMessage(Message message, Class targetClass) { @@ -181,10 +166,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 @Nullable public final Message toMessage(Object payload, @Nullable MessageHeaders headers) { @@ -224,6 +205,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, @Nullable MessageHeaders headers) { return (supports(payload.getClass()) && supportsMimeType(headers)); } @@ -249,6 +235,22 @@ public abstract class AbstractMessageConverter implements SmartMessageConverter return (headers != null && 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. + *

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 + */ + @Nullable + protected MimeType getDefaultContentType(Object payload) { + List mimeTypes = getSupportedMimeTypes(); + return (!mimeTypes.isEmpty() ? mimeTypes.get(0) : null); + } + /** * Whether the given class is supported by this converter. diff --git a/spring-messaging/src/main/java/org/springframework/messaging/simp/stomp/DefaultStompSession.java b/spring-messaging/src/main/java/org/springframework/messaging/simp/stomp/DefaultStompSession.java index c40853cb6cd..4f32c99e33a 100644 --- a/spring-messaging/src/main/java/org/springframework/messaging/simp/stomp/DefaultStompSession.java +++ b/spring-messaging/src/main/java/org/springframework/messaging/simp/stomp/DefaultStompSession.java @@ -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. @@ -684,8 +684,10 @@ public class DefaultStompSession implements ConnectionHandlingStompSession { if (conn != null) { conn.send(HEARTBEAT).addCallback( new ListenableFutureCallback() { + @Override public void onSuccess(@Nullable Void result) { } + @Override public void onFailure(Throwable ex) { handleFailure(ex); } diff --git a/spring-messaging/src/main/java/org/springframework/messaging/support/NativeMessageHeaderAccessor.java b/spring-messaging/src/main/java/org/springframework/messaging/support/NativeMessageHeaderAccessor.java index 14b5cf3a914..84ce91b6793 100644 --- a/spring-messaging/src/main/java/org/springframework/messaging/support/NativeMessageHeaderAccessor.java +++ b/spring-messaging/src/main/java/org/springframework/messaging/support/NativeMessageHeaderAccessor.java @@ -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. @@ -53,14 +53,14 @@ public class NativeMessageHeaderAccessor extends MessageHeaderAccessor { /** - * A protected constructor to create new headers. + * Protected constructor to create a new instance. */ protected NativeMessageHeaderAccessor() { this((Map>) 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(@Nullable Map> nativeHeaders) { @@ -70,7 +70,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(@Nullable Message message) { super(message); @@ -85,6 +85,10 @@ public class NativeMessageHeaderAccessor extends MessageHeaderAccessor { } } + + /** + * Subclasses can use this method to access the "native" headers sub-map. + */ @SuppressWarnings("unchecked") @Nullable protected Map> getNativeHeaders() { @@ -92,7 +96,7 @@ public class NativeMessageHeaderAccessor extends MessageHeaderAccessor { } /** - * 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> toNativeHeaderMap() { Map> map = getNativeHeaders(); @@ -114,6 +118,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> map = getNativeHeaders(); @@ -121,8 +126,9 @@ public class NativeMessageHeaderAccessor extends MessageHeaderAccessor { } /** - * Return all values for the specified native header. - * or {@code null} if none. + * 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 */ @Nullable public List getNativeHeader(String headerName) { @@ -131,15 +137,16 @@ public class NativeMessageHeaderAccessor extends MessageHeaderAccessor { } /** - * Return the first value for the specified native header, - * or {@code null} if none. + * 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 */ @Nullable public String getFirstNativeHeader(String headerName) { Map> map = getNativeHeaders(); if (map != null) { List values = map.get(headerName); - if (values != null) { + if (!CollectionUtils.isEmpty(values)) { return values.get(0); } } @@ -148,6 +155,8 @@ public class NativeMessageHeaderAccessor extends MessageHeaderAccessor { /** * Set the specified native header value replacing existing values. + *

In order for this to work, the accessor must be {@link #isMutable() + * mutable}. See {@link MessageHeaderAccessor} for details. */ public void setNativeHeader(String name, @Nullable String value) { Assert.state(isMutable(), "Already immutable"); @@ -173,6 +182,10 @@ public class NativeMessageHeaderAccessor extends MessageHeaderAccessor { /** * Add the specified native header value to existing values. + *

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, @Nullable String value) { Assert.state(isMutable(), "Already immutable"); @@ -189,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(@Nullable MultiValueMap headers) { if (headers == null) { return; @@ -196,23 +213,38 @@ public class NativeMessageHeaderAccessor extends MessageHeaderAccessor { headers.forEach((key, values) -> values.forEach(value -> addNativeHeader(key, value))); } + /** + * Remove the specified native header value replacing existing values. + *

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 + */ @Nullable - public List removeNativeHeader(String name) { + public List removeNativeHeader(String headerName) { Assert.state(isMutable(), "Already immutable"); Map> 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") @Nullable public static String getFirstNativeHeader(String headerName, Map headers) { Map> map = (Map>) headers.get(NATIVE_HEADERS); if (map != null) { List values = map.get(headerName); - if (values != null) { + if (!CollectionUtils.isEmpty(values)) { return values.get(0); } } diff --git a/spring-messaging/src/test/java/org/springframework/messaging/converter/MappingJackson2MessageConverterTests.java b/spring-messaging/src/test/java/org/springframework/messaging/converter/MappingJackson2MessageConverterTests.java index 652dc0108fe..d6dadc7527d 100644 --- a/spring-messaging/src/test/java/org/springframework/messaging/converter/MappingJackson2MessageConverterTests.java +++ b/spring-messaging/src/test/java/org/springframework/messaging/converter/MappingJackson2MessageConverterTests.java @@ -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. @@ -75,13 +75,8 @@ public class MappingJackson2MessageConverterTests { @Test public void fromMessage() { MappingJackson2MessageConverter converter = new MappingJackson2MessageConverter(); - String payload = "{" + - "\"bytes\":\"AQI=\"," + - "\"array\":[\"Foo\",\"Bar\"]," + - "\"number\":42," + - "\"string\":\"Foo\"," + - "\"bool\":true," + - "\"fraction\":42.0}"; + String payload = "{\"bytes\":\"AQI=\",\"array\":[\"Foo\",\"Bar\"]," + + "\"number\":42,\"string\":\"Foo\",\"bool\":true,\"fraction\":42.0}"; Message message = MessageBuilder.withPayload(payload.getBytes(StandardCharsets.UTF_8)).build(); MyBean actual = (MyBean) converter.fromMessage(message, MyBean.class); @@ -245,9 +240,12 @@ public class MappingJackson2MessageConverterTests { public void jsonViewPayload(@JsonView(MyJacksonView2.class) JacksonViewBean payload) { } - void handleList(List payload) {} + void handleList(List payload) { + } + + void handleMessage(Message message) { + } - void handleMessage(Message message) {} public static class MyBean { diff --git a/spring-web/src/main/java/org/springframework/http/ResponseCookie.java b/spring-web/src/main/java/org/springframework/http/ResponseCookie.java index 54976dd8ab2..b2374485648 100644 --- a/spring-web/src/main/java/org/springframework/http/ResponseCookie.java +++ b/spring-web/src/main/java/org/springframework/http/ResponseCookie.java @@ -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. @@ -144,7 +144,6 @@ public final class ResponseCookie extends HttpCookie { long millis = this.maxAge.getSeconds() > 0 ? System.currentTimeMillis() + this.maxAge.toMillis() : 0; sb.append(HttpHeaders.formatDate(millis)); } - if (this.secure) { sb.append("; Secure"); } @@ -160,7 +159,7 @@ public final class ResponseCookie extends HttpCookie { * with a name-value pair and may also include attributes. * @param name the cookie name * @param value the cookie value - * @return the created cookie instance + * @return a builder to create the cookie with */ public static ResponseCookieBuilder from(final String name, final String value) { diff --git a/spring-web/src/main/java/org/springframework/http/codec/json/AbstractJackson2Decoder.java b/spring-web/src/main/java/org/springframework/http/codec/json/AbstractJackson2Decoder.java index 72c29bb4549..c8e226ea93a 100644 --- a/spring-web/src/main/java/org/springframework/http/codec/json/AbstractJackson2Decoder.java +++ b/spring-web/src/main/java/org/springframework/http/codec/json/AbstractJackson2Decoder.java @@ -74,7 +74,7 @@ public abstract class AbstractJackson2Decoder extends Jackson2CodecSupport imple @Override public boolean canDecode(ResolvableType elementType, @Nullable MimeType mimeType) { - JavaType javaType = getObjectMapper().getTypeFactory().constructType(elementType.getType()); + JavaType javaType = getObjectMapper().constructType(elementType.getType()); // Skip String: CharSequenceDecoder + "*/*" comes after return (!CharSequence.class.isAssignableFrom(elementType.resolve(Object.class)) && getObjectMapper().canDeserialize(javaType) && supportsMimeType(mimeType)); diff --git a/spring-web/src/main/java/org/springframework/http/codec/json/Jackson2CodecSupport.java b/spring-web/src/main/java/org/springframework/http/codec/json/Jackson2CodecSupport.java index 7f8650d9965..ad9fb1532ad 100644 --- a/spring-web/src/main/java/org/springframework/http/codec/json/Jackson2CodecSupport.java +++ b/spring-web/src/main/java/org/springframework/http/codec/json/Jackson2CodecSupport.java @@ -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. @@ -27,7 +27,6 @@ import java.util.Map; import com.fasterxml.jackson.annotation.JsonView; import com.fasterxml.jackson.databind.JavaType; import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.type.TypeFactory; import org.springframework.core.GenericTypeResolver; import org.springframework.core.MethodParameter; @@ -95,8 +94,7 @@ public abstract class Jackson2CodecSupport { } protected JavaType getJavaType(Type type, @Nullable Class contextClass) { - TypeFactory typeFactory = this.objectMapper.getTypeFactory(); - return typeFactory.constructType(GenericTypeResolver.resolveType(type, contextClass)); + return this.objectMapper.constructType(GenericTypeResolver.resolveType(type, contextClass)); } protected Map getHints(ResolvableType resolvableType) { diff --git a/spring-web/src/main/java/org/springframework/http/converter/HttpMessageConverter.java b/spring-web/src/main/java/org/springframework/http/converter/HttpMessageConverter.java index f406637dc1f..a0583b9c6d5 100644 --- a/spring-web/src/main/java/org/springframework/http/converter/HttpMessageConverter.java +++ b/spring-web/src/main/java/org/springframework/http/converter/HttpMessageConverter.java @@ -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. @@ -25,11 +25,12 @@ import org.springframework.http.MediaType; import org.springframework.lang.Nullable; /** - * 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 * @since 3.0 + * @param the converted object type */ public interface HttpMessageConverter { @@ -53,7 +54,7 @@ public interface HttpMessageConverter { /** * 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 getSupportedMediaTypes(); diff --git a/spring-web/src/main/java/org/springframework/http/converter/json/AbstractJackson2HttpMessageConverter.java b/spring-web/src/main/java/org/springframework/http/converter/json/AbstractJackson2HttpMessageConverter.java index 7e4527c7e27..1c7252b92d7 100644 --- a/spring-web/src/main/java/org/springframework/http/converter/json/AbstractJackson2HttpMessageConverter.java +++ b/spring-web/src/main/java/org/springframework/http/converter/json/AbstractJackson2HttpMessageConverter.java @@ -38,7 +38,6 @@ import com.fasterxml.jackson.databind.SerializationConfig; import com.fasterxml.jackson.databind.SerializationFeature; import com.fasterxml.jackson.databind.exc.InvalidDefinitionException; import com.fasterxml.jackson.databind.ser.FilterProvider; -import com.fasterxml.jackson.databind.type.TypeFactory; import org.springframework.core.GenericTypeResolver; import org.springframework.http.HttpInputMessage; @@ -319,8 +318,7 @@ public abstract class AbstractJackson2HttpMessageConverter extends AbstractGener * @return the Jackson JavaType */ protected JavaType getJavaType(Type type, @Nullable Class contextClass) { - TypeFactory typeFactory = this.objectMapper.getTypeFactory(); - return typeFactory.constructType(GenericTypeResolver.resolveType(type, contextClass)); + return this.objectMapper.constructType(GenericTypeResolver.resolveType(type, contextClass)); } /** diff --git a/spring-web/src/main/java/org/springframework/web/util/UriComponentsBuilder.java b/spring-web/src/main/java/org/springframework/web/util/UriComponentsBuilder.java index 4420b3d40ef..24cfdfa2424 100644 --- a/spring-web/src/main/java/org/springframework/web/util/UriComponentsBuilder.java +++ b/spring-web/src/main/java/org/springframework/web/util/UriComponentsBuilder.java @@ -233,7 +233,7 @@ public class UriComponentsBuilder implements UriBuilder, 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)); } @@ -394,9 +394,8 @@ public class UriComponentsBuilder implements UriBuilder, Cloneable { * characters that should have been encoded. */ public UriComponents build(boolean encoded) { - return buildInternal(encoded ? - EncodingHint.FULLY_ENCODED : - this.encodeTemplate ? EncodingHint.ENCODE_TEMPLATE : EncodingHint.NONE); + return buildInternal(encoded ? EncodingHint.FULLY_ENCODED : + (this.encodeTemplate ? EncodingHint.ENCODE_TEMPLATE : EncodingHint.NONE)); } private UriComponents buildInternal(EncodingHint hint) { @@ -408,8 +407,7 @@ public class UriComponentsBuilder implements UriBuilder, Cloneable { HierarchicalUriComponents uric = new HierarchicalUriComponents(this.scheme, this.fragment, this.userInfo, this.host, this.port, this.pathBuilder.build(), this.queryParams, hint == EncodingHint.FULLY_ENCODED); - - result = hint == EncodingHint.ENCODE_TEMPLATE ? uric.encodeTemplate(this.charset) : uric; + result = (hint == EncodingHint.ENCODE_TEMPLATE ? uric.encodeTemplate(this.charset) : uric); } if (!this.uriVariables.isEmpty()) { result = result.expand(name -> this.uriVariables.getOrDefault(name, UriTemplateVariables.SKIP_VALUE)); @@ -466,9 +464,8 @@ public class UriComponentsBuilder implements UriBuilder, Cloneable { * @see UriComponents#toUriString() */ public String toUriString() { - return this.uriVariables.isEmpty() ? - build().encode().toUriString() : - buildInternal(EncodingHint.ENCODE_TEMPLATE).toUriString(); + return (this.uriVariables.isEmpty() ? build().encode().toUriString() : + buildInternal(EncodingHint.ENCODE_TEMPLATE).toUriString()); } @@ -841,12 +838,10 @@ public class UriComponentsBuilder implements UriBuilder, Cloneable { scheme(StringUtils.tokenizeToStringArray(protocolHeader, ",")[0]); port(null); } - String hostHeader = headers.getFirst("X-Forwarded-Host"); if (StringUtils.hasText(hostHeader)) { adaptForwardedHost(StringUtils.tokenizeToStringArray(hostHeader, ",")[0]); } - String portHeader = headers.getFirst("X-Forwarded-Port"); if (StringUtils.hasText(portHeader)) { port(Integer.parseInt(StringUtils.tokenizeToStringArray(portHeader, ",")[0]));