This Bugzilla instance is a read-only archive of historic NetBeans bug reports. To report a bug in NetBeans please follow the project's instructions for reporting issues.
In Projects build 20030915, I am unable to open an existing project on windows. The exception in the attachment is thrown. The cause of the problem is in org.openide.util.Utilities, method toFile(URL), as this method is unable to deal with files containing spaces. E.g. the following URL: file:/C:/Documents and Settings/pj97932/Projects/ is not translated to a File correctly. The patch should probably be something like URL-encoding parts of the URL string, however I am not sure what exactly needs to be done. Could we come across similar problems with e.g. multibyte file names? So the immediate patch could be replacing spaces by + (as URLEncoder would do), and we can think of a solution for the more general case.
Created attachment 11650 [details] Exceptions which cause the failure
Created attachment 11651 [details] A quick patch which fixes the spaces, but more may need to be done
Now I noticed that method Utilities.toFile(URL) (used from URLMapper) is deprecated, so it probably should be avoided altogether. But how? The one way I can think of is to deprecate URLMapper and introduce URIMapper. java.net.URI is nicer than java.net.URL - it has e.g. the toASCIIString() method, which can be useful.
Two static method methods in org.openide.util.Utilities were deprecated [snip]: * @deprecated Use {@link URI#URI(String)} and {@link File#File(URI)} instead under JDK 1.4. * (There was no proper equivalent under JDK 1.3.) public static File toFile(URL u) * @deprecated Use {@link File#toURI} and {@link URI#toURL} instead under JDK 1.4. * ({@link File#toURL} is buggy in JDK 1.3 and the bugs are not fixed in JDK 1.4.) public static URL toURL(File f) I don't think, that these two methods should be deprecated. Problems will appear for space and hash chars in path names . According to above description developers will write anything like that: File f = new File (new URI (myUrl.toExternalForm () )); 1/ Spaces in path: URI constructor in this case fires URISyntaxException for following URL : myUrll = new URL ("file:/C:/Documents and Settings/admin/Windows/"). This can be avoided by calling new URI (myUrl.getProtocol (), myUrl.getFile (), null). 2/ '#' as fragment in path (new URL ("file:/C:/Documents and Settings/admin/my#Folder/data/")) myUrl.toExternalForm () doesn't escape # here. then new URI (myUrl) accept # as fragment and new File (new URI (myUrl)) then fires IllegalArgumentException because there is not expected fragment at all. So, there must be some explicit decision if # is really fragment or is part of path and must be somehow escaped e.g.: replaceAll ("#",URLEncoder.encode("#")); I think this could be just responsibility of methods toFile and toURL.
Radek, thanks for your comments. I don't really know what should be done, so I defer to Jesse. But in general, using deprecated API is evil (especially since it causes bugs), and I see three potential solutions: 1) Un-deprecating the deprecated method and fixing it. The fix must also make sure that we correctly handle non-ASCII and multibyte characters. 2) Replacing the call to the deprecated API with a non-deprecated equivalent, however in this case I can't think of one. 3) Deprecating the class that calls deprecated API, and the corresponding API class (i.e. URLMapper), and providing a replacement (URIMapper ?) Jesse, what do you think?
I'm afraid I don't understand what the problem is here - other than a bug in some projects code that I don't know about. file:/C:/Documents and Settings/pj97932/Projects/ is an invalid URL, which you should not pass to toFile. (The Utilities methods now just delegate to the new JDK 1.4 methods, which should be used directly.) If you passed file:/C:/Documents%20and%20Settings/pj97932/Projects/ then probably it would work - I don't have access to a Windows machine to test. toURL should create URLs of the above form. If not, it is a JRE bug which should be filed, and we don't deal with it further. In my experience everything works smoothly in JRE 1.4 - spaces and hash marks are escaped perfectly well. Grepping prj40_prototype branch, I find: return new URL ("file:."); // NOI18N return new URL ("file:" + relName.toString()); // NOI18N -rw-rw-r-- 1 jglick jglick 6415 Jun 26 02:24 projects/ide/src/org/netbeans/modules/projects/ide/RelativeResolver.java Which is crap. If to == from, the relative URL is ".". "file:." is wrong, it is a bogus URL. In any case, a relative URL should have no protocol. If you write "file:foo/bar", this means the same as new File("foo/bar"), which is to say $nbhome/bin/foo/bar usually. Not sure if that code is at fault, or something else. But I don't see anything wrong in org.openide.filesystems, or in the impls of the now-deprecated methods. Probably some other piece of code makes bad URLs.
Ok, I am starting to understand what's going on. JDK does not make sure that URLs are properly encoded, so if you do new File("C:\\Documents and Settings\\pj97932\\Projects").toURL(), this returns a URL that contains spaces. For this reason, I thought it was ok to pass this URL to URLMapper.findFileObjects(...). I think it should be clarified in the URLMapper javadoc that such URLs are not acceptable. Note that the JDK 1.4 Javadoc for File.toURL() contains the following disclaimer: "Usage note: This method does not automatically escape characters that are illegal in URLs. It is recommended that new code convert an abstract pathname into a URL by first converting it into a URI, via the toURI method, and then converting the URI into a URL via the URI.toURL method." Regading the Projects code - you are right, this is flawed. On the other hand, manipulating relative URLs (which is needed in Projects) is not easy with JDK, the URI class is much more suitable for this. I believe if Projects stored URIs in the project file instead of URLs, the implementation could be simplified considerably. Adding Vita to cc:, so he can comment.
See also enhancement request 36188, which is somewhat related.
It is very simple - do not use File.toURL, ever. It generates unusable results. Consider it deprecated. Always use File.toURI().toURL() (or just File.toURI()) instead. I would have liked the JRE team to @deprecate the method, or (better) fix it to return toURI().toURL(), but for some reason they did not do either. Some likely culprits: return f.toURL(); -rw-rw-r-- 1 jglick jglick 6208 Jul 17 12:24 projects/compilation/test/unit/src/org/netbeans/api/compilation/BuildTargetOutputFolderTest.java url : resolver.toURL(fos[0]); -rw-rw-r-- 1 jglick jglick 9708 Jul 9 07:30 projects/ide/src/org/netbeans/modules/projects/ide/ProjectGroupDataObject.java u = f.toURL(); -rw-rw-r-- 1 jglick jglick 9282 Apr 21 05:48 projects/ide/src/org/netbeans/modules/projects/ide/ui/BaseOutputFolder.java setValue(new File(text).toURL()); setValue(f.toURL()); -rw-rw-r-- 1 jglick jglick 23969 Aug 6 10:36 projects/ide/src/org/netbeans/modules/projects/ide/ui/looks/OutputLook.java URL rememberedProjectHome = new File(home).toURL(); -rw-rw-r-- 1 jglick jglick 26710 Sep 3 15:47 projects/ide/src/org/netbeans/modules/projects/ide/wizards/ProjectLocationPanel.java Assuming this is a projects problem.
OK, there are two problems mentioned here: #1 - project's resolvers create bogus URLs when trying to relativize them. This can be easily fixed I think. #2 - we are using File.toURL() or generaly we aren't using correct methods for following conversions String <-> URL <-> File/FileObject. I admit I am confused a bit. Is there any guideline on what is the right way to do these conversions in regards of JDK bugs, etc. Or could you approve/disapprove that following is correct: String -> URI: new URI(string) URI -> String: URI.toASCIIString() File -> URI: File.toURI() URI -> File: new File(uri) URL -> FileObject: URLMapper.findFileObjects(url) FileObject -> URL: FileObject.getURL() URI -> URL: URI.toURL() URL -> URI: new URI(url.toExternalForm()) Any other conversions possible and safe? I remember we already had some troubles with persisting URLs and I would generaly prefere to use URIs, but all netbeans APIs are working with URLs and that's why I thought URLs are ok. It's unclear to me whether if I get URL from netbeans API (e.g. FileObject, URLMapper, etc) it's safe to persist it directly or if I have to convert it to URI and persist this URI instead?
OK, I'll try to go through the listed conversions as best I know: new URI(String) - fine URI.toASCIIString() - OK, but toExternalForm = toString is fine File.toURI() - fine new File(URI) - fine URLMapper.findFileObjects(URL) - fine FileObject.getURL() - works, but URLMapper.findURL(FileObject,int) is probably more useful URI.toURL() - fine new URI(URL.toExternalForm()) - fine You forgot: File.toURI().toURL() new File(new URI(URL.toExternalForm()) What is *not* safe: File.toURL() - does not work correctly new File(URL.getPath().replace('/', File.separatorChar)) - does not work Should be safe to persist URLs directly.
Thanks, I think this explains what needs to be fixed and how. However, shouldn't we still think of gradually moving the IDE to use URI instead of URL? I.e. create a URIMapper class etc. The one notable advantage of URIs is that they have a better support for relative locations and relativizing a location against another location. Also, if FileSystems API intends to be an abstraction over java.io.File, it should have the same capabilities as java.io.File. Lastly, the support for File <-> URI conversion is better than the support for File <-> URL conversion, although that's a very minor advantage.
I think it would be fine to support URIs more consistently, though I disagree that they are a *replacement* for URLs - they serve somewhat different purposes, as outlined in the Javadoc for URI. File RFEs as needed. File <-> URL conversion is perfectly safe so long as you go through URI and do not attempt to use the broken File.toURL call.
As described in http://www.netbeans.org/servlets/ReadMsg?msgId=619519&listName=nbdiscuss the current work on projects prototype has been stopped.
Marking issue as VERIFIED --->
---> CLOSED