9 May 10:06
Re: [groovy-dev] GroovyClassLoader recompile problem
From: Hans Lund <ha.lund@...>
Subject: Re: [groovy-dev] GroovyClassLoader recompile problem
Newsgroups: gmane.comp.lang.groovy.devel
Date: 2008-05-09 08:06:37 GMT
Subject: Re: [groovy-dev] GroovyClassLoader recompile problem
Newsgroups: gmane.comp.lang.groovy.devel
Date: 2008-05-09 08:06:37 GMT
On Thu, May 8, 2008 at 6:13 PM, Jochen Theodorou <blackdrag-BA+cFGlbTmA@public.gmane.org> wrote:
No just point to the same resource
file.lastModified() return "0L if the file does not exist or if an I/O error occurs"
No file.lastModified() never throws an exception -> it returns 0L
are you sure??
As far as I can see the Source URL that is parsed to the method might not be pointing to the same resource as the original location where found.
when the source url is constructed the assumption seams to be that
String somestring
URL u1 = new URL(somestring);
URL u2 = new URL(URLDecode(somestring, ENCODING)
will point to the same resource, and that is a wrong assumption!
This fails on windows, and do not have any guarantied behavior -> But the following should be guarantied on all platforms:
File f = new File("/tmp/ö+ß")
assert f.createNewFile() == true
URL url = f.toURI().toURL()
f = new File(url.toURI())
assert f.exists()==true
or simply keeping the URI.
I still don't see why all the explicit decoding/encoding takes place, It should not be needed at all File should be constructed from the URI when URL or URI is the resource locator.
It's GROOVY-2811
Hans Lund schrieb: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.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
-- snip from GroovyCodeSource(final File infile) --this.name <http://this.name> = (String) info[0];
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.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 valuedoes it need to be the same URL?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
No just point to the same resource
this is fine as long as the file is still found.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.
file.lastModified() return "0L if the file does not exist or if an I/O error occurs"
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,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;
}
No file.lastModified() never throws an exception -> it returns 0L
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
are you sure??
As far as I can see the Source URL that is parsed to the method might not be pointing to the same resource as the original location where found.
when the source url is constructed the assumption seams to be that
String somestring
URL u1 = new URL(somestring);
URL u2 = new URL(URLDecode(somestring, ENCODING)
will point to the same resource, and that is a wrong assumption!
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.
This fails on windows, and do not have any guarantied behavior -> But the following should be guarantied on all platforms:
File f = new File("/tmp/ö+ß")
assert f.createNewFile() == true
URL url = f.toURI().toURL()
f = new File(url.toURI())
assert f.exists()==true
or simply keeping the URI.
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.
I still don't see why all the explicit decoding/encoding takes place, It should not be needed at all File should be constructed from the URI when URL or URI is the resource locator.
hmm..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)
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 ifbecomes obsolete after this. Could someone with a windows system do a test?
source.getPath().replace('/',File.separatorChar).replace('|', ':');
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.Right now I'm unclear about why the keys in the GroovyClassLoader is not the URL object but a String representation,
because ClassLoader#loadClass(String) uses a String, and because the normal class loading is not URL based.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?
and 1.5.6PS: This regards v 1.6-beta-1
Could you please fill an issue for this?
It's GROOVY-2811
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