diff --git a/spring-context/src/main/java/org/springframework/validation/DataBinder.java b/spring-context/src/main/java/org/springframework/validation/DataBinder.java
index 912dad1321d..82eb52ec5fa 100644
--- a/spring-context/src/main/java/org/springframework/validation/DataBinder.java
+++ b/spring-context/src/main/java/org/springframework/validation/DataBinder.java
@@ -1379,6 +1379,9 @@ public class DataBinder implements PropertyEditorRegistry, TypeConverter {
/**
* Return the names of all property values.
+ *
Useful for proactive checks whether there are property values nested
+ * further below the path for a constructor arg. If not then the
+ * constructor arg can be considered missing and not to be instantiated.
* @since 6.1.2
*/
Set getNames();
diff --git a/spring-web/src/main/java/org/springframework/web/method/HandlerMethod.java b/spring-web/src/main/java/org/springframework/web/method/HandlerMethod.java
index 48f7f17803e..2db063ab7da 100644
--- a/spring-web/src/main/java/org/springframework/web/method/HandlerMethod.java
+++ b/spring-web/src/main/java/org/springframework/web/method/HandlerMethod.java
@@ -309,15 +309,19 @@ public class HandlerMethod extends AnnotatedMethod {
}
/**
- * If the provided instance contains a bean name rather than an object instance,
- * the bean name is resolved before a {@link HandlerMethod} is created and returned.
+ * If the {@link #getBean() handler} is a bean name rather than the actual
+ * handler instance, resolve the bean name through Spring configuration
+ * (e.g. for prototype beans), and return a new {@link HandlerMethod}
+ * instance with the resolved handler.
+ * If the {@link #getBean() handler} is not String, return the same instance.
*/
public HandlerMethod createWithResolvedBean() {
- Object handler = this.bean;
- if (this.bean instanceof String beanName) {
- Assert.state(this.beanFactory != null, "Cannot resolve bean name without BeanFactory");
- handler = this.beanFactory.getBean(beanName);
+ if (!(this.bean instanceof String beanName)) {
+ return this;
}
+
+ Assert.state(this.beanFactory != null, "Cannot resolve bean name without BeanFactory");
+ Object handler = this.beanFactory.getBean(beanName);
Assert.notNull(handler, "No handler instance");
return new HandlerMethod(this, handler, false);
}
diff --git a/spring-web/src/test/java/org/springframework/web/method/HandlerMethodTests.java b/spring-web/src/test/java/org/springframework/web/method/HandlerMethodTests.java
index 678b9587f65..660dfa06d6e 100644
--- a/spring-web/src/test/java/org/springframework/web/method/HandlerMethodTests.java
+++ b/spring-web/src/test/java/org/springframework/web/method/HandlerMethodTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2024 the original author or authors.
+ * Copyright 2002-2025 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.
@@ -72,6 +72,13 @@ class HandlerMethodTests {
testValidateReturnValue(target, List.of("getPerson"), false);
}
+ @Test // gh-34277
+ void createWithResolvedBeanSameInstance() {
+ MyClass target = new MyClass();
+ HandlerMethod handlerMethod = getHandlerMethod(target, "addPerson");
+ assertThat(handlerMethod.createWithResolvedBean()).isSameAs(handlerMethod);
+ }
+
private static void testValidateArgs(Object target, List methodNames, boolean expected) {
for (String methodName : methodNames) {
assertThat(getHandlerMethod(target, methodName).shouldValidateArguments()).isEqualTo(expected);
diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ExtendedServletRequestDataBinder.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ExtendedServletRequestDataBinder.java
index 657a2aa2fec..88b511ee371 100644
--- a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ExtendedServletRequestDataBinder.java
+++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ExtendedServletRequestDataBinder.java
@@ -125,7 +125,7 @@ public class ExtendedServletRequestDataBinder extends ServletRequestDataBinder {
String name = names.nextElement();
Object value = getHeaderValue(httpRequest, name);
if (value != null) {
- name = StringUtils.uncapitalize(name.replace("-", ""));
+ name = normalizeHeaderName(name);
addValueIfNotPresent(mpvs, "Header", name, value);
}
}
@@ -171,6 +171,10 @@ public class ExtendedServletRequestDataBinder extends ServletRequestDataBinder {
return values;
}
+ private static String normalizeHeaderName(String name) {
+ return StringUtils.uncapitalize(name.replace("-", ""));
+ }
+
/**
* Resolver of values that looks up URI path variables.
@@ -206,8 +210,10 @@ public class ExtendedServletRequestDataBinder extends ServletRequestDataBinder {
if (request instanceof HttpServletRequest httpServletRequest) {
Enumeration enumeration = httpServletRequest.getHeaderNames();
while (enumeration.hasMoreElements()) {
- String headerName = enumeration.nextElement();
- set.add(headerName.replaceAll("-", ""));
+ String name = enumeration.nextElement();
+ if (headerPredicate.test(name)) {
+ set.add(normalizeHeaderName(name));
+ }
}
}
return set;
diff --git a/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ExtendedServletRequestDataBinderTests.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ExtendedServletRequestDataBinderTests.java
index 02dc5656994..3164fba945f 100644
--- a/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ExtendedServletRequestDataBinderTests.java
+++ b/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ExtendedServletRequestDataBinderTests.java
@@ -119,6 +119,23 @@ class ExtendedServletRequestDataBinderTests {
assertThat(mpvs).isEmpty();
}
+ @Test
+ void headerPredicateWithConstructorArgs() {
+ ExtendedServletRequestDataBinder binder = new ExtendedServletRequestDataBinder(null);
+ binder.addHeaderPredicate(name -> !name.equalsIgnoreCase("Some-Int-Array"));
+ binder.setTargetType(ResolvableType.forClass(DataBean.class));
+ binder.setNameResolver(new BindParamNameResolver());
+
+ request.addHeader("Some-Int-Array", "1");
+ request.addHeader("Some-Int-Array", "2");
+
+ binder.construct(request);
+
+ DataBean bean = (DataBean) binder.getTarget();
+
+ assertThat(bean.someIntArray()).isNull();
+ }
+
@Test
void headerPredicate() {
TestBinder binder = new TestBinder();
diff --git a/spring-websocket/src/main/java/org/springframework/web/socket/WebSocketSession.java b/spring-websocket/src/main/java/org/springframework/web/socket/WebSocketSession.java
index 802880f59ec..aa3026857c3 100644
--- a/spring-websocket/src/main/java/org/springframework/web/socket/WebSocketSession.java
+++ b/spring-websocket/src/main/java/org/springframework/web/socket/WebSocketSession.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2022 the original author or authors.
+ * Copyright 2002-2025 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.
@@ -72,6 +72,12 @@ public interface WebSocketSession extends Closeable {
/**
* Return the address on which the request was received.
+ * Note: The localAddress is not always possible to access,
+ * which is the case with the Standard WebSocket client. In 6.2.x
+ * {@link org.springframework.web.socket.client.standard.StandardWebSocketClient}
+ * returns an address based on the local host and the port of the target
+ * address (not the same as the local port). In 7.0, the same will return
+ * {@code null} instead.
*/
@Nullable InetSocketAddress getLocalAddress();