diff --git a/spring-core/src/main/java/org/springframework/core/io/AbstractFileResolvingResource.java b/spring-core/src/main/java/org/springframework/core/io/AbstractFileResolvingResource.java index 8f61f36b94..7d1ef88e52 100644 --- a/spring-core/src/main/java/org/springframework/core/io/AbstractFileResolvingResource.java +++ b/spring-core/src/main/java/org/springframework/core/io/AbstractFileResolvingResource.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2017 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,6 +17,7 @@ package org.springframework.core.io; import java.io.File; +import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.net.HttpURLConnection; @@ -89,11 +90,11 @@ public abstract class AbstractFileResolvingResource extends AbstractResource { try { URL url = getURL(); if (ResourceUtils.isFileURL(url)) { - // Proceed with file system resolution... + // Proceed with file system resolution return getFile().exists(); } else { - // Try a URL connection content-length header... + // Try a URL connection content-length header URLConnection con = url.openConnection(); customizeConnection(con); HttpURLConnection httpCon = @@ -133,7 +134,7 @@ public abstract class AbstractFileResolvingResource extends AbstractResource { try { URL url = getURL(); if (ResourceUtils.isFileURL(url)) { - // Proceed with file system resolution... + // Proceed with file system resolution File file = getFile(); return (file.canRead() && !file.isDirectory()); } @@ -150,11 +151,11 @@ public abstract class AbstractFileResolvingResource extends AbstractResource { public long contentLength() throws IOException { URL url = getURL(); if (ResourceUtils.isFileURL(url)) { - // Proceed with file system resolution... + // Proceed with file system resolution return getFile().length(); } else { - // Try a URL connection content-length header... + // Try a URL connection content-length header URLConnection con = url.openConnection(); customizeConnection(con); return con.getContentLength(); @@ -165,15 +166,18 @@ public abstract class AbstractFileResolvingResource extends AbstractResource { public long lastModified() throws IOException { URL url = getURL(); if (ResourceUtils.isFileURL(url) || ResourceUtils.isJarURL(url)) { - // Proceed with file system resolution... - return super.lastModified(); - } - else { - // Try a URL connection last-modified header... - URLConnection con = url.openConnection(); - customizeConnection(con); - return con.getLastModified(); + // Proceed with file system resolution + try { + return super.lastModified(); + } + catch (FileNotFoundException ex) { + // Defensively fall back to URL connection check instead + } } + // Try a URL connection last-modified header + URLConnection con = url.openConnection(); + customizeConnection(con); + return con.getLastModified(); } diff --git a/spring-core/src/main/java/org/springframework/core/io/AbstractResource.java b/spring-core/src/main/java/org/springframework/core/io/AbstractResource.java index 1bc9e1b934..7d38cee93f 100644 --- a/spring-core/src/main/java/org/springframework/core/io/AbstractResource.java +++ b/spring-core/src/main/java/org/springframework/core/io/AbstractResource.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2017 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. @@ -119,7 +119,6 @@ public abstract class AbstractResource implements Resource { * content length. Subclasses will almost always be able to provide * a more optimal version of this, e.g. checking a File length. * @see #getInputStream() - * @throws IllegalStateException if {@link #getInputStream()} returns null. */ @Override public long contentLength() throws IOException { @@ -162,8 +161,9 @@ public abstract class AbstractResource implements Resource { * Determine the File to use for timestamp checking. *

The default implementation delegates to {@link #getFile()}. * @return the File to use for timestamp checking (never {@code null}) - * @throws IOException if the resource cannot be resolved as absolute - * file path, i.e. if the resource is not available in a file system + * @throws FileNotFoundException if the resource cannot be resolved as + * an absolute file path, i.e. is not available in a file system + * @throws IOException in case of general resolution/reading failures */ protected File getFileForLastModifiedCheck() throws IOException { return getFile(); 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 f7d1d7fec2..7d617cc6ab 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 @@ -583,10 +583,13 @@ public class PathMatchingResourcePatternResolver implements ResourcePatternResol // We'll also handle paths with and without leading "file:" prefix. String urlFile = rootDirURL.getFile(); try { - int separatorIndex = urlFile.indexOf(ResourceUtils.JAR_URL_SEPARATOR); + int separatorIndex = urlFile.indexOf(ResourceUtils.WAR_URL_SEPARATOR); + if (separatorIndex == -1) { + separatorIndex = urlFile.indexOf(ResourceUtils.JAR_URL_SEPARATOR); + } if (separatorIndex != -1) { jarFileUrl = urlFile.substring(0, separatorIndex); - rootEntryPath = urlFile.substring(separatorIndex + ResourceUtils.JAR_URL_SEPARATOR.length()); + rootEntryPath = urlFile.substring(separatorIndex + 2); // both separators are 2 chars jarFile = getJarFile(jarFileUrl); } else {