应用场景:
在eclipse插件开发中,插件中的某个动作需要使用当前java工程的classpath。例如在插件需要访问的XML资源文件可能已经打包在某个jar文件中了,而jar文件正好设置在当前工程的classpath中;再例如数据库访问插件,需要调用jdbc驱动,插件本身为了保证体积是不会包含数据库JDBC驱动的,这时可能需要访问当前工程classpath中的JDBC驱动。
解决办法:
因为已知当前工程(IProject),所以可以得到当前的Java工程(IJavaProject),根据IJavaProject可以得到所有的IPackageFragmentRoot,因而可以得到当前classpath的URLs,根据这些URL创建URLClassLoader即可。为了使用方便,我们将会把这个过程封装在ProjectClassLoader中,ProjectClassLoader继承了URLClassLoader。
实现:
import java.io.File; import java.net.URL; import java.net.URLClassLoader; import java.util.ArrayList; import java.util.Iterator; import java.util.List;
import org.eclipse.core.resources.IWorkspaceRoot; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.FileLocator; import org.eclipse.core.runtime.IPath; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.IPackageFragmentRoot; import org.eclipse.jdt.core.JavaModelException;
public class ProjectClassLoader extends URLClassLoader {
public ProjectClassLoader (IJavaProject project) throws JavaModelException { super(getURLSFromProject(project, null), Thread.currentThread().getContextClassLoader()); }
public ProjectClassLoader (IJavaProject project, URL[] extraUrls) throws JavaModelException { super(getURLSFromProject(project, extraUrls), Thread.currentThread().getContextClassLoader()); }
private static URL[] getURLSFromProject (IJavaProject project, URL[] extraUrls) throws JavaModelException { List<URL> list = new ArrayList<URL>(); if (null != extraUrls) { for (int i=0; i<extraUrls.length; i++) { list.add(extraUrls[i]); } }
IPackageFragmentRoot[] roots = project.getAllPackageFragmentRoots();
IPath installPath = ResourcesPlugin.getWorkspace().getRoot().getLocation();
for (int i=0; i<roots.length; i++) { try { if (roots[i].isArchive()) { File f = new File(FileLocator.resolve(installPath.append(roots[i].getPath()).toFile().toURL()).getFile()); if(!f.exists()){ f = new File(FileLocator.resolve(roots[i].getPath().makeAbsolute().toFile().toURL()).getFile()); } list.add(f.toURL()); } else { IPath path = roots[i].getJavaProject().getOutputLocation(); if (path.segmentCount() > 1) { IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot(); path = root.getFolder(path).getLocation(); list.add(path.toFile().toURL()); } else { path = roots[i].getJavaProject().getProject().getLocation(); list.add(path.toFile().toURL()); } } } catch (Exception e) {} }
URL[] urls = new URL[list.size()]; int index = 0; for (Iterator i=list.iterator(); i.hasNext(); index++) { urls[index] = (URL) i.next(); } return urls; } } |
IJavaProject javaProject = JavaCore.create(project);//IProject à IJavaProject
ProjectClassLoader loader = new ProjectClassLoader(javaProject);
《Building Commercial-Quality Plug-ins, Second Edition》一书中给出了另外一种实现:
Chapter 20. Advanced Topics/ Plug-in ClassLoaders
public class ProjectClassLoader extends ClassLoader { private IJavaProject project;
public ProjectClassLoader(IJavaProject project) { if (project == null || !project.exists() || !project.isOpen()) throw new IllegalArgumentException("Invalid project"); this.project = project; }
protected Class findClass(String name) throws ClassNotFoundException { byte[] buf = readBytes(name); if (buf == null) throw new ClassNotFoundException(name); return defineClass(name, buf, 0, buf.length); }
private byte[] readBytes(String name) { IPath rootLoc = ResourcesPlugin .getWorkspace().getRoot().getLocation(); Path relativePathToClassFile = new Path(name.replace(".","/") + ".class"); IClasspathEntry[] entries; IPath outputLocation; try { entries = project.getResolvedClasspath(true); outputLocation = rootLoc.append(project.getOutputLocation()); } catch (JavaModelException e) { FavoritesLog.logError(e); return null; } for (int i = 0; i < entries.length; i++) { IClasspathEntry entry = entries[i]; switch (entry.getEntryKind()) {
case IClasspathEntry.CPE_SOURCE : IPath path = entry.getOutputLocation(); if (path != null) path = rootLoc.append(path); else path = outputLocation; path = path.append(relativePathToClassFile); byte[] buf = readBytes(path.toFile()); if (buf != null) return buf; break; case IClasspathEntry.CPE_LIBRARY: case IClasspathEntry.CPE_PROJECT: // Handle other entry types here. break;
default : break; } } return null; }
private static byte[] readBytes(File file) { if (file == null || !file.exists()) return null; InputStream stream = null; try { stream = new BufferedInputStream( new FileInputStream(file)); int size = 0; byte[] buf = new byte[10]; while (true) { int count = stream.read(buf, size, buf.length - size); if (count < 0) break; size += count; if (size < buf.length) break; byte[] newBuf = new byte[size + 10]; System.arraycopy(buf, 0, newBuf, 0, size); buf = newBuf; } byte[] result = new byte[size]; System.arraycopy(buf, 0, result, 0, size); return result; } catch (Exception e) { FavoritesLog.logError(e); return null; } finally { try { if (stream != null) stream.close(); } catch (IOException e) { FavoritesLog.logError(e); return null; } } } }
|