From f07e7ab39d04c0f8b27f3e5678227952cc3ac380 Mon Sep 17 00:00:00 2001 From: Sam Brannen Date: Mon, 23 May 2022 14:22:35 +0200 Subject: [PATCH] Create UrlResource factory methods that throw unchecked exceptions UrlResource constructors throw checked exceptions which makes it difficult to use them in java.util.Stream and java.util.Optional APIs or other scenarios when a checked IOException is undesirable. To support such use cases, this commit introduces `from(URI)` and `from(String)` factory methods in UrlResource that throw UncheckedIOExceptions. Closes gh-28501 --- .../springframework/core/io/UrlResource.java | 47 ++++++++++++++++++- .../core/io/ResourceTests.java | 17 ++++++- 2 files changed, 62 insertions(+), 2 deletions(-) diff --git a/spring-core/src/main/java/org/springframework/core/io/UrlResource.java b/spring-core/src/main/java/org/springframework/core/io/UrlResource.java index 3f1dcc05ff..645b4b7051 100644 --- a/spring-core/src/main/java/org/springframework/core/io/UrlResource.java +++ b/spring-core/src/main/java/org/springframework/core/io/UrlResource.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2020 the original author or authors. + * Copyright 2002-2022 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. @@ -19,6 +19,7 @@ package org.springframework.core.io; import java.io.File; import java.io.IOException; import java.io.InputStream; +import java.io.UncheckedIOException; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URI; @@ -37,6 +38,7 @@ import org.springframework.util.StringUtils; * case of the {@code "file:"} protocol. * * @author Juergen Hoeller + * @author Sam Brannen * @since 28.12.2003 * @see java.net.URL */ @@ -135,6 +137,49 @@ public class UrlResource extends AbstractFileResolvingResource { } + /** + * Create a new {@code UrlResource} from the given {@link URI}. + *

This factory method is a convenience for {@link #UrlResource(URI)} that + * catches any {@link MalformedURLException} and rethrows it wrapped in an + * {@link UncheckedIOException}; suitable for use in {@link java.util.Stream} + * and {@link java.util.Optional} APIs or other scenarios when a checked + * {@link IOException} is undesirable. + * @param uri a URI + * @throws UncheckedIOException if the given URL path is not valid + * @since 6.0 + * @see #UrlResource(URI) + */ + public static UrlResource from(URI uri) throws UncheckedIOException { + try { + return new UrlResource(uri); + } + catch (MalformedURLException ex) { + throw new UncheckedIOException(ex); + } + } + + /** + * Create a new {@code UrlResource} from the given URL path. + *

This factory method is a convenience for {@link #UrlResource(String)} + * that catches any {@link MalformedURLException} and rethrows it wrapped in an + * {@link UncheckedIOException}; suitable for use in {@link java.util.Stream} + * and {@link java.util.Optional} APIs or other scenarios when a checked + * {@link IOException} is undesirable. + * @param path a URL path + * @throws UncheckedIOException if the given URL path is not valid + * @since 6.0 + * @see #UrlResource(String) + */ + public static UrlResource from(String path) throws UncheckedIOException { + try { + return new UrlResource(path); + } + catch (MalformedURLException ex) { + throw new UncheckedIOException(ex); + } + } + + /** * Determine a cleaned URL for the given original URL. * @param originalUrl the original URL 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 5a9c8e5d6d..21825f617d 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 @@ -1,5 +1,5 @@ /* - * Copyright 2002-2020 the original author or authors. + * Copyright 2002-2022 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. @@ -208,6 +208,21 @@ class ResourceTests { relative4::lastModified); } + @Test + void urlResourceFactoryMethods() throws IOException { + Resource resource1 = new UrlResource("file:core/io/Resource.class"); + Resource resource2 = UrlResource.from("file:core/io/Resource.class"); + Resource resource3 = UrlResource.from(resource1.getURI()); + + assertThat(resource2.getURL()).isEqualTo(resource1.getURL()); + assertThat(resource3.getURL()).isEqualTo(resource1.getURL()); + + assertThat(UrlResource.from("file:core/../core/io/./Resource.class")).isEqualTo(resource1); + assertThat(UrlResource.from("file:/dir/test.txt?argh").getFilename()).isEqualTo("test.txt"); + assertThat(UrlResource.from("file:\\dir\\test.txt?argh").getFilename()).isEqualTo("test.txt"); + assertThat(UrlResource.from("file:\\dir/test.txt?argh").getFilename()).isEqualTo("test.txt"); + } + @Test void classPathResourceWithRelativePath() throws IOException { Resource resource = new ClassPathResource("dir/");