diff --git a/src/main/java/com/fasterxml/jackson/databind/ext/NioPathDeserializer.java b/src/main/java/com/fasterxml/jackson/databind/ext/NioPathDeserializer.java index 48a39ebe7c..20e9d5cf12 100644 --- a/src/main/java/com/fasterxml/jackson/databind/ext/NioPathDeserializer.java +++ b/src/main/java/com/fasterxml/jackson/databind/ext/NioPathDeserializer.java @@ -1,16 +1,22 @@ package com.fasterxml.jackson.databind.ext; +import java.io.File; import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; +import java.nio.file.FileSystemNotFoundException; import java.nio.file.Path; import java.nio.file.Paths; +import java.nio.file.spi.FileSystemProvider; +import java.util.ServiceLoader; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonToken; import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.deser.std.StdScalarDeserializer; +import static java.lang.Character.isLetter; + /** * @since 2.8 */ @@ -18,6 +24,19 @@ public class NioPathDeserializer extends StdScalarDeserializer { private static final long serialVersionUID = 1; + private static final boolean areWindowsFilePathsSupported; + static { + boolean isWindowsRootFound = false; + for (File file : File.listRoots()) { + String path = file.getPath(); + if (path.length() >= 2 && isLetter(path.charAt(0)) && path.charAt(1) == ':') { + isWindowsRootFound = true; + break; + } + } + areWindowsFilePathsSupported = isWindowsRootFound; + } + public NioPathDeserializer() { super(Path.class); } @Override @@ -25,17 +44,45 @@ public Path deserialize(JsonParser p, DeserializationContext ctxt) throws IOExce if (!p.hasToken(JsonToken.VALUE_STRING)) { return (Path) ctxt.handleUnexpectedToken(Path.class, p); } + final String value = p.getText(); + // If someone gives us an input with no : at all, treat as local path, instead of failing // with invalid URI. if (value.indexOf(':') < 0) { return Paths.get(value); } + + if (areWindowsFilePathsSupported) { + if (value.length() >= 2 && isLetter(value.charAt(0)) && value.charAt(1) == ':') { + return Paths.get(value); + } + } + + final URI uri; try { - URI uri = new URI(value); - return Paths.get(uri); + uri = new URI(value); } catch (URISyntaxException e) { return (Path) ctxt.handleInstantiationProblem(handledType(), value, e); } + try { + return Paths.get(uri); + } catch (FileSystemNotFoundException cause) { + try { + final String scheme = uri.getScheme(); + // We want to use the current thread's context class loader, not system class loader that is used in Paths.get(): + for (FileSystemProvider provider : ServiceLoader.load(FileSystemProvider.class)) { + if (provider.getScheme().equalsIgnoreCase(scheme)) { + return provider.getPath(uri); + } + } + return (Path) ctxt.handleInstantiationProblem(handledType(), value, cause); + } catch (Throwable e) { + e.addSuppressed(cause); + return (Path) ctxt.handleInstantiationProblem(handledType(), value, e); + } + } catch (Throwable e) { + return (Path) ctxt.handleInstantiationProblem(handledType(), value, e); + } } }