001/* 002 * Copyright 2002-2018 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.util.Assert; 031 032/** 033 * Editor for {@code java.nio.file.Path}, to directly populate a Path 034 * property instead of using a String property as bridge. 035 * 036 * <p>Based on {@link Paths#get(URI)}'s resolution algorithm, checking 037 * registered NIO file system providers, including the default file system 038 * for "file:..." paths. Also supports Spring-style URL notation: any fully 039 * qualified standard URL and Spring's special "classpath:" pseudo-URL, as 040 * well as Spring's context-specific relative file paths. As a fallback, a 041 * path will be resolved in the file system via {@code Paths#get(String)} 042 * if no existing context-relative resource could be found. 043 * 044 * @author Juergen Hoeller 045 * @since 4.3.2 046 * @see java.nio.file.Path 047 * @see Paths#get(URI) 048 * @see ResourceEditor 049 * @see org.springframework.core.io.ResourceLoader 050 * @see FileEditor 051 * @see URLEditor 052 */ 053public class PathEditor extends PropertyEditorSupport { 054 055 private final ResourceEditor resourceEditor; 056 057 058 /** 059 * Create a new PathEditor, using the default ResourceEditor underneath. 060 */ 061 public PathEditor() { 062 this.resourceEditor = new ResourceEditor(); 063 } 064 065 /** 066 * Create a new PathEditor, using the given ResourceEditor underneath. 067 * @param resourceEditor the ResourceEditor to use 068 */ 069 public PathEditor(ResourceEditor resourceEditor) { 070 Assert.notNull(resourceEditor, "ResourceEditor must not be null"); 071 this.resourceEditor = resourceEditor; 072 } 073 074 075 @Override 076 public void setAsText(String text) throws IllegalArgumentException { 077 boolean nioPathCandidate = !text.startsWith(ResourceLoader.CLASSPATH_URL_PREFIX); 078 if (nioPathCandidate && !text.startsWith("/")) { 079 try { 080 URI uri = new URI(text); 081 if (uri.getScheme() != null) { 082 nioPathCandidate = false; 083 // Let's try NIO file system providers via Paths.get(URI) 084 setValue(Paths.get(uri).normalize()); 085 return; 086 } 087 } 088 catch (URISyntaxException | FileSystemNotFoundException ex) { 089 // Not a valid URI (let's try as Spring resource location), 090 // or a URI scheme not registered for NIO (let's try URL 091 // protocol handlers via Spring's resource mechanism). 092 } 093 } 094 095 this.resourceEditor.setAsText(text); 096 Resource resource = (Resource) this.resourceEditor.getValue(); 097 if (resource == null) { 098 setValue(null); 099 } 100 else if (!resource.exists() && nioPathCandidate) { 101 setValue(Paths.get(text).normalize()); 102 } 103 else { 104 try { 105 setValue(resource.getFile().toPath()); 106 } 107 catch (IOException ex) { 108 throw new IllegalArgumentException("Failed to retrieve file for " + resource, ex); 109 } 110 } 111 } 112 113 @Override 114 public String getAsText() { 115 Path value = (Path) getValue(); 116 return (value != null ? value.toString() : ""); 117 } 118 119}