8 May 18:13
Re: [groovy-dev] GroovyClassLoader recompile problem
From: Jochen Theodorou <blackdrag@...>
Subject: Re: [groovy-dev] GroovyClassLoader recompile problem
Newsgroups: gmane.comp.lang.groovy.devel
Date: 2008-05-08 16:13:01 GMT
Subject: Re: [groovy-dev] GroovyClassLoader recompile problem
Newsgroups: gmane.comp.lang.groovy.devel
Date: 2008-05-08 16:13:01 GMT
Hans Lund schrieb:
> H
>
> I can't get the GroovyClassLoader to recompile scripts from the
> filesystem, and I suspect this to be a bug?
>
> As far as I can deduct -> resolving classes with loadClass(className,
> true, false, true);
> will a) if the class is not loaded -> create a GroovyCodeSource() with
> some meta data about the source
the most important fact that you should ensure is, that the
configuration used for this class loader has the recompilation enabled.
Without that nothing will happen. So for the following I guess it is
enabled.
> -- snip from GroovyCodeSource(final File infile) --
>
> try {
> Object[] info = (Object[]) AccessController.doPrivileged(new
> PrivilegedExceptionAction() {
> public Object run() throws MalformedURLException {
> Object[] info = new Object[2];
> URL url = file.toURI().toURL();
> info[0] = url.toExternalForm();
> //toURI().toURL() will encode, but toURL() will not.
> info[1] = new CodeSource(url, (Certificate[]) null);
> return info;
> }
> });
> this.name <http://this.name> = (String) info[0];
> this.codeSource = (CodeSource) info[1];
>
> ---------------------
> the meta data (name and codeSource) generated is then used in the
> GroovyClassLoader cashing.
true, with the name as key and the code source or url as value
> But now subsequent calls to loadClass(className, true, false, true);
> might fail to evaluate
> correct because the source url in isSourceNewer(URL source, Class cls) -
> here is not the correct URL
does it need to be the same URL?
> but a url created from the url encoded external form from the meta-data.
> Now, if the original filepath contains
> chars that have been encoded (like spaces), the url is now altered and
> the path is not found -> as a consequence
> lastMod evaluates to 0, and isSourceNewer always return false.
this is fine as long as the file is still found.
> protected boolean isSourceNewer(URL source, Class cls) throws IOException {
> long lastMod;
>
> // Special handling for file:// protocol, as getLastModified()
> often reports
> // incorrect results (-1)
> if (source.getProtocol().equals("file")) {
> // Coerce the file URL to a File
> String path = source.getPath().replace('/',
> File.separatorChar).replace('|', ':');
> File file = new File(path);
> lastMod = file.lastModified();
> } else {
> URLConnection conn = source.openConnection();
> lastMod = conn.getLastModified();
> conn.getInputStream().close();
> }
> long classTime = getTimeStamp(cls);
> return classTime + config.getMinimumRecompilationInterval() <
> lastMod;
> }
let's say the class you want to recompile is originally a source file in
the file system, then usually the protocol is file. source.getPath()
will return the path to the file... so either the path is encoded wrong,
then file.lastModified(); will cause an exception, or it works. If the
other path is taken, then the URL methods are taken... if that does not
work, then it is a bug in URL
So besides having a potential problem in URL itself, we have the
encoding problem. Of course I can run a script like this one:
File f = new File("/tmp/ö+ß")
assert f.createNewFile() == true
URL url = f.toURI().toURL()
println url.path
f = new File(url.path)
assert f.exists()==true
it will not fail, but I am on a unix like system would be nice if you
could test this script on your system as well if it is not like that...
of course you have to adapt the path then. But I see a problem in this
code. That is when the file name contains |. So I redo my test first with |
File f = new File("/tmp/|")
//assert f.createNewFile() == true
URL url = f.toURI().toURL()
String path = URLDecoder.decode(url.path,"UTF8")
println path
f = new File(path)
assert f.exists()==true
In that case it will fail, because it will search for "/tmp/%7C" instead
of "/tmp/|".... oh well, not the problem with replace I thought to get,
but now I get the encoding problem you mentioned. So I guess it s a bug.
> A very quick fix could be
>
> if (source.getProtocol().equals("file")) {
> // Coerce the file URL to a File
> String path = source.getPath().replace('/',
> File.separatorChar).replace('|', ':');
> File file = new File(URLDecoder(path));
> lastMod = file.lastModified();
> }
>
> but I'm not sure about the consequences (I guess that recompile now will
> fail)
hmm..
File f = new File("/tmp/|")
assert f.createNewFile() == true
URL url = f.toURI().toURL()
String path = URLDecoder.decode(url.path,"UTF8")
println path
f = new File(path)
assert f.exists()==true
this will do.. I wonder if
source.getPath().replace('/',File.separatorChar).replace('|', ':');
becomes obsolete after this. Could someone with a windows system do a test?
> Right now I'm unclear about why the keys in the GroovyClassLoader is not
> the URL object but a String representation,
because it is the name of the class. The URL won't make sense, since you
can't have multiple versions of a class with the same name in the same
loader.
> why all the conversions from URL to string and back to URL? if anyone
> could point me towards the some hints on why
> the URI/URL is not the native abstraction within the GroovyClassLoader?
because ClassLoader#loadClass(String) uses a String, and because the
normal class loading is not URL based.
> PS: This regards v 1.6-beta-1
and 1.5.6
Could you please fill an issue for this?
bye blackdrag
--
--
Jochen "blackdrag" Theodorou
The Groovy Project Tech Lead (http://groovy.codehaus.org)
http://blackdragsview.blogspot.com/
http://www.g2one.com/
---------------------------------------------------------------------
To unsubscribe from this list, please visit:
http://xircles.codehaus.org/manage_email
RSS Feed