Re: Classloading issues...

Brian Hawkins <brianhks-BYHubErIwDGZvNlLnfxc/[email protected]> Sun, 15 May 2005 10:48:18 -0600
Newsgroups gmane.comp.java.beanshell.devel
Message-ID <[email protected]>
Pat,

I've actually tried to do this with a project I'm working on.  See the 
attached file ClassLoaderWrapper.java.  The idea here is that in your 
main function use the ClassLoaderWrapper class to load your first 
class.  It would then set itself as the ClassLoader of all subsequent 
classes that are loaded and attempt to load all classes itself instead 
of differing to its parent.  The only classes it cannot load are the 
ones in the java package.  A security exception is thrown if it tries.  
So in that case it defers to its parent class loader.

The code is still in a working state but it did work.  My main objective 
was to be able to modify the classpath at runtime but this sounds 
similar to what you want to do.

I hope it helps

Brian

Patrick Niemeyer wrote:

>
> In order to complete BeanShell's class generation and classpath  
> management integration with Java I'm considering doing the following  
> things.  I'd be interested in any feedback:
>
> 1) Where allowed, BeanShell needs to set itself as the thread context  
> classloader (delegating to any previous context classloader) during  
> the span of an evaluation within the interpreter.
>
> This will allow generated classes and added / reloaded classpath to  
> be visible not only within the script but to any external Java apps  
> and APIs that respect the context classloader and are called by the  
> script.
>
> 2) Perhaps more controversially:  Within BeanShell scripts, the  
> interpreter needs to intercept calls to Class.forName() and perform  
> them relative to the BeanShell classloader.  I would expect this to  
> be part of a more general hook to intercept/override any registered  
> method or class.  (Another candidate would be ObjectInputStream).
>
> I realize that there are many ways to get a class loaded (e.g. you  
> could ask some random object for its class and get the classloader  
> that way).  We can't really intercept them all.  But this seems to  
> cover the most common case in a way that I believe the user would  
> expect.  As a reminder, BeanShell has a getClass() command that does  
> the right thing, but of course interpreting regular Java code we  
> won't find that.
>
> Let me know if you have thoughts.
>
>
> Pat
>
>
>
>
> -------------------------------------------------------
> This SF.Net email is sponsored by Oracle Space Sweepstakes
> Want to be the first software developer in space?
> Enter now for the Oracle Space Sweepstakes!
> http://ads.osdn.com/?ad_id=7393&alloc_id=16281&op=click
> _______________________________________________
> Beanshell-developers mailing list
> Beanshell-developers-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org
> https://lists.sourceforge.net/lists/listinfo/beanshell-developers
>
ClassLoaderWrapper.java (text/java, 3.1 KB)
/*
 * Copyright (c) 2004, Brian Hawkins
 * brianhks-BYHubErIwDGZvNlLnfxc/[email protected]
 * 
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the Free 
 * Software Foundation; either version 2 of the License, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful, but 
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 
 * for more details.
 *
 * You should have received a copy of the GNU General Public License along 
 * with this program; if not, write to the 
 * Free Software Foundation, Inc., 
 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 */
 
package bhutils;
 
import java.net.*;
import java.util.*;
import java.io.*;

public class ClassLoaderWrapper extends ClassLoader
	{
	private static ClassLoaderWrapper s_loader = null;
	ClassLoader m_parentLoader;
	
	private ClassLoaderWrapper()
		{
		//super(new URL[0], null);
		super(null);
		m_parentLoader = getClass().getClassLoader();
		}
		
	
	public static ClassLoaderWrapper getClassLoader()
		{
		if (s_loader == null)
			s_loader = new ClassLoaderWrapper();
			
		return (s_loader);
		}
		
	public static ClassLoader getSystemClassLoader()
		{
		System.out.println("Returning system class loader");
		return (getClassLoader());
		}
		
	public static InputStream getSystemResourceAsStream(String name)
		{
		System.out.println("System resource");
		return (ClassLoader.getSystemResourceAsStream(name));
		}
		
	public static Enumeration getSystemResources(String name)
			throws IOException
		{
		System.out.println("System resource");
		return (ClassLoader.getSystemResources(name));
		}
		
	public URL getResource(String name)
		{
		//System.out.println("Getting resource "+name);
		return (m_parentLoader.getResource(name));
		}
		
	public InputStream getResourceAsStream(String name)
		{
		//System.out.println("Getting resource "+name);
		return (m_parentLoader.getResourceAsStream(name));
		}
		
	//Special case for ClassLoader and ClassLoaderWrapper
	public Class loadClass(String name)
			throws ClassNotFoundException
		{
		Class ret;
		System.out.println("Loading "+name);
		
		ret = findLoadedClass(name);
		
		/*if (name.equals("java.lang.ClassLoader"))
			{
			System.out.println("Returning ClassLoader");
			Thread.dumpStack();
			ret = this.getClass();
			}
		else*/ 
		if (name.startsWith("java."))
			ret = m_parentLoader.loadClass(name);
		
		if (ret == null)
			{
			InputStream classIS = m_parentLoader.getResourceAsStream(name.replace('.', '/')+".class");
		
			if (classIS == null)
				ret = super.loadClass(name);
			else
				{
				int data;
				ByteArrayOutputStream classOS = new ByteArrayOutputStream();
				
				try
					{
					while ((data = classIS.read()) != -1)
						classOS.write(data);
					}
				catch(IOException ioe)
					{
					throw new ClassNotFoundException(ioe.getMessage());
					}
					
				ret = defineClass(name, classOS.toByteArray(), 0, classOS.size());
				resolveClass(ret);
				}
			
			}
		
		return (ret);
		}
		
	}