Skip to content

Commit aaeb5eb

Browse files
committed
Avoid direct URL construction and URL equality checks
Closes gh-29486
1 parent 0b21c16 commit aaeb5eb

File tree

8 files changed

+87
-59
lines changed

8 files changed

+87
-59
lines changed

spring-beans/src/main/java/org/springframework/beans/factory/xml/ResourceEntityResolver.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2021 the original author or authors.
2+
* Copyright 2002-2022 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -18,7 +18,6 @@
1818

1919
import java.io.File;
2020
import java.io.IOException;
21-
import java.net.URL;
2221
import java.net.URLDecoder;
2322
import java.nio.charset.StandardCharsets;
2423

@@ -30,6 +29,7 @@
3029
import org.springframework.core.io.Resource;
3130
import org.springframework.core.io.ResourceLoader;
3231
import org.springframework.lang.Nullable;
32+
import org.springframework.util.ResourceUtils;
3333

3434
/**
3535
* {@code EntityResolver} implementation that tries to resolve entity references
@@ -82,7 +82,7 @@ public InputSource resolveEntity(@Nullable String publicId, @Nullable String sys
8282
String resourcePath = null;
8383
try {
8484
String decodedSystemId = URLDecoder.decode(systemId, StandardCharsets.UTF_8);
85-
String givenUrl = new URL(decodedSystemId).toString();
85+
String givenUrl = ResourceUtils.toURL(decodedSystemId).toString();
8686
String systemRootUrl = new File("").toURI().toURL().toString();
8787
// Try relative to resource base if currently in system root.
8888
if (givenUrl.startsWith(systemRootUrl)) {
@@ -116,7 +116,7 @@ else if (systemId.endsWith(DTD_SUFFIX) || systemId.endsWith(XSD_SUFFIX)) {
116116
url = "https:" + url.substring(5);
117117
}
118118
try {
119-
source = new InputSource(new URL(url).openStream());
119+
source = new InputSource(ResourceUtils.toURL(url).openStream());
120120
source.setPublicId(publicId);
121121
source.setSystemId(systemId);
122122
}

spring-beans/src/main/java/org/springframework/beans/propertyeditors/PathEditor.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2021 the original author or authors.
2+
* Copyright 2002-2022 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -77,7 +77,7 @@ public void setAsText(String text) throws IllegalArgumentException {
7777
boolean nioPathCandidate = !text.startsWith(ResourceUtils.CLASSPATH_URL_PREFIX);
7878
if (nioPathCandidate && !text.startsWith("/")) {
7979
try {
80-
URI uri = new URI(text);
80+
URI uri = ResourceUtils.toURI(text);
8181
if (uri.getScheme() != null) {
8282
nioPathCandidate = false;
8383
// Let's try NIO file system providers via Paths.get(URI)

spring-core/src/main/java/org/springframework/core/io/DefaultResourceLoader.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ else if (location.startsWith(CLASSPATH_URL_PREFIX)) {
162162
else {
163163
try {
164164
// Try to parse the location as a URL...
165-
URL url = new URL(location);
165+
URL url = ResourceUtils.toURL(location);
166166
return (ResourceUtils.isFileURL(url) ? new FileUrlResource(url) : new UrlResource(url));
167167
}
168168
catch (MalformedURLException ex) {

spring-core/src/main/java/org/springframework/core/io/UrlResource.java

Lines changed: 17 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131

3232
import org.springframework.lang.Nullable;
3333
import org.springframework.util.Assert;
34+
import org.springframework.util.ResourceUtils;
3435
import org.springframework.util.StringUtils;
3536

3637
/**
@@ -57,10 +58,10 @@ public class UrlResource extends AbstractFileResolvingResource {
5758
private final URL url;
5859

5960
/**
60-
* Cleaned URL (with normalized path), used for comparisons.
61+
* Cleaned URL String (with normalized path), used for comparisons.
6162
*/
6263
@Nullable
63-
private volatile URL cleanedUrl;
64+
private volatile String cleanedUrl;
6465

6566

6667
/**
@@ -97,8 +98,8 @@ public UrlResource(URI uri) throws MalformedURLException {
9798
public UrlResource(String path) throws MalformedURLException {
9899
Assert.notNull(path, "Path must not be null");
99100
this.uri = null;
100-
this.url = new URL(path);
101-
this.cleanedUrl = getCleanedUrl(this.url, path);
101+
this.url = ResourceUtils.toURL(path);
102+
this.cleanedUrl = StringUtils.cleanPath(path);
102103
}
103104

104105
/**
@@ -144,7 +145,7 @@ public UrlResource(String protocol, String location, @Nullable String fragment)
144145
* Create a new {@code UrlResource} from the given {@link URI}.
145146
* <p>This factory method is a convenience for {@link #UrlResource(URI)} that
146147
* catches any {@link MalformedURLException} and rethrows it wrapped in an
147-
* {@link UncheckedIOException}; suitable for use in {@link java.util.Stream}
148+
* {@link UncheckedIOException}; suitable for use in {@link java.util.stream.Stream}
148149
* and {@link java.util.Optional} APIs or other scenarios when a checked
149150
* {@link IOException} is undesirable.
150151
* @param uri a URI
@@ -165,7 +166,7 @@ public static UrlResource from(URI uri) throws UncheckedIOException {
165166
* Create a new {@code UrlResource} from the given URL path.
166167
* <p>This factory method is a convenience for {@link #UrlResource(String)}
167168
* that catches any {@link MalformedURLException} and rethrows it wrapped in an
168-
* {@link UncheckedIOException}; suitable for use in {@link java.util.Stream}
169+
* {@link UncheckedIOException}; suitable for use in {@link java.util.stream.Stream}
169170
* and {@link java.util.Optional} APIs or other scenarios when a checked
170171
* {@link IOException} is undesirable.
171172
* @param path a URL path
@@ -183,36 +184,16 @@ public static UrlResource from(String path) throws UncheckedIOException {
183184
}
184185

185186

186-
/**
187-
* Determine a cleaned URL for the given original URL.
188-
* @param originalUrl the original URL
189-
* @param originalPath the original URL path
190-
* @return the cleaned URL (possibly the original URL as-is)
191-
* @see org.springframework.util.StringUtils#cleanPath
192-
*/
193-
private static URL getCleanedUrl(URL originalUrl, String originalPath) {
194-
String cleanedPath = StringUtils.cleanPath(originalPath);
195-
if (!cleanedPath.equals(originalPath)) {
196-
try {
197-
return new URL(cleanedPath);
198-
}
199-
catch (MalformedURLException ex) {
200-
// Cleaned URL path cannot be converted to URL -> take original URL.
201-
}
202-
}
203-
return originalUrl;
204-
}
205-
206187
/**
207188
* Lazily determine a cleaned URL for the given original URL.
208-
* @see #getCleanedUrl(URL, String)
209189
*/
210-
private URL getCleanedUrl() {
211-
URL cleanedUrl = this.cleanedUrl;
190+
private String getCleanedUrl() {
191+
String cleanedUrl = this.cleanedUrl;
212192
if (cleanedUrl != null) {
213193
return cleanedUrl;
214194
}
215-
cleanedUrl = getCleanedUrl(this.url, (this.uri != null ? this.uri : this.url).toString());
195+
String originalPath = (this.uri != null ? this.uri : this.url).toString();
196+
cleanedUrl = StringUtils.cleanPath(originalPath);
216197
this.cleanedUrl = cleanedUrl;
217198
return cleanedUrl;
218199
}
@@ -305,16 +286,13 @@ public Resource createRelative(String relativePath) throws MalformedURLException
305286
* A leading slash will get dropped; a "#" symbol will get encoded.
306287
* @since 5.2
307288
* @see #createRelative(String)
308-
* @see java.net.URL#URL(java.net.URL, String)
289+
* @see ResourceUtils#toRelativeURL(URL, String)
309290
*/
310291
protected URL createRelativeURL(String relativePath) throws MalformedURLException {
311292
if (relativePath.startsWith("/")) {
312293
relativePath = relativePath.substring(1);
313294
}
314-
// # can appear in filenames, java.net.URL should not treat it as a fragment
315-
relativePath = StringUtils.replace(relativePath, "#", "%23");
316-
// Use the URL constructor for applying the relative path as a URL spec
317-
return new URL(this.url, relativePath);
295+
return ResourceUtils.toRelativeURL(this.url, relativePath);
318296
}
319297

320298
/**
@@ -324,17 +302,18 @@ protected URL createRelativeURL(String relativePath) throws MalformedURLExceptio
324302
* @see java.net.URLDecoder#decode(String, java.nio.charset.Charset)
325303
*/
326304
@Override
305+
@Nullable
327306
public String getFilename() {
328-
String filename = StringUtils.getFilename(getCleanedUrl().getPath());
329-
return URLDecoder.decode(filename, StandardCharsets.UTF_8);
307+
String filename = StringUtils.getFilename(this.uri != null ? this.uri.getPath() : this.url.getPath());
308+
return (filename != null ? URLDecoder.decode(filename, StandardCharsets.UTF_8) : null);
330309
}
331310

332311
/**
333312
* This implementation returns a description that includes the URL.
334313
*/
335314
@Override
336315
public String getDescription() {
337-
return "URL [" + this.url + "]";
316+
return "URL [" + (this.uri != null ? this.uri : this.url) + "]";
338317
}
339318

340319

spring-core/src/main/java/org/springframework/core/io/VfsResource.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424

2525
import org.springframework.lang.Nullable;
2626
import org.springframework.util.Assert;
27+
import org.springframework.util.ResourceUtils;
2728

2829
/**
2930
* JBoss VFS based {@link Resource} implementation.
@@ -115,7 +116,7 @@ public Resource createRelative(String relativePath) throws IOException {
115116
}
116117
}
117118

118-
return new VfsResource(VfsUtils.getRelative(new URL(getURL(), relativePath)));
119+
return new VfsResource(VfsUtils.getRelative(ResourceUtils.toRelativeURL(getURL(), relativePath)));
119120
}
120121

121122
@Override

spring-core/src/main/java/org/springframework/util/ResourceUtils.java

Lines changed: 55 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2018 the original author or authors.
2+
* Copyright 2002-2022 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -109,7 +109,7 @@ public static boolean isUrl(@Nullable String resourceLocation) {
109109
return true;
110110
}
111111
try {
112-
new URL(resourceLocation);
112+
toURL(resourceLocation);
113113
return true;
114114
}
115115
catch (MalformedURLException ex) {
@@ -141,7 +141,7 @@ public static URL getURL(String resourceLocation) throws FileNotFoundException {
141141
}
142142
try {
143143
// try URL
144-
return new URL(resourceLocation);
144+
return toURL(resourceLocation);
145145
}
146146
catch (MalformedURLException ex) {
147147
// no URL -> treat as file path
@@ -181,7 +181,7 @@ public static File getFile(String resourceLocation) throws FileNotFoundException
181181
}
182182
try {
183183
// try URL
184-
return getFile(new URL(resourceLocation));
184+
return getFile(toURL(resourceLocation));
185185
}
186186
catch (MalformedURLException ex) {
187187
// no URL -> treat as file path
@@ -311,15 +311,15 @@ public static URL extractJarFileURL(URL jarUrl) throws MalformedURLException {
311311
if (separatorIndex != -1) {
312312
String jarFile = urlFile.substring(0, separatorIndex);
313313
try {
314-
return new URL(jarFile);
314+
return toURL(jarFile);
315315
}
316316
catch (MalformedURLException ex) {
317317
// Probably no protocol in original jar URL, like "jar:C:/mypath/myjar.jar".
318318
// This usually indicates that the jar file resides in the file system.
319319
if (!jarFile.startsWith("/")) {
320320
jarFile = "/" + jarFile;
321321
}
322-
return new URL(FILE_URL_PREFIX + jarFile);
322+
return toURL(FILE_URL_PREFIX + jarFile);
323323
}
324324
}
325325
else {
@@ -346,11 +346,11 @@ public static URL extractArchiveURL(URL jarUrl) throws MalformedURLException {
346346
// Tomcat's "war:file:...mywar.war*/WEB-INF/lib/myjar.jar!/myentry.txt"
347347
String warFile = urlFile.substring(0, endIndex);
348348
if (URL_PROTOCOL_WAR.equals(jarUrl.getProtocol())) {
349-
return new URL(warFile);
349+
return toURL(warFile);
350350
}
351351
int startIndex = warFile.indexOf(WAR_URL_PREFIX);
352352
if (startIndex != -1) {
353-
return new URL(warFile.substring(startIndex + WAR_URL_PREFIX.length()));
353+
return toURL(warFile.substring(startIndex + WAR_URL_PREFIX.length()));
354354
}
355355
}
356356

@@ -381,6 +381,53 @@ public static URI toURI(String location) throws URISyntaxException {
381381
return new URI(StringUtils.replace(location, " ", "%20"));
382382
}
383383

384+
/**
385+
* Create a URL instance for the given location String,
386+
* going through URI construction and then URL conversion.
387+
* @param location the location String to convert into a URL instance
388+
* @return the URL instance
389+
* @throws MalformedURLException if the location wasn't a valid URL
390+
* @since 6.0
391+
*/
392+
public static URL toURL(String location) throws MalformedURLException {
393+
// Not fully equivalent - but to be moved in the given direction
394+
// since JDK 20 deprecates all direct java.net.URL constructors.
395+
/*
396+
try {
397+
return toURI(location).toURL();
398+
}
399+
catch (URISyntaxException ex) {
400+
MalformedURLException exToThrow = new MalformedURLException(ex.getMessage());
401+
exToThrow.initCause(ex);
402+
throw exToThrow;
403+
}
404+
*/
405+
406+
return new URL(location);
407+
}
408+
409+
/**
410+
* Create a URL instance for the given root URL and relative path,
411+
* going through URI construction and then URL conversion.
412+
* @param root the root URL to start from
413+
* @param relativePath the relative path to apply
414+
* @return the relative URL instance
415+
* @throws MalformedURLException if the end result is not a valid URL
416+
* @since 6.0
417+
*/
418+
public static URL toRelativeURL(URL root, String relativePath) throws MalformedURLException {
419+
// # can appear in filenames, java.net.URL should not treat it as a fragment
420+
relativePath = StringUtils.replace(relativePath, "#", "%23");
421+
422+
// Not fully equivalent - but to be moved in the given direction
423+
// since JDK 20 deprecates all direct java.net.URL constructors.
424+
/*
425+
return toURL(StringUtils.applyRelativePath(root.toString(), relativePath));
426+
*/
427+
428+
return new URL(root, relativePath);
429+
}
430+
384431
/**
385432
* Set the {@link URLConnection#setUseCaches "useCaches"} flag on the
386433
* given connection, preferring {@code false} but leaving the

spring-orm/src/main/java/org/springframework/orm/jpa/persistenceunit/PersistenceUnitReader.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2020 the original author or authors.
2+
* Copyright 2002-2022 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -312,7 +312,7 @@ protected void parseJarFiles(Element persistenceUnit, SpringPersistenceUnitInfo
312312
// relative to the persistence unit root, according to the JPA spec
313313
URL rootUrl = unitInfo.getPersistenceUnitRootUrl();
314314
if (rootUrl != null) {
315-
unitInfo.addJarFileUrl(new URL(rootUrl, value));
315+
unitInfo.addJarFileUrl(ResourceUtils.toRelativeURL(rootUrl, value));
316316
}
317317
else {
318318
logger.warn("Cannot resolve jar-file entry [" + value + "] in persistence unit '" +
@@ -363,7 +363,7 @@ static URL determinePersistenceUnitRootUrl(Resource resource) throws IOException
363363
if (persistenceUnitRoot.endsWith("/")) {
364364
persistenceUnitRoot = persistenceUnitRoot.substring(0, persistenceUnitRoot.length() - 1);
365365
}
366-
return new URL(persistenceUnitRoot);
366+
return ResourceUtils.toURL(persistenceUnitRoot);
367367
}
368368

369369
}

spring-oxm/src/main/java/org/springframework/oxm/jaxb/Jaxb2Marshaller.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2021 the original author or authors.
2+
* Copyright 2002-2022 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -101,6 +101,7 @@
101101
import org.springframework.util.ClassUtils;
102102
import org.springframework.util.FileCopyUtils;
103103
import org.springframework.util.ObjectUtils;
104+
import org.springframework.util.ResourceUtils;
104105
import org.springframework.util.StringUtils;
105106
import org.springframework.util.xml.StaxUtils;
106107

@@ -985,7 +986,7 @@ public String addMtomAttachment(DataHandler dataHandler, String elementNamespace
985986

986987
private String getHost(String elementNamespace, DataHandler dataHandler) {
987988
try {
988-
URI uri = new URI(elementNamespace);
989+
URI uri = ResourceUtils.toURI(elementNamespace);
989990
return uri.getHost();
990991
}
991992
catch (URISyntaxException ex) {

0 commit comments

Comments
 (0)