From ce0832ae9290e2314baba0d6d2be7300233d4f7a Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Fri, 7 Aug 2020 12:59:41 +0200 Subject: [PATCH] Avoid unnecessary computation of cleaned URL Closes gh-25531 (cherry picked from commit 96a4e1150e608a66998988f5d4903297ef11e977) --- .../springframework/core/io/UrlResource.java | 47 ++++++++++++------- 1 file changed, 31 insertions(+), 16 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 e12c3826c7ea..2f02e0f5de29 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-2018 the original author or authors. + * Copyright 2002-2020 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,7 +56,8 @@ public class UrlResource extends AbstractFileResolvingResource { /** * Cleaned URL (with normalized path), used for comparisons. */ - private final URL cleanedUrl; + @Nullable + private volatile URL cleanedUrl; /** @@ -69,7 +70,6 @@ public UrlResource(URI uri) throws MalformedURLException { Assert.notNull(uri, "URI must not be null"); this.uri = uri; this.url = uri.toURL(); - this.cleanedUrl = getCleanedUrl(this.url, uri.toString()); } /** @@ -78,9 +78,8 @@ public UrlResource(URI uri) throws MalformedURLException { */ public UrlResource(URL url) { Assert.notNull(url, "URL must not be null"); - this.url = url; - this.cleanedUrl = getCleanedUrl(this.url, url.toString()); this.uri = null; + this.url = url; } /** @@ -127,7 +126,6 @@ public UrlResource(String protocol, String location, @Nullable String fragment) try { this.uri = new URI(protocol, location, fragment); this.url = this.uri.toURL(); - this.cleanedUrl = getCleanedUrl(this.url, this.uri.toString()); } catch (URISyntaxException ex) { MalformedURLException exToThrow = new MalformedURLException(ex.getMessage()); @@ -144,17 +142,34 @@ public UrlResource(String protocol, String location, @Nullable String fragment) * @return the cleaned URL * @see org.springframework.util.StringUtils#cleanPath */ - private URL getCleanedUrl(URL originalUrl, String originalPath) { - try { - return new URL(StringUtils.cleanPath(originalPath)); + private static URL getCleanedUrl(URL originalUrl, String originalPath) { + String cleanedPath = StringUtils.cleanPath(originalPath); + if (!cleanedPath.equals(originalPath)) { + try { + return new URL(cleanedPath); + } + catch (MalformedURLException ex) { + // Cleaned URL path cannot be converted to URL -> take original URL. + } } - catch (MalformedURLException ex) { - // Cleaned URL path cannot be converted to URL - // -> take original URL. - return originalUrl; + return originalUrl; + } + + /** + * Lazily determine a cleaned URL for the given original URL. + * @see #getCleanedUrl(URL, String) + */ + private URL getCleanedUrl() { + URL cleanedUrl = this.cleanedUrl; + if (cleanedUrl != null) { + return cleanedUrl; } + cleanedUrl = getCleanedUrl(this.url, (this.uri != null ? this.uri : this.url).toString()); + this.cleanedUrl = cleanedUrl; + return cleanedUrl; } + /** * This implementation opens an InputStream for the given URL. *

It sets the {@code useCaches} flag to {@code false}, @@ -245,7 +260,7 @@ public Resource createRelative(String relativePath) throws MalformedURLException */ @Override public String getFilename() { - return StringUtils.getFilename(this.cleanedUrl.getPath()); + return StringUtils.getFilename(getCleanedUrl().getPath()); } /** @@ -263,7 +278,7 @@ public String getDescription() { @Override public boolean equals(Object other) { return (this == other || (other instanceof UrlResource && - this.cleanedUrl.equals(((UrlResource) other).cleanedUrl))); + getCleanedUrl().equals(((UrlResource) other).getCleanedUrl()))); } /** @@ -271,7 +286,7 @@ public boolean equals(Object other) { */ @Override public int hashCode() { - return this.cleanedUrl.hashCode(); + return getCleanedUrl().hashCode(); } }