Skip to content

Commit

Permalink
ClassPathResource.isReadable() checks InputStream (for jar directories)
Browse files Browse the repository at this point in the history
Resource.isReadable() is defined to semantically imply exists() now.

Issue: SPR-16832
  • Loading branch information
jhoeller committed May 29, 2018
1 parent 8593fec commit 69f14a2
Show file tree
Hide file tree
Showing 6 changed files with 54 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URI;
import java.net.URL;
Expand Down Expand Up @@ -70,19 +69,18 @@ else if (code == HttpURLConnection.HTTP_NOT_FOUND) {
return true;
}
if (httpCon != null) {
// no HTTP OK status, and no content-length header: give up
// No HTTP OK status, and no content-length header: give up
httpCon.disconnect();
return false;
}
else {
// Fall back to stream existence: can we open the stream?
InputStream is = getInputStream();
is.close();
getInputStream().close();
return true;
}
}
}
catch (IOException ex) {
catch (Exception ex) {
return false;
}
}
Expand All @@ -97,10 +95,33 @@ public boolean isReadable() {
return (file.canRead() && !file.isDirectory());
}
else {
// Try InputStream resolution for jar resources
URLConnection con = url.openConnection();
customizeConnection(con);
if (con instanceof HttpURLConnection) {
HttpURLConnection httpCon = (HttpURLConnection) con;
int code = httpCon.getResponseCode();
if (code != HttpURLConnection.HTTP_OK) {
httpCon.disconnect();
return false;
}
}
int contentLength = con.getContentLength();
if (contentLength > 0) {
return true;
}
else if (contentLength < 0) {
return false;
}
// 0 length: either an empty file or a directory...
// On current JDKs, this will trigger an NPE from within the close() call
// for directories, only returning true for actual files with 0 length.
getInputStream().close();
return true;
}
}
catch (IOException ex) {
catch (Exception ex) {
// Usually an IOException but potentially a NullPointerException (see above)
return false;
}
}
Expand All @@ -114,7 +135,7 @@ public boolean isFile() {
}
return ResourceUtils.URL_PROTOCOL_FILE.equals(url.getProtocol());
}
catch (IOException ex) {
catch (Exception ex) {
return false;
}
}
Expand Down Expand Up @@ -165,7 +186,7 @@ protected boolean isFile(URI uri) {
}
return ResourceUtils.URL_PROTOCOL_FILE.equals(uri.getScheme());
}
catch (IOException ex) {
catch (Exception ex) {
return false;
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2018 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.
Expand Down Expand Up @@ -57,8 +57,7 @@ public boolean exists() {
catch (IOException ex) {
// Fall back to stream existence: can we open the stream?
try {
InputStream is = getInputStream();
is.close();
getInputStream().close();
return true;
}
catch (Throwable isEx) {
Expand All @@ -68,11 +67,12 @@ public boolean exists() {
}

/**
* This implementation always returns {@code true}.
* This implementation always returns {@code true} for a resource
* that {@link #exists() exists} (revised as of 5.1).
*/
@Override
public boolean isReadable() {
return true;
return exists();
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2018 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.
Expand Down Expand Up @@ -62,14 +62,16 @@ public interface Resource extends InputStreamSource {
/**
* Indicate whether the contents of this resource can be read via
* {@link #getInputStream()}.
* <p>Will be {@code true} for typical resource descriptors;
* note that actual content reading may still fail when attempted.
* <p>Will be {@code true} for typical resource descriptors that exist
* since it strictly implies {@link #exists()} semantics as of 5.1.
* Note that actual content reading may still fail when attempted.
* However, a value of {@code false} is a definitive indication
* that the resource content cannot be read.
* @see #getInputStream()
* @see #exists()
*/
default boolean isReadable() {
return true;
return exists();
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2018 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.
Expand Down Expand Up @@ -109,6 +109,17 @@ public void preserveLeadingSlashForClassRelativeAccess() {
assertEquals("/test.html", ((ClassPathResource) new ClassPathResource("", getClass()).createRelative("/test.html")).getPath());
}

@Test
public void directoryNotReadable() {
Resource fileDir = new ClassPathResource("org/springframework/core");
assertTrue(fileDir.exists());
assertFalse(fileDir.isReadable());

Resource jarDir = new ClassPathResource("reactor/core");
assertTrue(jarDir.exists());
assertFalse(jarDir.isReadable());
}


private void assertDescriptionContainsExpectedPath(ClassPathResource resource, String expectedPath) {
Matcher matcher = DESCRIPTION_PATTERN.matcher(resource.getDescription());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ private Mono<Resource> getResource(String resourcePath, List<? extends Resource>
protected Mono<Resource> getResource(String resourcePath, Resource location) {
try {
Resource resource = location.createRelative(resourcePath);
if (resource.exists() && resource.isReadable()) {
if (resource.isReadable()) {
if (checkResource(resource, location)) {
if (logger.isTraceEnabled()) {
logger.trace("Found match: " + resource);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ else if (logger.isTraceEnabled()) {
@Nullable
protected Resource getResource(String resourcePath, Resource location) throws IOException {
Resource resource = location.createRelative(resourcePath);
if (resource.exists() && resource.isReadable()) {
if (resource.isReadable()) {
if (checkResource(resource, location)) {
return resource;
}
Expand Down

0 comments on commit 69f14a2

Please sign in to comment.