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.File;
021import java.io.IOException;
022
023import org.springframework.core.io.Resource;
024import org.springframework.core.io.ResourceEditor;
025import org.springframework.util.Assert;
026import org.springframework.util.ResourceUtils;
027import org.springframework.util.StringUtils;
028
029/**
030 * Editor for {@code java.io.File}, to directly populate a File property
031 * from a Spring resource location.
032 *
033 * <p>Supports Spring-style URL notation: any fully qualified standard URL
034 * ("file:", "http:", etc) and Spring's special "classpath:" pseudo-URL.
035 *
036 * <p><b>NOTE:</b> The behavior of this editor has changed in Spring 2.0.
037 * Previously, it created a File instance directly from a filename.
038 * As of Spring 2.0, it takes a standard Spring resource location as input;
039 * this is consistent with URLEditor and InputStreamEditor now.
040 *
041 * <p><b>NOTE:</b> In Spring 2.5 the following modification was made.
042 * If a file name is specified without a URL prefix or without an absolute path
043 * then we try to locate the file using standard ResourceLoader semantics.
044 * If the file was not found, then a File instance is created assuming the file
045 * name refers to a relative file location.
046 *
047 * @author Juergen Hoeller
048 * @author Thomas Risberg
049 * @since 09.12.2003
050 * @see java.io.File
051 * @see org.springframework.core.io.ResourceEditor
052 * @see org.springframework.core.io.ResourceLoader
053 * @see URLEditor
054 * @see InputStreamEditor
055 */
056public class FileEditor extends PropertyEditorSupport {
057
058        private final ResourceEditor resourceEditor;
059
060
061        /**
062         * Create a new FileEditor, using a default ResourceEditor underneath.
063         */
064        public FileEditor() {
065                this.resourceEditor = new ResourceEditor();
066        }
067
068        /**
069         * Create a new FileEditor, using the given ResourceEditor underneath.
070         * @param resourceEditor the ResourceEditor to use
071         */
072        public FileEditor(ResourceEditor resourceEditor) {
073                Assert.notNull(resourceEditor, "ResourceEditor must not be null");
074                this.resourceEditor = resourceEditor;
075        }
076
077
078        @Override
079        public void setAsText(String text) throws IllegalArgumentException {
080                if (!StringUtils.hasText(text)) {
081                        setValue(null);
082                        return;
083                }
084
085                // Check whether we got an absolute file path without "file:" prefix.
086                // For backwards compatibility, we'll consider those as straight file path.
087                File file = null;
088                if (!ResourceUtils.isUrl(text)) {
089                        file = new File(text);
090                        if (file.isAbsolute()) {
091                                setValue(file);
092                                return;
093                        }
094                }
095
096                // Proceed with standard resource location parsing.
097                this.resourceEditor.setAsText(text);
098                Resource resource = (Resource) this.resourceEditor.getValue();
099
100                // If it's a URL or a path pointing to an existing resource, use it as-is.
101                if (file == null || resource.exists()) {
102                        try {
103                                setValue(resource.getFile());
104                        }
105                        catch (IOException ex) {
106                                throw new IllegalArgumentException(
107                                                "Could not retrieve file for " + resource + ": " + ex.getMessage());
108                        }
109                }
110                else {
111                        // Set a relative File reference and hope for the best.
112                        setValue(file);
113                }
114        }
115
116        @Override
117        public String getAsText() {
118                File value = (File) getValue();
119                return (value != null ? value.getPath() : "");
120        }
121
122}