Skip to content

Commit b921d56

Browse files
committed
DefaultResourceLoader resolves writable FileUrlResource for "file:" URL
Issue: SPR-16140
1 parent da9f138 commit b921d56

File tree

3 files changed

+105
-3
lines changed

3 files changed

+105
-3
lines changed

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

+2-1
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import org.springframework.lang.Nullable;
2828
import org.springframework.util.Assert;
2929
import org.springframework.util.ClassUtils;
30+
import org.springframework.util.ResourceUtils;
3031
import org.springframework.util.StringUtils;
3132

3233
/**
@@ -160,7 +161,7 @@ else if (location.startsWith(CLASSPATH_URL_PREFIX)) {
160161
try {
161162
// Try to parse the location as a URL...
162163
URL url = new URL(location);
163-
return new UrlResource(url);
164+
return (ResourceUtils.isFileURL(url) ? new FileUrlResource(url) : new UrlResource(url));
164165
}
165166
catch (MalformedURLException ex) {
166167
// No URL -> resolve as resource path.

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ public File getFile() {
183183
*/
184184
@Override
185185
public ReadableByteChannel readableChannel() throws IOException {
186-
return FileChannel.open(getFile().toPath(), StandardOpenOption.READ);
186+
return FileChannel.open(this.file.toPath(), StandardOpenOption.READ);
187187
}
188188

189189
/**
@@ -192,7 +192,7 @@ public ReadableByteChannel readableChannel() throws IOException {
192192
*/
193193
@Override
194194
public WritableByteChannel writableChannel() throws IOException {
195-
return FileChannel.open(getFile().toPath(), StandardOpenOption.WRITE);
195+
return FileChannel.open(this.file.toPath(), StandardOpenOption.WRITE);
196196
}
197197

198198
/**
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
/*
2+
* Copyright 2002-2017 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.core.io;
18+
19+
import java.io.File;
20+
import java.io.IOException;
21+
import java.io.OutputStream;
22+
import java.net.MalformedURLException;
23+
import java.net.URL;
24+
import java.nio.channels.FileChannel;
25+
import java.nio.channels.WritableByteChannel;
26+
import java.nio.file.Files;
27+
import java.nio.file.StandardOpenOption;
28+
29+
import org.springframework.util.ResourceUtils;
30+
31+
/**
32+
* Subclass of {@link UrlResource} which assumes file resolution, to the degree
33+
* of implementing the {@link WritableResource} interface for it.
34+
*
35+
* <p>This is the class resolved by {@link DefaultResourceLoader} for a "file:..."
36+
* URL location, allowing a downcast to {@link WritableResource} for it.
37+
*
38+
* <p>Alternatively, for direct construction from a {@link java.io.File} handle,
39+
* consider using {@link FileSystemResource}. For an NIO {@link java.nio.file.Path},
40+
* consider using {@link PathResource} instead.
41+
*
42+
* @author Juergen Hoeller
43+
* @since 5.0.2
44+
*/
45+
public class FileUrlResource extends UrlResource implements WritableResource {
46+
47+
/**
48+
* Create a new {@code FileUrlResource} based on the given URL object.
49+
* <p>Note that this does not enforce "file" as URL protocol. If a protocol
50+
* is known to be resolvable to a file,
51+
* @param url a URL
52+
* @see ResourceUtils#isFileURL(URL)
53+
* @see #getFile()
54+
*/
55+
public FileUrlResource(URL url) {
56+
super(url);
57+
}
58+
59+
/**
60+
* Create a new {@code FileUrlResource} based on the given file location,
61+
* using the URL protocol "file".
62+
* <p>The given parts will automatically get encoded if necessary.
63+
* @param location the location (i.e. the file path within that protocol)
64+
* @throws MalformedURLException if the given URL specification is not valid
65+
* @see UrlResource#UrlResource(String, String)
66+
* @see ResourceUtils#URL_PROTOCOL_FILE
67+
*/
68+
public FileUrlResource(String location) throws MalformedURLException {
69+
super(ResourceUtils.URL_PROTOCOL_FILE, location);
70+
}
71+
72+
73+
@Override
74+
public boolean isWritable() {
75+
try {
76+
URL url = getURL();
77+
if (ResourceUtils.isFileURL(url)) {
78+
// Proceed with file system resolution
79+
File file = getFile();
80+
return (file.canWrite() && !file.isDirectory());
81+
}
82+
else {
83+
return true;
84+
}
85+
}
86+
catch (IOException ex) {
87+
return false;
88+
}
89+
}
90+
91+
@Override
92+
public OutputStream getOutputStream() throws IOException {
93+
return Files.newOutputStream(getFile().toPath());
94+
}
95+
96+
@Override
97+
public WritableByteChannel writableChannel() throws IOException {
98+
return FileChannel.open(getFile().toPath(), StandardOpenOption.WRITE);
99+
}
100+
101+
}

0 commit comments

Comments
 (0)