Merge pull request #295 from marschall/SPR-10608
# By Philippe Marschall * SPR-10608-rebase: Introduce java.nio.file.Path based Resource
This commit is contained in:
@@ -0,0 +1,253 @@
|
||||
/*
|
||||
* Copyright 2002-2013 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.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.OpenOption;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* {@link Resource} implementation for {@code java.nio.file.Path} handles.
|
||||
* Supports resolution as File, and also as URL.
|
||||
* Implements the extended {@link WritableResource} interface.
|
||||
*
|
||||
* @author Philippe Marschall
|
||||
* @since 4.0
|
||||
* @see java.nio.file.Path
|
||||
*/
|
||||
public class PathResource extends AbstractResource implements WritableResource {
|
||||
|
||||
private final Path path;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new PathResource from a Path handle.
|
||||
* <p>Note: Unlike {@link FileSystemResource}, when building relative resources
|
||||
* via {@link #createRelative}, the relative path will be built <i>underneath</i> the
|
||||
* given root:
|
||||
* e.g. Paths.get("C:/dir1/"), relative path "dir2" -> "C:/dir1/dir2"!
|
||||
* @param path a Path handle
|
||||
*/
|
||||
public PathResource(Path path) {
|
||||
Assert.notNull(path, "Path must not be null");
|
||||
this.path = path.normalize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new PathResource from a Path handle.
|
||||
* Create a new PathResource from a Path handle.
|
||||
* <p>Note: Unlike {@link FileSystemResource}, when building relative resources
|
||||
* via {@link #createRelative}, the relative path will be built <i>underneath</i> the
|
||||
* given root:
|
||||
* e.g. Paths.get("C:/dir1/"), relative path "dir2" -> "C:/dir1/dir2"!
|
||||
* @param path a path
|
||||
* @see java.nio.file.Paths#get(String, String...)
|
||||
*/
|
||||
public PathResource(String path) {
|
||||
Assert.notNull(path, "Path must not be null");
|
||||
this.path = Paths.get(path).normalize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new PathResource from a Path handle.
|
||||
* <p>Note: Unlike {@link FileSystemResource}, when building relative resources
|
||||
* via {@link #createRelative}, the relative path will be built <i>underneath</i> the
|
||||
* given root:
|
||||
* e.g. Paths.get("C:/dir1/"), relative path "dir2" -> "C:/dir1/dir2"!
|
||||
* @see java.nio.file.Paths#get(URI)
|
||||
* @param uri a path URI
|
||||
*/
|
||||
public PathResource(URI uri) {
|
||||
Assert.notNull(uri, "URI must not be null");
|
||||
this.path = Paths.get(uri).normalize();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the file path for this resource.
|
||||
*/
|
||||
public final String getPath() {
|
||||
return this.path.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* This implementation returns whether the underlying file exists.
|
||||
* @see org.springframework.core.io.PathResource#exists()
|
||||
*/
|
||||
@Override
|
||||
public boolean exists() {
|
||||
return Files.exists(this.path);
|
||||
}
|
||||
|
||||
/**
|
||||
* This implementation checks whether the underlying file is marked as readable
|
||||
* (and corresponds to an actual file with content, not to a directory).
|
||||
* @see java.nio.file.Files#isReadable(Path)
|
||||
* @see java.nio.file.Files#isDirectory(Path, java.nio.file.LinkOption...)
|
||||
*/
|
||||
@Override
|
||||
public boolean isReadable() {
|
||||
return (Files.isReadable(this.path) && !Files.isDirectory(this.path));
|
||||
}
|
||||
|
||||
/**
|
||||
* This implementation opens a InputStream for the underlying file.
|
||||
* @see java.nio.file.spi.FileSystemProvider#newInputStream(Path, OpenOption...)
|
||||
*/
|
||||
@Override
|
||||
public InputStream getInputStream() throws IOException {
|
||||
if(!exists()) {
|
||||
throw new FileNotFoundException(getPath() + " (No such file or directory)");
|
||||
}
|
||||
if(Files.isDirectory(this.path)) {
|
||||
throw new FileNotFoundException(getPath() + " (Is a directory)");
|
||||
}
|
||||
return Files.newInputStream(this.path);
|
||||
}
|
||||
|
||||
/**
|
||||
* This implementation returns a URL for the underlying file.
|
||||
* @see java.nio.file.Path#toUri()
|
||||
* @see java.net.URI#toURL()
|
||||
*/
|
||||
@Override
|
||||
public URL getURL() throws IOException {
|
||||
return this.path.toUri().toURL();
|
||||
}
|
||||
|
||||
/**
|
||||
* This implementation returns a URI for the underlying file.
|
||||
* @see java.nio.file.Path#toUri()
|
||||
*/
|
||||
@Override
|
||||
public URI getURI() throws IOException {
|
||||
return this.path.toUri();
|
||||
}
|
||||
|
||||
/**
|
||||
* This implementation returns the underlying File reference.
|
||||
*/
|
||||
@Override
|
||||
public File getFile() throws IOException {
|
||||
try {
|
||||
return this.path.toFile();
|
||||
}
|
||||
catch (UnsupportedOperationException ex) {
|
||||
// only Paths on the default file system can be converted to a File
|
||||
// do exception translation for cases where conversion is not possible
|
||||
throw new FileNotFoundException(this.path + " cannot be resolved to "
|
||||
+ "absolute file path");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This implementation returns the underlying File's length.
|
||||
*/
|
||||
@Override
|
||||
public long contentLength() throws IOException {
|
||||
return Files.size(this.path);
|
||||
}
|
||||
|
||||
/**
|
||||
* This implementation returns the underlying File's timestamp.
|
||||
* @see java.nio.file.Files#getLastModifiedTime(Path, java.nio.file.LinkOption...)
|
||||
*/
|
||||
@Override
|
||||
public long lastModified() throws IOException {
|
||||
// we can not use the super class method since it uses conversion to a File and
|
||||
// only Paths on the default file system can be converted to a File
|
||||
return Files.getLastModifiedTime(path).toMillis();
|
||||
}
|
||||
|
||||
/**
|
||||
* This implementation creates a FileResource, applying the given path
|
||||
* relative to the path of the underlying file of this resource descriptor.
|
||||
* @see java.nio.file.Path#resolve(String)
|
||||
*/
|
||||
@Override
|
||||
public Resource createRelative(String relativePath) throws IOException {
|
||||
return new PathResource(this.path.resolve(relativePath));
|
||||
}
|
||||
|
||||
/**
|
||||
* This implementation returns the name of the file.
|
||||
* @see java.nio.file.Path#getFileName()
|
||||
*/
|
||||
@Override
|
||||
public String getFilename() {
|
||||
return this.path.getFileName().toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return "path [" + this.path.toAbsolutePath() + "]";
|
||||
}
|
||||
|
||||
// implementation of WritableResource
|
||||
|
||||
/**
|
||||
* This implementation checks whether the underlying file is marked as writable
|
||||
* (and corresponds to an actual file with content, not to a directory).
|
||||
* @see java.nio.file.Files#isWritable(Path)
|
||||
* @see java.nio.file.Files#isDirectory(Path, java.nio.file.LinkOption...)
|
||||
*/
|
||||
@Override
|
||||
public boolean isWritable() {
|
||||
return Files.isWritable(this.path) && !Files.isDirectory(this.path);
|
||||
}
|
||||
|
||||
/**
|
||||
* This implementation opens a OutputStream for the underlying file.
|
||||
* @see java.nio.file.spi.FileSystemProvider#newOutputStream(Path, OpenOption...)
|
||||
*/
|
||||
@Override
|
||||
public OutputStream getOutputStream() throws IOException {
|
||||
if(Files.isDirectory(this.path)) {
|
||||
throw new FileNotFoundException(getPath() + " (Is a directory)");
|
||||
}
|
||||
return Files.newOutputStream(this.path);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This implementation compares the underlying Path references.
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
return (obj == this ||
|
||||
(obj instanceof PathResource && this.path.equals(((PathResource) obj).path)));
|
||||
}
|
||||
|
||||
/**
|
||||
* This implementation returns the hash code of the underlying Path reference.
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return this.path.hashCode();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -42,6 +42,7 @@ import java.net.URL;
|
||||
* @see UrlResource
|
||||
* @see ByteArrayResource
|
||||
* @see InputStreamResource
|
||||
* @see PathResource
|
||||
*/
|
||||
public interface Resource extends InputStreamSource {
|
||||
|
||||
|
||||
@@ -0,0 +1,277 @@
|
||||
/*
|
||||
* Copyright 2002-2012 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.FileNotFoundException;
|
||||
import java.net.URI;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
import org.junit.rules.TemporaryFolder;
|
||||
import org.springframework.util.FileCopyUtils;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.BDDMockito.*;
|
||||
|
||||
/**
|
||||
* Unit tests for the {@link PathResource} class.
|
||||
*
|
||||
* @author Philippe Marschall
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
public class PathResourceTests {
|
||||
|
||||
private static final String TEST_DIR = "src/test/java/org/springframework/core/io";
|
||||
|
||||
private static final String TEST_FILE = "src/test/java/org/springframework/core/io/example.properties";
|
||||
|
||||
private static final String NON_EXISTING_FILE = "src/test/java/org/springframework/core/io/doesnotexist.properties";
|
||||
|
||||
|
||||
@Rule
|
||||
public ExpectedException thrown = ExpectedException.none();
|
||||
|
||||
@Rule
|
||||
public TemporaryFolder temporaryFolder = new TemporaryFolder();
|
||||
|
||||
|
||||
@Test
|
||||
public void nullPath() throws Exception {
|
||||
thrown.expect(IllegalArgumentException.class);
|
||||
thrown.expectMessage("Path must not be null");
|
||||
new PathResource((Path) null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nullPathString() throws Exception {
|
||||
thrown.expect(IllegalArgumentException.class);
|
||||
thrown.expectMessage("Path must not be null");
|
||||
new PathResource((String) null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nullUri() throws Exception {
|
||||
thrown.expect(IllegalArgumentException.class);
|
||||
thrown.expectMessage("URI must not be null");
|
||||
new PathResource((URI) null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createFromPath() throws Exception {
|
||||
Path path = Paths.get(TEST_FILE);
|
||||
PathResource resource = new PathResource(path);
|
||||
assertThat(resource.getPath(), equalTo(TEST_FILE));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createFromString() throws Exception {
|
||||
PathResource resource = new PathResource(TEST_FILE);
|
||||
assertThat(resource.getPath(), equalTo(TEST_FILE));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createFromUri() throws Exception {
|
||||
File file = new File(TEST_FILE);
|
||||
PathResource resource = new PathResource(file.toURI());
|
||||
assertThat(resource.getPath(), equalTo(file.getAbsoluteFile().toString()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getPathForFile() throws Exception {
|
||||
PathResource resource = new PathResource(TEST_FILE);
|
||||
assertThat(resource.getPath(), equalTo(TEST_FILE));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getPathForDir() throws Exception {
|
||||
PathResource resource = new PathResource(TEST_DIR);
|
||||
assertThat(resource.getPath(), equalTo(TEST_DIR));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void fileExists() throws Exception {
|
||||
PathResource resource = new PathResource(TEST_FILE);
|
||||
assertThat(resource.exists(), equalTo(true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void dirExists() throws Exception {
|
||||
PathResource resource = new PathResource(TEST_DIR);
|
||||
assertThat(resource.exists(), equalTo(true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void fileDoesNotExist() throws Exception {
|
||||
PathResource resource = new PathResource(NON_EXISTING_FILE);
|
||||
assertThat(resource.exists(), equalTo(false));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void fileIsReadable() throws Exception {
|
||||
PathResource resource = new PathResource(TEST_FILE);
|
||||
assertThat(resource.isReadable(), equalTo(true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doesNotExistIsNotReadable() throws Exception {
|
||||
PathResource resource = new PathResource(NON_EXISTING_FILE);
|
||||
assertThat(resource.isReadable(), equalTo(false));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void directoryIsNotReadable() throws Exception {
|
||||
PathResource resource = new PathResource(TEST_DIR);
|
||||
assertThat(resource.isReadable(), equalTo(false));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getInputStream() throws Exception {
|
||||
PathResource resource = new PathResource(TEST_FILE);
|
||||
byte[] bytes = FileCopyUtils.copyToByteArray(resource.getInputStream());
|
||||
assertThat(bytes.length, greaterThan(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getInputStreamForDir() throws Exception {
|
||||
PathResource resource = new PathResource(TEST_DIR);
|
||||
thrown.expect(FileNotFoundException.class);
|
||||
resource.getInputStream();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getInputStreamDoesNotExist() throws Exception {
|
||||
PathResource resource = new PathResource(NON_EXISTING_FILE);
|
||||
thrown.expect(FileNotFoundException.class);
|
||||
resource.getInputStream();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getUrl() throws Exception {
|
||||
PathResource resource = new PathResource(TEST_FILE);
|
||||
assertTrue(resource.getURL().toString().endsWith(TEST_FILE));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getUri() throws Exception {
|
||||
PathResource resource = new PathResource(TEST_FILE);
|
||||
assertTrue(resource.getURI().toString().endsWith(TEST_FILE));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getFile() throws Exception {
|
||||
PathResource resource = new PathResource(TEST_FILE);
|
||||
File file = new File(TEST_FILE);
|
||||
assertThat(resource.getFile().getAbsoluteFile(), equalTo(file.getAbsoluteFile()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getFileUnsupported() throws Exception {
|
||||
Path path = mock(Path.class);
|
||||
given(path.normalize()).willReturn(path);
|
||||
given(path.toFile()).willThrow(new UnsupportedOperationException());
|
||||
PathResource resource = new PathResource(path);
|
||||
thrown.expect(FileNotFoundException.class);
|
||||
resource.getFile();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void contentLength() throws Exception {
|
||||
PathResource resource = new PathResource(TEST_FILE);
|
||||
File file = new File(TEST_FILE);
|
||||
assertThat(resource.contentLength(), equalTo(file.length()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void contentLengthForDirectory() throws Exception {
|
||||
PathResource resource = new PathResource(TEST_DIR);
|
||||
File file = new File(TEST_DIR);
|
||||
assertThat(resource.contentLength(), equalTo(file.length()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void lastModified() throws Exception {
|
||||
PathResource resource = new PathResource(TEST_FILE);
|
||||
File file = new File(TEST_FILE);
|
||||
assertThat(resource.lastModified(), equalTo(file.lastModified()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createRelativeFromDir() throws Exception {
|
||||
Resource resource = new PathResource(TEST_DIR).createRelative("example.properties");
|
||||
assertThat(resource, equalTo((Resource) new PathResource(TEST_FILE)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createRelativeFromFile() throws Exception {
|
||||
Resource resource = new PathResource(TEST_FILE).createRelative("../example.properties");
|
||||
assertThat(resource, equalTo((Resource) new PathResource(TEST_FILE)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void filename() throws Exception {
|
||||
Resource resource = new PathResource(TEST_FILE);
|
||||
assertThat(resource.getFilename(), equalTo("example.properties"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void description() throws Exception {
|
||||
Resource resource = new PathResource(TEST_FILE);
|
||||
assertThat(resource.getDescription(), containsString("path ["));
|
||||
assertThat(resource.getDescription(), containsString(TEST_FILE));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void fileIsWritable() throws Exception {
|
||||
PathResource resource = new PathResource(TEST_FILE);
|
||||
assertThat(resource.isWritable(), equalTo(true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void directoryIsNotWritable() throws Exception {
|
||||
PathResource resource = new PathResource(TEST_DIR);
|
||||
assertThat(resource.isWritable(), equalTo(false));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void outputStream() throws Exception {
|
||||
PathResource resource = new PathResource(temporaryFolder.newFile("test").toPath());
|
||||
FileCopyUtils.copy("test".getBytes(), resource.getOutputStream());
|
||||
assertThat(resource.contentLength(), equalTo(4L));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doesNotExistOutputStream() throws Exception {
|
||||
File file = temporaryFolder.newFile("test");
|
||||
file.delete();
|
||||
PathResource resource = new PathResource(file.toPath());
|
||||
FileCopyUtils.copy("test".getBytes(), resource.getOutputStream());
|
||||
assertThat(resource.contentLength(), equalTo(4L));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void directoryOutputStream() throws Exception {
|
||||
PathResource resource = new PathResource(TEST_DIR);
|
||||
thrown.expect(FileNotFoundException.class);
|
||||
resource.getOutputStream();
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user