Re: dealing with ClassLoaders...
Josip Almasi <joe@vrspace.org> wrote:
On 07/31/2014 09:40 PM, Andreas Leitgeb wrote:
The classloader tutorials I skimmed so far seem to imply, that
a custom classloader is only appropriate to enable classloading
from sources that the system classloader cannot handle itself.
Nah, it's also appropriate for context isolation.
But it seems like it doesn't really make it easy to use it
that way.
Is there a clean way to keep classes of a given package confined
to some custom classloader, in order to control the classes' and
their statics' scope/lifetime?
Yep, just don't break delegation model.
Model says something like, a classloader should ask parent classloader
if it has already loaded the class.
So, make sure you respect that rule.
The twist in my case comes from the fact, that the parent *could*
theoretically have loaded one of my special classes, but that would
just indicate a programming error (aka Bug), so I'd rather have the
compiler or at least the VM report a strange ClassCastException
than silently use one of my classes loaded by wrong classloader.
Also, make sure your loaders don't load the same packages.
This I don't understand.
While my "special classes" happen to be in a specific package,
I don't see, why packages as such would be relevant. I'd expect
that even within the same package I should (in principle) be
allowed to have some classes loaded through parent and others
through custom classloader.
My latest hack of loadClass now looks like this:
@Override
public Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
Class<?> res = null;
if (name != null && name.startsWith(PACKAGE_PREFIX)) {
synchronized (this) {
res = m_classes.get(name);
if (res != null) { return res; }
// name -> classData
byte[] classData = new byte[1024*1024*10]; int len = 0;
URL url = getSystemResource(name.replace('.', '/') + ".class");
try {
len = url.openConnection().getInputStream().read(classData);
} catch (IOException e) {
e.printStackTrace();
}
// if anything went wrong, let defineClass complain...
res = defineClass(name, classData, 0, len);
if (resolve && res != null) { resolveClass(res); }
m_classes.put(name, res);
return res;
}
} else {
return super.loadClass(name,resolve);
}
}
This appears to work (from watching the debugger pass through it),
although it is obviously quick'n'dirty. Most obviously, I'd like
to get rid of the 10M-sized array, but I don't think I can ask the
URL or the Stream about the exact size beforehand.
I'd welcome hints for how to improve the "classname -> byte[]" step.
Yep, get rid of statics.
On my TODO list for later.
Thanks for your reply.