diff --git a/spring-core/src/main/java/org/springframework/core/ReactiveAdapterRegistry.java b/spring-core/src/main/java/org/springframework/core/ReactiveAdapterRegistry.java
index 98c6fda4b36..5bcb289f794 100644
--- a/spring-core/src/main/java/org/springframework/core/ReactiveAdapterRegistry.java
+++ b/spring-core/src/main/java/org/springframework/core/ReactiveAdapterRegistry.java
@@ -40,7 +40,7 @@ import org.springframework.util.ConcurrentReferenceHashMap;
/**
* A registry of adapters to adapt Reactive Streams {@link Publisher} to/from
* various async/reactive types such as {@code CompletableFuture}, RxJava
- * {@code Observable}, and others.
+ * {@code Flowable}, and others.
*
*
By default, depending on classpath availability, adapters are registered
* for Reactor, RxJava 3, {@link CompletableFuture}, {@code Flow.Publisher},
diff --git a/spring-web/src/main/java/org/springframework/http/RequestEntity.java b/spring-web/src/main/java/org/springframework/http/RequestEntity.java
index 4c77123332c..6dd27d02db2 100644
--- a/spring-web/src/main/java/org/springframework/http/RequestEntity.java
+++ b/spring-web/src/main/java/org/springframework/http/RequestEntity.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2020 the original author or authors.
+ * Copyright 2002-2021 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.
@@ -194,15 +194,15 @@ public class RequestEntity extends HttpEntity {
return false;
}
RequestEntity> otherEntity = (RequestEntity>) other;
- return (ObjectUtils.nullSafeEquals(getMethod(), otherEntity.getMethod()) &&
- ObjectUtils.nullSafeEquals(getUrl(), otherEntity.getUrl()));
+ return (ObjectUtils.nullSafeEquals(this.method, otherEntity.method) &&
+ ObjectUtils.nullSafeEquals(this.url, otherEntity.url));
}
@Override
public int hashCode() {
int hashCode = super.hashCode();
hashCode = 29 * hashCode + ObjectUtils.nullSafeHashCode(this.method);
- hashCode = 29 * hashCode + ObjectUtils.nullSafeHashCode(getUrl());
+ hashCode = 29 * hashCode + ObjectUtils.nullSafeHashCode(this.url);
return hashCode;
}
@@ -544,13 +544,13 @@ public class RequestEntity extends HttpEntity {
private final URI uri;
@Nullable
- String uriTemplate;
+ private final String uriTemplate;
@Nullable
- private Object[] uriVarsArray;
+ private final Object[] uriVarsArray;
@Nullable
- Map uriVarsMap;
+ private final Map uriVarsMap;
DefaultBodyBuilder(HttpMethod method, URI url) {
this.method = method;
@@ -661,7 +661,7 @@ public class RequestEntity extends HttpEntity {
return buildInternal(body, type);
}
- private RequestEntity buildInternal(@Nullable T body, @Nullable Type type) {
+ private RequestEntity buildInternal(@Nullable T body, @Nullable Type type) {
if (this.uri != null) {
return new RequestEntity<>(body, this.headers, this.method, this.uri, type);
}
@@ -716,6 +716,25 @@ public class RequestEntity extends HttpEntity {
return this.uriVarsMap;
}
+ @Override
+ public boolean equals(@Nullable Object other) {
+ if (this == other) {
+ return true;
+ }
+ if (!super.equals(other)) {
+ return false;
+ }
+ UriTemplateRequestEntity> otherEntity = (UriTemplateRequestEntity>) other;
+ return (ObjectUtils.nullSafeEquals(this.uriTemplate, otherEntity.uriTemplate) &&
+ ObjectUtils.nullSafeEquals(this.uriVarsArray, otherEntity.uriVarsArray) &&
+ ObjectUtils.nullSafeEquals(this.uriVarsMap, otherEntity.uriVarsMap));
+ }
+
+ @Override
+ public int hashCode() {
+ return (29 * super.hashCode() + ObjectUtils.nullSafeHashCode(this.uriTemplate));
+ }
+
@Override
public String toString() {
return format(getMethod(), getUriTemplate(), getBody(), getHeaders());
diff --git a/spring-web/src/main/java/org/springframework/web/bind/MethodArgumentNotValidException.java b/spring-web/src/main/java/org/springframework/web/bind/MethodArgumentNotValidException.java
index e51f136e475..3638ac1411b 100644
--- a/spring-web/src/main/java/org/springframework/web/bind/MethodArgumentNotValidException.java
+++ b/spring-web/src/main/java/org/springframework/web/bind/MethodArgumentNotValidException.java
@@ -56,8 +56,8 @@ public class MethodArgumentNotValidException extends BindException {
@Override
public String getMessage() {
StringBuilder sb = new StringBuilder("Validation failed for argument [")
- .append(this.parameter.getParameterIndex()).append("] in ")
- .append(this.parameter.getExecutable().toGenericString());
+ .append(this.parameter.getParameterIndex()).append("] in ")
+ .append(this.parameter.getExecutable().toGenericString());
BindingResult bindingResult = getBindingResult();
if (bindingResult.getErrorCount() > 1) {
sb.append(" with ").append(bindingResult.getErrorCount()).append(" errors");
diff --git a/spring-web/src/test/java/org/springframework/http/RequestEntityTests.java b/spring-web/src/test/java/org/springframework/http/RequestEntityTests.java
index e165ef8082d..1c979728f9b 100644
--- a/spring-web/src/test/java/org/springframework/http/RequestEntityTests.java
+++ b/spring-web/src/test/java/org/springframework/http/RequestEntityTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2020 the original author or authors.
+ * Copyright 2002-2021 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.
@@ -20,6 +20,7 @@ import java.net.URI;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
+import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -175,4 +176,37 @@ class RequestEntityTests {
assertThat(entity.getType()).isEqualTo(typeReference.getType());
}
+ @Test
+ void equalityWithUrl() {
+ RequestEntity requestEntity1 = RequestEntity.method(HttpMethod.GET, "http://test.api/path/").build();
+ RequestEntity requestEntity2 = RequestEntity.method(HttpMethod.GET, "http://test.api/path/").build();
+ RequestEntity requestEntity3 = RequestEntity.method(HttpMethod.GET, "http://test.api/pathX/").build();
+
+ assertThat(requestEntity1).isEqualTo(requestEntity2);
+ assertThat(requestEntity2).isEqualTo(requestEntity1);
+ assertThat(requestEntity1).isNotEqualTo(requestEntity3);
+ assertThat(requestEntity3).isNotEqualTo(requestEntity2);
+ assertThat(requestEntity1.hashCode()).isEqualTo(requestEntity2.hashCode());
+ assertThat(requestEntity1.hashCode()).isNotEqualTo(requestEntity3.hashCode());
+ }
+
+ @Test // gh-27531
+ void equalityWithUriTemplate() {
+ Map vars = Collections.singletonMap("id", "1");
+
+ RequestEntity requestEntity1 =
+ RequestEntity.method(HttpMethod.GET, "http://test.api/path/{id}", vars).build();
+ RequestEntity requestEntity2 =
+ RequestEntity.method(HttpMethod.GET, "http://test.api/path/{id}", vars).build();
+ RequestEntity requestEntity3 =
+ RequestEntity.method(HttpMethod.GET, "http://test.api/pathX/{id}", vars).build();
+
+ assertThat(requestEntity1).isEqualTo(requestEntity2);
+ assertThat(requestEntity2).isEqualTo(requestEntity1);
+ assertThat(requestEntity1).isNotEqualTo(requestEntity3);
+ assertThat(requestEntity3).isNotEqualTo(requestEntity2);
+ assertThat(requestEntity1.hashCode()).isEqualTo(requestEntity2.hashCode());
+ assertThat(requestEntity1.hashCode()).isNotEqualTo(requestEntity3.hashCode());
+ }
+
}
diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/AbstractHandlerMethodMapping.java b/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/AbstractHandlerMethodMapping.java
index 4487162cc9e..7d59209955d 100644
--- a/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/AbstractHandlerMethodMapping.java
+++ b/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/AbstractHandlerMethodMapping.java
@@ -157,12 +157,10 @@ public abstract class AbstractHandlerMethodMapping extends AbstractHandlerMap
*/
@Override
public void afterPropertiesSet() {
-
initHandlerMethods();
- // Total includes detected mappings + explicit registrations via registerMapping..
- int total = this.getHandlerMethods().size();
-
+ // Total includes detected mappings + explicit registrations via registerMapping
+ int total = getHandlerMethods().size();
if ((logger.isTraceEnabled() && total == 0) || (logger.isDebugEnabled() && total > 0) ) {
logger.debug(total + " mappings in " + formatMappingName());
}
diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/support/DefaultHandlerExceptionResolver.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/support/DefaultHandlerExceptionResolver.java
index 140214b29c9..dfd379d7ac4 100644
--- a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/support/DefaultHandlerExceptionResolver.java
+++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/support/DefaultHandlerExceptionResolver.java
@@ -519,7 +519,7 @@ public class DefaultHandlerExceptionResolver extends AbstractHandlerExceptionRes
/**
* Handle the case where an async request timed out.
* The default implementation sends an HTTP 503 error.
- * @param ex the {@link AsyncRequestTimeoutException }to be handled
+ * @param ex the {@link AsyncRequestTimeoutException} to be handled
* @param request current HTTP request
* @param response current HTTP response
* @param handler the executed handler, or {@code null} if none chosen