Skip to content

Add PathEditor to enable conversion to java.nio.file.Path [SPR-14436] #19007

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
spring-projects-issues opened this issue Jul 6, 2016 · 2 comments
Assignees
Labels
type: enhancement A general enhancement
Milestone

Comments

@spring-projects-issues
Copy link
Collaborator

spring-projects-issues commented Jul 6, 2016

Holger Stenzhorn opened SPR-14436 and commented

Currently

@Value{some.path.property} private Path path;

fails with

Cannot convert value of type [java.lang.String] to required type [java.nio.file.Path]: no matching editors or conversion strategy found;

because no PathEditor is implemented (and added to the defaultEditors of PropertyEditorRegistrySupport).

It would be nice if this could be changed... :-) Below you can find a quick implementation for PathEditor:

/*
 * Copyright 2002-2016 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.beans.propertyeditors;

import java.beans.PropertyEditorSupport;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;

import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceEditor;
import org.springframework.util.Assert;
import org.springframework.util.ResourceUtils;
import org.springframework.util.StringUtils;

/**
 * Editor for {@code java.nio.file.{@link Path}}, to directly populate a Path property
 * from a Spring resource location.
 *
 * <p>Supports Spring-style URL notation: any fully qualified standard URL
 * ("file:", "http:", etc) and Spring's special "classpath:" pseudo-URL.
 *
 * @author Juergen Hoeller
 * @author Thomas Risberg
 * @author Holger Stenzhorn
 * @since 06.07.2016
 * @see java.nio.file.Path
 * @see org.springframework.core.io.ResourceEditor
 * @see org.springframework.core.io.ResourceLoader
 * @see URLEditor
 * @see InputStreamEditor
 */
public class PathEditor extends PropertyEditorSupport {

	private final ResourceEditor resourceEditor;


	/**
	 * Create a new PathEditor,
	 * using the default ResourceEditor underneath.
	 */
	public PathEditor() {
		this.resourceEditor = new ResourceEditor();
	}

	/**
	 * Create a new PathEditor,
	 * using the given ResourceEditor underneath.
	 * @param resourceEditor the ResourceEditor to use
	 */
	public PathEditor(ResourceEditor resourceEditor) {
		Assert.notNull(resourceEditor, "ResourceEditor must not be null");
		this.resourceEditor = resourceEditor;
	}


	@Override
	public void setAsText(String text) throws IllegalArgumentException {
		if (!StringUtils.hasText(text)) {
			setValue(null);
			return;
		}

		// Check whether we got an absolute file path without "file:" prefix.
		// For backwards compatibility, we'll consider those as straight file path.
		if (!ResourceUtils.isUrl(text)) {
			Path path = Paths.get(text);
			if (path.isAbsolute()) {
				setValue(path);
				return;
			}
		}

		// Proceed with standard resource location parsing.
		this.resourceEditor.setAsText(text);
		Resource resource = (Resource) this.resourceEditor.getValue();

		// If it's a URL or a path pointing to an existing resource, use it as-is.
		if (ResourceUtils.isUrl(text) || resource.exists()) {
			try {
				setValue(resource.getFile().toPath());
			}
			catch (IOException ex) {
				throw new IllegalArgumentException(
						"Could not retrieve Path for " + resource + ": " + ex.getMessage());
			}
		}
		else {
			// Create a relative Path reference and hope for the best.
			setValue(Paths.get(text));
		}
	}

	@Override
	public String getAsText() {
		Path value = (Path) getValue();
		return (value != null ? value.toString() : "");
	}

}

Issue Links:

Referenced from: commits f85d48d, 23c2b6a

@spring-projects-issues
Copy link
Collaborator Author

Juergen Hoeller commented

I've added such a PathEditor, however, in a rather different style: not inheriting FileEditor's legacy with ambiguous plain paths but rather freshly based on Paths.get(URI)'s resolution algorithm, checking registered NIO file system providers, including the default file system for "file:..." paths. If that resolution fails, we try the Spring context's resource loader next, in particular for "classpath:..." pseudo-URLs and for context-relative resource locations.

Note that, in contrast to FileEditor, relative paths are only supported by Spring's resource abstraction here. Direct Paths.get resolution in a file system always has to go through the corresponding file system provider's scheme, i.e. "file" for the default file system.

@spring-projects-issues
Copy link
Collaborator Author

Holger Stenzhorn commented

Juergen Hoeller: Great! Thanks a lot for your quick support on this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: enhancement A general enhancement
Projects
None yet
Development

No branches or pull requests

2 participants