1 package com.fasterxml.jackson.databind.ext; 2 3 import java.io.File; 4 import java.io.IOException; 5 import java.net.URI; 6 import java.net.URISyntaxException; 7 import java.nio.file.FileSystemNotFoundException; 8 import java.nio.file.Path; 9 import java.nio.file.Paths; 10 import java.nio.file.spi.FileSystemProvider; 11 import java.util.ServiceLoader; 12 13 import com.fasterxml.jackson.core.JsonParser; 14 import com.fasterxml.jackson.core.JsonToken; 15 import com.fasterxml.jackson.databind.DeserializationContext; 16 import com.fasterxml.jackson.databind.deser.std.StdScalarDeserializer; 17 18 import static java.lang.Character.isLetter; 19 20 /** 21 * @since 2.8 22 */ 23 public class NioPathDeserializer extends StdScalarDeserializer<Path> 24 { 25 private static final long serialVersionUID = 1; 26 27 private static final boolean areWindowsFilePathsSupported; 28 static { 29 boolean isWindowsRootFound = false; 30 for (File file : File.listRoots()) { 31 String path = file.getPath(); 32 if (path.length() >= 2 && isLetter(path.charAt(0)) && path.charAt(1) == ':') { 33 isWindowsRootFound = true; 34 break; 35 } 36 } 37 areWindowsFilePathsSupported = isWindowsRootFound; 38 } 39 NioPathDeserializer()40 public NioPathDeserializer() { super(Path.class); } 41 42 @Override deserialize(JsonParser p, DeserializationContext ctxt)43 public Path deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { 44 if (!p.hasToken(JsonToken.VALUE_STRING)) { 45 return (Path) ctxt.handleUnexpectedToken(Path.class, p); 46 } 47 48 final String value = p.getText(); 49 50 // If someone gives us an input with no : at all, treat as local path, instead of failing 51 // with invalid URI. 52 if (value.indexOf(':') < 0) { 53 return Paths.get(value); 54 } 55 56 if (areWindowsFilePathsSupported) { 57 if (value.length() >= 2 && isLetter(value.charAt(0)) && value.charAt(1) == ':') { 58 return Paths.get(value); 59 } 60 } 61 62 final URI uri; 63 try { 64 uri = new URI(value); 65 } catch (URISyntaxException e) { 66 return (Path) ctxt.handleInstantiationProblem(handledType(), value, e); 67 } 68 try { 69 return Paths.get(uri); 70 } catch (FileSystemNotFoundException cause) { 71 try { 72 final String scheme = uri.getScheme(); 73 // We want to use the current thread's context class loader, not system class loader that is used in Paths.get(): 74 for (FileSystemProvider provider : ServiceLoader.load(FileSystemProvider.class)) { 75 if (provider.getScheme().equalsIgnoreCase(scheme)) { 76 return provider.getPath(uri); 77 } 78 } 79 return (Path) ctxt.handleInstantiationProblem(handledType(), value, cause); 80 } catch (Throwable e) { 81 e.addSuppressed(cause); 82 return (Path) ctxt.handleInstantiationProblem(handledType(), value, e); 83 } 84 } catch (Throwable e) { 85 return (Path) ctxt.handleInstantiationProblem(handledType(), value, e); 86 } 87 } 88 } 89