001/*
002 * Copyright 2002-2016 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *      https://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package org.springframework.beans.propertyeditors;
018
019import java.beans.PropertyEditorSupport;
020import java.io.IOException;
021import java.net.URI;
022import java.net.URISyntaxException;
023import java.nio.file.FileSystemNotFoundException;
024import java.nio.file.Path;
025import java.nio.file.Paths;
026
027import org.springframework.core.io.Resource;
028import org.springframework.core.io.ResourceEditor;
029import org.springframework.core.io.ResourceLoader;
030import org.springframework.lang.UsesJava7;
031import org.springframework.util.Assert;
032
033/**
034 * Editor for {@code java.nio.file.Path}, to directly populate a Path
035 * property instead of using a String property as bridge.
036 *
037 * <p>Based on {@link Paths#get(URI)}'s resolution algorithm, checking
038 * registered NIO file system providers, including the default file system
039 * for "file:..." paths. Also supports Spring-style URL notation: any fully
040 * qualified standard URL and Spring's special "classpath:" pseudo-URL, as
041 * well as Spring's context-specific relative file paths. As a fallback, a
042 * path will be resolved in the file system via {@code Paths#get(String)}
043 * if no existing context-relative resource could be found.
044 *
045 * @author Juergen Hoeller
046 * @since 4.3.2
047 * @see java.nio.file.Path
048 * @see Paths#get(URI)
049 * @see ResourceEditor
050 * @see org.springframework.core.io.ResourceLoader
051 * @see FileEditor
052 * @see URLEditor
053 */
054@UsesJava7
055public class PathEditor extends PropertyEditorSupport {
056
057        private final ResourceEditor resourceEditor;
058
059
060        /**
061         * Create a new PathEditor, using the default ResourceEditor underneath.
062         */
063        public PathEditor() {
064                this.resourceEditor = new ResourceEditor();
065        }
066
067        /**
068         * Create a new PathEditor, using the given ResourceEditor underneath.
069         * @param resourceEditor the ResourceEditor to use
070         */
071        public PathEditor(ResourceEditor resourceEditor) {
072                Assert.notNull(resourceEditor, "ResourceEditor must not be null");
073                this.resourceEditor = resourceEditor;
074        }
075
076
077        @Override
078        public void setAsText(String text) throws IllegalArgumentException {
079                boolean nioPathCandidate = !text.startsWith(ResourceLoader.CLASSPATH_URL_PREFIX);
080                if (nioPathCandidate && !text.startsWith("/")) {
081                        try {
082                                URI uri = new URI(text);
083                                if (uri.getScheme() != null) {
084                                        nioPathCandidate = false;
085                                        // Let's try NIO file system providers via Paths.get(URI)
086                                        setValue(Paths.get(uri).normalize());
087                                        return;
088                                }
089                        }
090                        catch (URISyntaxException ex) {
091                                // Not a valid URI: Let's try as Spring resource location.
092                        }
093                        catch (FileSystemNotFoundException ex) {
094                                // URI scheme not registered for NIO:
095                                // Let's try URL protocol handlers via Spring's resource mechanism.
096                        }
097                }
098
099                this.resourceEditor.setAsText(text);
100                Resource resource = (Resource) this.resourceEditor.getValue();
101                if (resource == null) {
102                        setValue(null);
103                }
104                else if (!resource.exists() && nioPathCandidate) {
105                        setValue(Paths.get(text).normalize());
106                }
107                else {
108                        try {
109                                setValue(resource.getFile().toPath());
110                        }
111                        catch (IOException ex) {
112                                throw new IllegalArgumentException("Failed to retrieve file for " + resource, ex);
113                        }
114                }
115        }
116
117        @Override
118        public String getAsText() {
119                Path value = (Path) getValue();
120                return (value != null ? value.toString() : "");
121        }
122
123}