classpath - Parent Last Classloader to solve Java Class path hell? -
i have project uses 2 versions of bouncycastle jars bcprov-jdk15 , bcprov-jdk16. jvm loads older version there feature wrote needs newer version run. tried solve classpath hell using custom class loader. after googling , of previous stackoverflow answers[1] [2] , blog, wrote following parent last class loader load classes newer jar before delegating parent class loader.
public class parentlastclassloader extends classloader { private string jarfile; //path jar file private hashtable classes = new hashtable(); //used cache defined classes public parentlastclassloader(classloader parent, string path) { super(parent); this.jarfile = path; } @override public class<?> findclass(string name) throws classnotfoundexception { system.out.println("trying find"); throw new classnotfoundexception(); } @override protected synchronized class<?> loadclass(string classname, boolean resolve) throws classnotfoundexception { system.out.println("trying load"); try { system.out.println("loading class in child : " + classname); byte classbyte[]; class result = null; //checks in cached classes result = (class) classes.get(classname); if (result != null) { return result; } try { jarfile jar = new jarfile(jarfile); jarentry entry = jar.getjarentry(classname + ".class"); inputstream = jar.getinputstream(entry); bytearrayoutputstream bytestream = new bytearrayoutputstream(); int nextvalue = is.read(); while (-1 != nextvalue) { bytestream.write(nextvalue); nextvalue = is.read(); } classbyte = bytestream.tobytearray(); result = defineclass(classname, classbyte, 0, classbyte.length, null); classes.put(classname, result); return result; } catch (exception e) { throw new classnotfoundexception(classname + "not found", e); } } catch( classnotfoundexception e ){ system.out.println("delegating parent : " + classname); // didn't find it, try parent return super.loadclass(classname, resolve); } } }
i loaded main class in feature class loader bouncycaslte classes used in feature not loaded custom classloader.
classloader loader = new parentlastclassloader(thread.currentthread().getcontextclassloader(), pathtojar); class myclass = loader.loadclass("mainclassofthefeature"); method mainmethod = myclass.getmethod("mainmethod"); mainmethod.invoke(myclass.getconstructor().newinstance());
jvm still uses classes loaded older version. how can make jvm load classes class loader when running feature , use loaded older classes in older jar when feature not running?
edit: problem remains after setting custom classloader thread context classloader in mainmethod of feature main class.
thread.currentthread().setcontextclassloader(this.getclass().getclassloader());
i managed solve problem. modified code of parentlastclassloader array of all jarfile paths needed feature. when class loaded, jarfiles needed feature searched .class files. if class file cannot found, delegated parent.
private class parentlastclassloader extends classloader { private string[] jarfiles; //paths jar files private hashtable classes = new hashtable(); //used cache defined classes public parentlastclassloader(classloader parent, string[] paths) { super(parent); this.jarfiles = paths; } @override public class<?> findclass(string name) throws classnotfoundexception { system.out.println("trying find"); throw new classnotfoundexception(); } @override protected synchronized class<?> loadclass(string classname, boolean resolve) throws classnotfoundexception { system.out.println("trying load"); try { system.out.println("loading class in child : " + classname); byte classbyte[]; class result = null; //checks in cached classes result = (class) classes.get(classname); if (result != null) { return result; } for(string jarfile: jarfiles){ try { jarfile jar = new jarfile(jarfile); jarentry entry = jar.getjarentry(classname.replace(".","/") + ".class"); inputstream = jar.getinputstream(entry); bytearrayoutputstream bytestream = new bytearrayoutputstream(); int nextvalue = is.read(); while (-1 != nextvalue) { bytestream.write(nextvalue); nextvalue = is.read(); } classbyte = bytestream.tobytearray(); result = defineclass(classname, classbyte, 0, classbyte.length, null); classes.put(classname, result); } catch (exception e) { continue; } } result = (class) classes.get(classname); if (result != null) { return result; } else{ throw new classnotfoundexception("not found "+ classname); } } catch( classnotfoundexception e ){ system.out.println("delegating parent : " + classname); // didn't find it, try parent return super.loadclass(classname, resolve); } } }
the parentlastclassloader instantiated follows.
classloader loader = new parentlastclassloader(thread.currentthread().getcontextclassloader(), paths);
once parentlastclassloader instantiated, mainclassofthefeature loaded , mainmethod invoked.
Comments
Post a Comment