--- a/openide.filesystems/apichanges.xml +++ a/openide.filesystems/apichanges.xml @@ -938,6 +938,27 @@ + + + + FileUtil.normalizePath added + + + + + + +

+ The method + FileUtil.normalizePath(String) was added as a + refinement of + FileUtil.normalizeFile that does prevent String to File to String + conversion on client side when intention is to convert unnormalized path to normalized path presentation. +

+
+ + +
--- a/openide.filesystems/manifest.mf +++ a/openide.filesystems/manifest.mf @@ -2,5 +2,5 @@ OpenIDE-Module: org.openide.filesystems OpenIDE-Module-Localizing-Bundle: org/openide/filesystems/Bundle.properties OpenIDE-Module-Layer: org/openide/filesystems/resources/layer.xml -OpenIDE-Module-Specification-Version: 7.41 +OpenIDE-Module-Specification-Version: 7.42 --- a/openide.filesystems/src/org/openide/filesystems/FileUtil.java +++ a/openide.filesystems/src/org/openide/filesystems/FileUtil.java @@ -1672,6 +1672,33 @@ * (including filechoosers), configuration files, Ant properties, etc. Internal * calculations should not need to renormalize paths since {@link File#listFiles}, * {@link File#getParentFile}, etc. will not produce abnormal variants. + * @param path file path to normalize + * @return normalized file path + * @since 7.42 + */ + public static String normalizePath(final String path) { + Map normalizedPaths = getNormalizedFilesMap(); + String normalized = normalizedPaths.get(path); + if (normalized == null) { + File ret = normalizeFileImpl(new File(path)); + normalized = ret.getPath(); + normalizedPaths.put(path, normalized); + } + return normalized; + } + + /** + * Normalize a file path to a clean form. + * This method may for example make sure that the returned file uses + * the natural case on Windows; that old Windows 8.3 filenames are changed to the long form; + * that relative paths are changed to be + * absolute; that . and .. sequences are removed; etc. + * Unlike {@link File#getCanonicalFile} this method will not traverse symbolic links on Unix. + *

This method involves some overhead and should not be called frivolously. + * Generally it should be called on incoming pathnames that are gotten from user input + * (including filechoosers), configuration files, Ant properties, etc. Internal + * calculations should not need to renormalize paths since {@link File#listFiles}, + * {@link File#getParentFile}, etc. will not produce abnormal variants. * @param file file to normalize * @return normalized file * @since 4.48 --- a/openide.filesystems/test/unit/src/org/openide/filesystems/FileUtilTest.java +++ a/openide.filesystems/test/unit/src/org/openide/filesystems/FileUtilTest.java @@ -253,6 +253,44 @@ /** Tests normalizeFile() method. */ public void testNormalizeFile() throws IOException { // pairs of path before and after normalization + Map paths = createNormalizedPaths(); + + for (String path : paths.keySet()) { + File file = new File(path); + assertTrue("Idempotency violated for path: " + path, FileUtil.normalizeFile(FileUtil.normalizeFile(file)).equals(FileUtil.normalizeFile(file))); + assertEquals("File not normalized: " + path, paths.get(path), FileUtil.normalizeFile(file).getPath()); + } + } + + public void testNormalizeFileIsCached() throws Exception { + File f = new File(getWorkDir(), "text.txt"); + CharSequence log = Log.enable(FileUtil.class.getName(), Level.FINE); + File one = FileUtil.normalizeFile(f); + String msg = "FileUtil.normalizeFile for " + f; + if (log.toString().indexOf(msg) == -1) { + fail("One querfy for the file shall be in logs:\n" + log); + } + CharSequence log2 = Log.enable(FileUtil.class.getName(), Level.FINE); + File two = FileUtil.normalizeFile(f); + if (log2.toString().contains(msg)) { + fail("No second FileUtil.normalizeFile for in:\n" + log); + } + assertEquals("Files are equal", one, two); + } + + /** Tests normalizePath() method. */ + public void testNormalizePath() throws IOException { + // pairs of path before and after normalization + Map paths = createNormalizedPaths(); + + for (String path : paths.keySet()) { + assertTrue("Idempotency violated for path: " + path, FileUtil.normalizePath(FileUtil.normalizePath(path)).equals(FileUtil.normalizePath(path))); + assertEquals("File path not normalized: " + path, paths.get(path), FileUtil.normalizePath(path)); + } + } + + private Map createNormalizedPaths() throws IOException { + // pairs of path before and after normalization Map paths = new HashMap(); if (Utilities.isWindows()) { paths.put("A:\\", "A:\\"); @@ -291,30 +329,25 @@ // #137407 - java.io.File(".") should be normalized paths.put(".", new File(".").getCanonicalPath()); paths.put("..", new File("..").getCanonicalPath()); - - for (String path : paths.keySet()) { - File file = new File(path); - assertTrue("Idempotency violated for path: " + path, FileUtil.normalizeFile(FileUtil.normalizeFile(file)).equals(FileUtil.normalizeFile(file))); - assertEquals("File not normalized: " + path, paths.get(path), FileUtil.normalizeFile(file).getPath()); - } + return paths; } - - public void testNormalizeFileIsCached() throws Exception { - File f = new File(getWorkDir(), "text.txt"); + + public void testNormalizePathIsCached() throws Exception { + File f = new File(getWorkDir(), "textPath.txt"); + String path = f.getPath(); CharSequence log = Log.enable(FileUtil.class.getName(), Level.FINE); - File one = FileUtil.normalizeFile(f); + String one = FileUtil.normalizePath(path); String msg = "FileUtil.normalizeFile for " + f; if (log.toString().indexOf(msg) == -1) { fail("One querfy for the file shall be in logs:\n" + log); } CharSequence log2 = Log.enable(FileUtil.class.getName(), Level.FINE); - File two = FileUtil.normalizeFile(f); + String two = FileUtil.normalizePath(path); if (log2.toString().contains(msg)) { fail("No second FileUtil.normalizeFile for in:\n" + log); } assertEquals("Files are equal", one, two); } - /** Tests that only resolvers are queried which supply at least one of * MIME types given in array in FileUtil.getMIMEType(fo, String[]).