From 534f123fe81a7221da67d190ea1ebdeac7ba2512 Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Tue, 4 Mar 2025 18:44:25 +0100 Subject: [PATCH 1/2] Add explicit FileSystemResource path check for trailing slash Closes gh-34509 --- .../resource/ResourceHandlerUtils.java | 11 +++++++---- .../PathResourceLookupFunctionTests.java | 19 ++++++++++++++++--- .../resource/ResourceHandlerUtils.java | 11 +++++++---- .../PathResourceLookupFunctionTests.java | 16 +++++++++++++++- 4 files changed, 45 insertions(+), 12 deletions(-) diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/resource/ResourceHandlerUtils.java b/spring-webflux/src/main/java/org/springframework/web/reactive/resource/ResourceHandlerUtils.java index 019ffa5a44..667911a322 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/resource/ResourceHandlerUtils.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/resource/ResourceHandlerUtils.java @@ -24,7 +24,7 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.core.io.ClassPathResource; -import org.springframework.core.io.PathResource; +import org.springframework.core.io.FileSystemResource; import org.springframework.core.io.Resource; import org.springframework.core.io.UrlResource; import org.springframework.core.log.LogFormatUtils; @@ -57,15 +57,18 @@ public abstract class ResourceHandlerUtils { Assert.notNull(location, "Resource location must not be null"); try { String path; - if (location instanceof PathResource) { + if (location instanceof org.springframework.core.io.PathResource) { return; } - else if (location instanceof UrlResource) { - path = location.getURL().toExternalForm(); + else if (location instanceof FileSystemResource fileSystemResource) { + path = fileSystemResource.getPath(); } else if (location instanceof ClassPathResource classPathResource) { path = classPathResource.getPath(); } + else if (location instanceof UrlResource) { + path = location.getURL().toExternalForm(); + } else { path = location.getURL().getPath(); } diff --git a/spring-webflux/src/test/java/org/springframework/web/reactive/function/server/PathResourceLookupFunctionTests.java b/spring-webflux/src/test/java/org/springframework/web/reactive/function/server/PathResourceLookupFunctionTests.java index b28db67d28..08bf35bdcd 100644 --- a/spring-webflux/src/test/java/org/springframework/web/reactive/function/server/PathResourceLookupFunctionTests.java +++ b/spring-webflux/src/test/java/org/springframework/web/reactive/function/server/PathResourceLookupFunctionTests.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. @@ -26,6 +26,7 @@ import reactor.core.publisher.Mono; import reactor.test.StepVerifier; import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.FileSystemResource; import org.springframework.core.io.Resource; import org.springframework.web.testfixture.http.server.reactive.MockServerHttpRequest; import org.springframework.web.testfixture.server.MockServerWebExchange; @@ -39,8 +40,7 @@ class PathResourceLookupFunctionTests { void normal() throws Exception { ClassPathResource location = new ClassPathResource("org/springframework/web/reactive/function/server/"); - PathResourceLookupFunction - function = new PathResourceLookupFunction("/resources/**", location); + PathResourceLookupFunction function = new PathResourceLookupFunction("/resources/**", location); MockServerHttpRequest mockRequest = MockServerHttpRequest.get("https://localhost/resources/response.txt").build(); ServerRequest request = new DefaultServerRequest(MockServerWebExchange.from(mockRequest), Collections.emptyList()); Mono result = function.apply(request); @@ -124,4 +124,17 @@ class PathResourceLookupFunctionTests { .verify(); } + @Test + @SuppressWarnings("removal") + void withPathResource() { + org.springframework.core.io.PathResource location = new org.springframework.core.io.PathResource("/static/"); + PathResourceLookupFunction function = new PathResourceLookupFunction("/resources/**", location); + } + + @Test + void withFileSystemResource() { + FileSystemResource location = new FileSystemResource("/static/"); + PathResourceLookupFunction function = new PathResourceLookupFunction("/resources/**", location); + } + } diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/resource/ResourceHandlerUtils.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/resource/ResourceHandlerUtils.java index a2effd4256..6e1f986cd7 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/resource/ResourceHandlerUtils.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/resource/ResourceHandlerUtils.java @@ -24,7 +24,7 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.core.io.ClassPathResource; -import org.springframework.core.io.PathResource; +import org.springframework.core.io.FileSystemResource; import org.springframework.core.io.Resource; import org.springframework.core.io.UrlResource; import org.springframework.core.log.LogFormatUtils; @@ -58,15 +58,18 @@ public abstract class ResourceHandlerUtils { Assert.notNull(location, "Resource location must not be null"); try { String path; - if (location instanceof PathResource) { + if (location instanceof org.springframework.core.io.PathResource) { return; } - else if (location instanceof UrlResource) { - path = location.getURL().toExternalForm(); + else if (location instanceof FileSystemResource fileSystemResource) { + path = fileSystemResource.getPath(); } else if (location instanceof ClassPathResource classPathResource) { path = classPathResource.getPath(); } + else if (location instanceof UrlResource) { + path = location.getURL().toExternalForm(); + } else { path = location.getURL().getPath(); } diff --git a/spring-webmvc/src/test/java/org/springframework/web/servlet/function/PathResourceLookupFunctionTests.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/function/PathResourceLookupFunctionTests.java index 33ad38b0ba..582ae35295 100644 --- a/spring-webmvc/src/test/java/org/springframework/web/servlet/function/PathResourceLookupFunctionTests.java +++ b/spring-webmvc/src/test/java/org/springframework/web/servlet/function/PathResourceLookupFunctionTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2023 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. @@ -24,6 +24,7 @@ import java.util.function.Function; import org.junit.jupiter.api.Test; import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.FileSystemResource; import org.springframework.core.io.Resource; import org.springframework.web.servlet.handler.PathPatternsTestUtils; @@ -102,4 +103,17 @@ class PathResourceLookupFunctionTests { Collections.emptyList()); } + @Test + @SuppressWarnings("removal") + void withPathResource() { + org.springframework.core.io.PathResource location = new org.springframework.core.io.PathResource("/static/"); + PathResourceLookupFunction function = new PathResourceLookupFunction("/resources/**", location); + } + + @Test + void withFileSystemResource() { + FileSystemResource location = new FileSystemResource("/static/"); + PathResourceLookupFunction function = new PathResourceLookupFunction("/resources/**", location); + } + } From 403362fe3c720d84a619cf2a06bd56c91d8040c4 Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Tue, 4 Mar 2025 18:44:56 +0100 Subject: [PATCH 2/2] Polishing --- .../beans/factory/aot/InstanceSupplierCodeGenerator.java | 3 ++- .../main/java/org/springframework/util/StringUtils.java | 8 ++++---- .../springframework/core/GenericTypeResolverTests.java | 2 +- .../servlet/function/ResourceHandlerFunctionTests.java | 3 ++- 4 files changed, 9 insertions(+), 7 deletions(-) diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/aot/InstanceSupplierCodeGenerator.java b/spring-beans/src/main/java/org/springframework/beans/factory/aot/InstanceSupplierCodeGenerator.java index b70c6f287d..3e03043075 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/aot/InstanceSupplierCodeGenerator.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/aot/InstanceSupplierCodeGenerator.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. @@ -443,6 +443,7 @@ public class InstanceSupplierCodeGenerator { } } + record ConstructorDescriptor(String beanName, Constructor constructor, Class publicType) { Class actualType() { diff --git a/spring-core/src/main/java/org/springframework/util/StringUtils.java b/spring-core/src/main/java/org/springframework/util/StringUtils.java index 86fc164c8c..deed77ff40 100644 --- a/spring-core/src/main/java/org/springframework/util/StringUtils.java +++ b/spring-core/src/main/java/org/springframework/util/StringUtils.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. @@ -787,9 +787,9 @@ public abstract class StringUtils { pathElements.addFirst(CURRENT_PATH); } - final String joined = collectionToDelimitedString(pathElements, FOLDER_SEPARATOR); - // avoid string concatenation with empty prefix - return prefix.isEmpty() ? joined : prefix + joined; + String joined = collectionToDelimitedString(pathElements, FOLDER_SEPARATOR); + // Avoid String concatenation with empty prefix + return (prefix.isEmpty() ? joined : prefix + joined); } /** diff --git a/spring-core/src/test/java/org/springframework/core/GenericTypeResolverTests.java b/spring-core/src/test/java/org/springframework/core/GenericTypeResolverTests.java index df63c65e24..21ab4004fe 100644 --- a/spring-core/src/test/java/org/springframework/core/GenericTypeResolverTests.java +++ b/spring-core/src/test/java/org/springframework/core/GenericTypeResolverTests.java @@ -461,7 +461,7 @@ class GenericTypeResolverTests { } } - public interface InterfaceWithDefaultMethod { + public interface InterfaceWithDefaultMethod { default String get(T input) { throw new UnsupportedOperationException(); diff --git a/spring-webmvc/src/test/java/org/springframework/web/servlet/function/ResourceHandlerFunctionTests.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/function/ResourceHandlerFunctionTests.java index 9c6d9320fd..781bad421c 100644 --- a/spring-webmvc/src/test/java/org/springframework/web/servlet/function/ResourceHandlerFunctionTests.java +++ b/spring-webmvc/src/test/java/org/springframework/web/servlet/function/ResourceHandlerFunctionTests.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. @@ -56,6 +56,7 @@ class ResourceHandlerFunctionTests { private ResourceHttpMessageConverter messageConverter; + @BeforeEach void createContext() { this.messageConverter = new ResourceHttpMessageConverter();