diff --git a/spring-core/src/main/java/org/springframework/core/io/DefaultResourceLoader.java b/spring-core/src/main/java/org/springframework/core/io/DefaultResourceLoader.java index cde09fe8e54..b63b7f5746e 100644 --- a/spring-core/src/main/java/org/springframework/core/io/DefaultResourceLoader.java +++ b/spring-core/src/main/java/org/springframework/core/io/DefaultResourceLoader.java @@ -27,6 +27,7 @@ import java.util.concurrent.ConcurrentHashMap; import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; +import org.springframework.util.ResourceUtils; import org.springframework.util.StringUtils; /** @@ -160,7 +161,7 @@ public class DefaultResourceLoader implements ResourceLoader { try { // Try to parse the location as a URL... URL url = new URL(location); - return new UrlResource(url); + return (ResourceUtils.isFileURL(url) ? new FileUrlResource(url) : new UrlResource(url)); } catch (MalformedURLException ex) { // No URL -> resolve as resource path. diff --git a/spring-core/src/main/java/org/springframework/core/io/FileSystemResource.java b/spring-core/src/main/java/org/springframework/core/io/FileSystemResource.java index 80f86d85eaa..c7e1276f300 100644 --- a/spring-core/src/main/java/org/springframework/core/io/FileSystemResource.java +++ b/spring-core/src/main/java/org/springframework/core/io/FileSystemResource.java @@ -183,7 +183,7 @@ public class FileSystemResource extends AbstractResource implements WritableReso */ @Override public ReadableByteChannel readableChannel() throws IOException { - return FileChannel.open(getFile().toPath(), StandardOpenOption.READ); + return FileChannel.open(this.file.toPath(), StandardOpenOption.READ); } /** @@ -192,7 +192,7 @@ public class FileSystemResource extends AbstractResource implements WritableReso */ @Override public WritableByteChannel writableChannel() throws IOException { - return FileChannel.open(getFile().toPath(), StandardOpenOption.WRITE); + return FileChannel.open(this.file.toPath(), StandardOpenOption.WRITE); } /** diff --git a/spring-core/src/main/java/org/springframework/core/io/FileUrlResource.java b/spring-core/src/main/java/org/springframework/core/io/FileUrlResource.java new file mode 100644 index 00000000000..973b19a8bf5 --- /dev/null +++ b/spring-core/src/main/java/org/springframework/core/io/FileUrlResource.java @@ -0,0 +1,101 @@ +/* + * 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.core.io; + +import java.io.File; +import java.io.IOException; +import java.io.OutputStream; +import java.net.MalformedURLException; +import java.net.URL; +import java.nio.channels.FileChannel; +import java.nio.channels.WritableByteChannel; +import java.nio.file.Files; +import java.nio.file.StandardOpenOption; + +import org.springframework.util.ResourceUtils; + +/** + * Subclass of {@link UrlResource} which assumes file resolution, to the degree + * of implementing the {@link WritableResource} interface for it. + * + *
This is the class resolved by {@link DefaultResourceLoader} for a "file:..." + * URL location, allowing a downcast to {@link WritableResource} for it. + * + *
Alternatively, for direct construction from a {@link java.io.File} handle, + * consider using {@link FileSystemResource}. For an NIO {@link java.nio.file.Path}, + * consider using {@link PathResource} instead. + * + * @author Juergen Hoeller + * @since 5.0.2 + */ +public class FileUrlResource extends UrlResource implements WritableResource { + + /** + * Create a new {@code FileUrlResource} based on the given URL object. + *
Note that this does not enforce "file" as URL protocol. If a protocol + * is known to be resolvable to a file, + * @param url a URL + * @see ResourceUtils#isFileURL(URL) + * @see #getFile() + */ + public FileUrlResource(URL url) { + super(url); + } + + /** + * Create a new {@code FileUrlResource} based on the given file location, + * using the URL protocol "file". + *
The given parts will automatically get encoded if necessary. + * @param location the location (i.e. the file path within that protocol) + * @throws MalformedURLException if the given URL specification is not valid + * @see UrlResource#UrlResource(String, String) + * @see ResourceUtils#URL_PROTOCOL_FILE + */ + public FileUrlResource(String location) throws MalformedURLException { + super(ResourceUtils.URL_PROTOCOL_FILE, location); + } + + + @Override + public boolean isWritable() { + try { + URL url = getURL(); + if (ResourceUtils.isFileURL(url)) { + // Proceed with file system resolution + File file = getFile(); + return (file.canWrite() && !file.isDirectory()); + } + else { + return true; + } + } + catch (IOException ex) { + return false; + } + } + + @Override + public OutputStream getOutputStream() throws IOException { + return Files.newOutputStream(getFile().toPath()); + } + + @Override + public WritableByteChannel writableChannel() throws IOException { + return FileChannel.open(getFile().toPath(), StandardOpenOption.WRITE); + } + +}