bytearray - Loading custom class loader to load a transferred byte[] in java -
i transfer whole .class file (and it's declared , anonymous classes) byte[] , want able define using class loader on computer receives byte[].
i have found solution @ java: how load class stored byte[] jvm?, however, don't understand how use byteclassloader purpose. post code here again:
public class byteclassloader extends urlclassloader { private final map<string, byte[]> extraclassdefs; public byteclassloader(url[] urls, classloader parent, map<string, byte[]> extraclassdefs) { super(urls, parent); this.extraclassdefs = new hashmap<string, byte[]>(extraclassdefs); } @override protected class<?> findclass(final string name) throws classnotfoundexception { byte[] classbytes = this.extraclassdefs.remove(name); if (classbytes != null) { return defineclass(name, classbytes, 0, classbytes.length); } return super.findclass(name); }
}
the question is: how have instantiate it?
i tried use instantiating byteclassloader b = new byteclassloader(...)
; obviously, not working (as expected).
i found way of loading new class loader @ beginning of program @ https://analyzejava.wordpress.com/2014/09/25/java-classloader-loading-a-custom-classloader-on-jvm-start/ using -djava.system.class.loader =...byteclassloader
, however, did not work either (it did not find class byteclassloader
. helpful me if point me right direction of how use referenced class loader (i'm new class loaders , not yet understand how work).
edit: have class serializeutils
method deserialize() instantiate byteclassloader
. did not work referenced implementation, tried byteclassloader extends classloader
(i did not know url[]
from) , change contextclassloader
of thread:
public static map<string, class<?>> deserialize(map<string, byte[]> classestodefine) { // serializeutils.class.getclassloader(). byteclassloader l = new byteclassloader(thread.currentthread().getcontextclassloader(), classestodefine); // todo // may // problem thread.currentthread().setcontextclassloader(l); map<string, class<?>> classes = new hashmap<>(); (string classname : classestodefine.keyset()) { try { system.out.println("classname in deserialize: "+ classname); class<?> c = ((byteclassloader)thread.currentthread().getcontextclassloader()).findclass(classname); system.out.println("class found : " + c.getname()); classes.put(classname, c); } catch (classnotfoundexception e) { e.printstacktrace(); } } return classes; }
what hoped achieve converted byte array available execution, such may able instantiate it. need passing actual data of object serialized byte array using and, right after loaded class, decode object , use using:
public static object decodejavaobject(byte[] me, int offset, int length) throws classnotfoundexception, ioexception { bytearrayinputstream bais = new bytearrayinputstream(me, offset, length); objectinputstream ois = new objectinputstream(bais); object obj = ois.readobject(); // no need call close of flush since use bytearrayinputstream return obj; }
so call serializeutils.deserialize() deserialize .class file in hope of having available afterwards. right after that, call
so complete deserialization process looks follows:
public static job deserialize(jobtransferobject jobtodeserialize) throws classnotfoundexception, ioexception { job job = new job(); (transferobject tasktransferobject : jobtodeserialize.tasktransferobjects()) { serializeutils.deserialize(tasktransferobject.classfiles()); task task = (task) utils.decodejavaobject(tasktransferobject.data(), 0, tasktransferobject.data().length); job.addtask(task); } return job; }
so first call serializeutils.deserialize() deserialize class files in hope of having them available next invocation of utils.decodejavaobject try deserialize byte[] of actual object transferred (so send class files of class want instantiate , decode object of class sent on network). task abstract class class file deserialize extends, task known program needs deserialize implementation of it). btw, transferobject looks this:
public class transferobject implements serializable{ /** * */ private static final long serialversionuid = 8971732001157216939l; private byte[] data; private map<string, byte[]> classfiles; private string classname; public transferobject(byte[] data, map<string, byte[]> classfiles, string classname) { this.data = data; this.classfiles = classfiles; this.classname = classname; } public byte[] data() { return this.data; } public map<string, byte[]> classfiles() { return this.classfiles; } public string classname() { return this.classname; }
}
(data = serialised object extending task on computer, classfiles = serialised class files of extended object, , classname actual name of extended class)
and extension of task on computer looks e.g. this:
task initshutdown = new task(writetask.currentid(), numberutils.next()) { /** * */ private static final long serialversionuid = -5543401293112052880l; @override public void broadcastreceiver(navigablemap<number640, data> input, dhtconnectionprovider dht) throws exception { dht.shutdown(); } };
and task abstract class following code:
public abstract class task implements serializable { /** * */ private static final long serialversionuid = 9198452155865807410l; private final number640 previousid; private final number640 currentid; public task(number640 previousid, number640 currentid) { this.previousid = previousid; this.currentid = currentid; } public abstract void broadcastreceiver(navigablemap<number640, data> input, dhtconnectionprovider dht) throws exception; public number640 currentid() { return this.currentid; } public number640 previousid() { return this.previousid; }}
sorry complicated explanation...
without having tested it, here suggestion:
create single classloader per definition map:
public static job deserialize(jobtransferobject jobtodeserialize) throws classnotfoundexception, ioexception { job job = new job(); (transferobject tasktransferobject : jobtodeserialize.tasktransferobjects()) { classloader cl = new byteclassloader(new url[0], task.class.getclassloader(), tasktransferobject.classfiles()); task task = (task)utils.decodejavaobject(tasktransferobject.data(), 0, tasktransferobject.data().length, cl); job.addtask(task); } return job; }
and extend objectinputstream
use classloader in deserialization:
public static object decodejavaobject(byte[] me, int offset, int length, final classloader cl) throws classnotfoundexception, ioexception { bytearrayinputstream bais = new bytearrayinputstream(me, offset, length); objectinputstream ois = new objectinputstream(bais) { @override protected class<?> resolveclass(objectstreamclass objectstreamclass) throws ioexception, classnotfoundexception { class<?> clazz = class.forname(objectstreamclass.getname(), false, cl); if (clazz != null) { return clazz; } else { return super.resolveclass(objectstreamclass); } } @override protected class<?> resolveproxyclass(string[] interfaces) throws ioexception, classnotfoundexception { class<?>[] interfaceclasses = new class[interfaces.length]; (int = 0; < interfaces.length; i++) { interfaceclasses[i] = class.forname(interfaces[i], false, cl); } try { return proxy.getproxyclass(cl, interfaceclasses); } catch (illegalargumentexception e) { return super.resolveproxyclass(interfaces); } } }; object obj = ois.readobject(); return obj; }
Thanks for give us valuable information
ReplyDeleteWordPress Support Australia
WordPress Support Number