diff --git a/spring-beans/src/main/java/org/springframework/beans/propertyeditors/ZoneIdEditor.java b/spring-beans/src/main/java/org/springframework/beans/propertyeditors/ZoneIdEditor.java index 4992e33aeb..cee4801e66 100644 --- a/spring-beans/src/main/java/org/springframework/beans/propertyeditors/ZoneIdEditor.java +++ b/spring-beans/src/main/java/org/springframework/beans/propertyeditors/ZoneIdEditor.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2022 the original author or authors. + * Copyright 2002-2024 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. @@ -17,16 +17,18 @@ package org.springframework.beans.propertyeditors; import java.beans.PropertyEditorSupport; +import java.time.DateTimeException; import java.time.ZoneId; import org.springframework.util.StringUtils; /** - * Editor for {@code java.time.ZoneId}, translating zone ID Strings into {@code ZoneId} - * objects. Exposes the {@code TimeZone} ID as a text representation. + * Editor for {@code java.time.ZoneId}, translating time zone Strings into {@code ZoneId} + * objects. Exposes the time zone as a text representation. * * @author Nicholas Williams * @author Sam Brannen + * @author Juergen Hoeller * @since 4.0 * @see java.time.ZoneId * @see TimeZoneEditor @@ -38,7 +40,12 @@ public class ZoneIdEditor extends PropertyEditorSupport { if (StringUtils.hasText(text)) { text = text.trim(); } - setValue(ZoneId.of(text)); + try { + setValue(ZoneId.of(text)); + } + catch (DateTimeException ex) { + throw new IllegalArgumentException(ex.getMessage(), ex); + } } @Override diff --git a/spring-beans/src/test/java/org/springframework/beans/propertyeditors/ZoneIdEditorTests.java b/spring-beans/src/test/java/org/springframework/beans/propertyeditors/ZoneIdEditorTests.java index 535f0ed3ad..932a78fdbd 100644 --- a/spring-beans/src/test/java/org/springframework/beans/propertyeditors/ZoneIdEditorTests.java +++ b/spring-beans/src/test/java/org/springframework/beans/propertyeditors/ZoneIdEditorTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2023 the original author or authors. + * Copyright 2002-2024 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. @@ -23,10 +23,12 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; /** * @author Nicholas Williams * @author Sam Brannen + * @author Juergen Hoeller */ class ZoneIdEditorTests { @@ -69,4 +71,9 @@ class ZoneIdEditorTests { assertThat(editor.getAsText()).as("The text version is not correct.").isEqualTo("America/New_York"); } + @Test + void correctExceptionForInvalid() { + assertThatIllegalArgumentException().isThrownBy(() -> editor.setAsText("INVALID")).withMessageContaining("INVALID"); + } + } diff --git a/spring-core/src/main/java/org/springframework/core/io/support/PathMatchingResourcePatternResolver.java b/spring-core/src/main/java/org/springframework/core/io/support/PathMatchingResourcePatternResolver.java index 8b921c1bda..59fc828119 100644 --- a/spring-core/src/main/java/org/springframework/core/io/support/PathMatchingResourcePatternResolver.java +++ b/spring-core/src/main/java/org/springframework/core/io/support/PathMatchingResourcePatternResolver.java @@ -429,6 +429,7 @@ public class PathMatchingResourcePatternResolver implements ResourcePatternResol * @see #doFindAllClassPathResources * @see #doFindPathMatchingFileResources */ + @SuppressWarnings("deprecation") // on JDK 20 (deprecated URL constructor) protected Resource convertClassLoaderURL(URL url) { if (ResourceUtils.URL_PROTOCOL_FILE.equals(url.getProtocol())) { try { @@ -446,14 +447,10 @@ public class PathMatchingResourcePatternResolver implements ResourcePatternResol if (!cleanedPath.equals(urlString)) { // Prefer cleaned URL, aligned with UrlResource#createRelative(String) try { - // Cannot test for URLStreamHandler directly: URL equality for same String - // in order to find out whether original URL uses default URLStreamHandler. - if (ResourceUtils.toURL(urlString).equals(url)) { - // Plain URL with default URLStreamHandler -> replace with cleaned path. - return new UrlResource(ResourceUtils.toURI(cleanedPath)); - } + // Retain original URL instance, potentially including custom URLStreamHandler. + return new UrlResource(new URL(url, cleanedPath)); } - catch (URISyntaxException | MalformedURLException ex) { + catch (MalformedURLException ex) { // Fallback to regular URL construction below... } } diff --git a/spring-core/src/main/java/org/springframework/util/ResourceUtils.java b/spring-core/src/main/java/org/springframework/util/ResourceUtils.java index ec75c898f9..02c302752c 100644 --- a/spring-core/src/main/java/org/springframework/util/ResourceUtils.java +++ b/spring-core/src/main/java/org/springframework/util/ResourceUtils.java @@ -405,14 +405,14 @@ public abstract class ResourceUtils { * @see java.net.URI#toURL() * @see #toURI(String) */ - @SuppressWarnings("deprecation") // on JDK 20 + @SuppressWarnings("deprecation") // on JDK 20 (deprecated URL constructor) public static URL toURL(String location) throws MalformedURLException { try { // Prefer URI construction with toURL conversion (as of 6.1) return toURI(StringUtils.cleanPath(location)).toURL(); } catch (URISyntaxException | IllegalArgumentException ex) { - // Lenient fallback to deprecated (on JDK 20) URL constructor, + // Lenient fallback to deprecated URL constructor, // e.g. for decoded location Strings with percent characters. return new URL(location); } @@ -429,11 +429,13 @@ public abstract class ResourceUtils { * @see #toURL(String) * @see StringUtils#applyRelativePath */ + @SuppressWarnings("deprecation") // on JDK 20 (deprecated URL constructor) public static URL toRelativeURL(URL root, String relativePath) throws MalformedURLException { // # can appear in filenames, java.net.URL should not treat it as a fragment relativePath = StringUtils.replace(relativePath, "#", "%23"); - return toURL(StringUtils.applyRelativePath(root.toString(), relativePath)); + // Retain original URL instance, potentially including custom URLStreamHandler. + return new URL(root, StringUtils.cleanPath(StringUtils.applyRelativePath(root.toString(), relativePath))); } /** diff --git a/spring-core/src/test/java/org/springframework/core/io/ResourceTests.java b/spring-core/src/test/java/org/springframework/core/io/ResourceTests.java index 8ebe03e00d..220c3ebc6b 100644 --- a/spring-core/src/test/java/org/springframework/core/io/ResourceTests.java +++ b/spring-core/src/test/java/org/springframework/core/io/ResourceTests.java @@ -376,6 +376,13 @@ class ResourceTests { assertThat(relative).isEqualTo(new UrlResource("file:dir/subdir")); } + @Test + void unusualRelativeResourcesAreEqual() throws Exception { + Resource resource = new UrlResource("file:dir/"); + Resource relative = resource.createRelative("http://spring.io"); + assertThat(relative).isEqualTo(new UrlResource("file:dir/http://spring.io")); + } + @Test void missingRemoteResourceDoesNotExist() throws Exception { String baseUrl = startServer();