1 / 21

Dynamic Code Generation in Java

Dynamic Code Generation in Java. Class Loading. Class loading is the process of transforming a byte code (e.g., a .class file) into a Java class A Java class can be loaded dynamically (i.e., during runtime) The class is then represented by an object of class Class

wilda
Download Presentation

Dynamic Code Generation in Java

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Dynamic Code Generation in Java

  2. Class Loading • Class loadingis the process of transforming a byte code (e.g., a .class file) into a Java class • A Java class can be loaded dynamically (i.e., during runtime) • The class is then represented by an object of class Class • You can use the method Class.forName("name") to get a pointer to the Class object, given its name (exactly one object represents each class).

  3. Dynamic Code Invocation • Using dynamic class loading, we can dynamically generate a .class file, load it, instantiate it (class.newInstance()), and invoke its methods • Therefore, we can write and execute methods within the execution of the calling program. • Q: How can we access a method of an object, if we do not know its type on compile time? • One solution is to implement a known interface.

  4. An Example • In the following example, we will invoke the method run() of a dynamically created object of class C, inherited from an interface Base

  5. publicinterfaceBase{ publicvoidrun(); } An Example publicclass Invoker { publicstaticvoid main(String[] argv)throwsException{ Stringcode="public class C implements Base {\n" +" public void run() {\n" +" System.out.println(\"++++++++++\");\n" + " }}"; createClassFile(code); // Implemented in the next slide Class classB =Class.forName("C"); Base b =(Base)classB.newInstance(); b.run(); }

  6. An Example publicstaticvoid createClassFile(String code) throwsException { OutputStream os = newFileOutputStream(newFile("C.java")); os.write(code.getBytes()); os.close(); Process p =Runtime.getRuntime(). exec("javac -classpath . C.java"); p.waitFor(); } }

  7. The Result

  8. The Whole Process

  9. Assumptions The example we just saw works correctlyunder the following assumptions: • The command javac is known to the System • e.g., the javac executable is in the PATH variable • The directory "." is in the class path of Java • Hence, Class.forName("C") will find that C.class

  10. Class Reloading Stringcode1="public class C implements Base {\n" +"public void run() {\n" +"System.out.println(\"++++++++++\");\n" + "}}"; Stringcode2="public class C implements Base {\n" + "public void run() {\n" +"System.out.println(\"----------\");\n" + "}}"; createClass(code1); ((Base)Class.forName("C").newInstance()).run(); createClass(code2); ((Base)Class.forName("C").newInstance()).run(); What is the problem here?

  11. The Result

  12. Class Loaders • Java classes are loaded by class loaders • Two special class loaders exist: (why not just one?) • The bootstrap class loader • Typically implemented completely in C. Loads the primitive classes that are necessary for the initialization of the JVM (rt.jar) • The system class loader • Loads the regular classes in the program (e.g., all of the classes that you have written so far in various exercises) • In addition, any number of user-defined class loaders may be defined • Each class loader has a parent class loader • Except for the bootstrap class loader • Having a null parent is the same as having the bootstrap class loader as a parent

  13. The System Class Loader • Class.forName(name)invokes loadClass(name) of the class loader of the current class, which is usually the system class loader • The system class loader can always be accessed by the static call: ClassLoader.getSystemClassLoader() • Hence, a class can explicitly be loaded by the system class loader as follows: ClassLoader.getSystemClassLoader().loadClass(name)

  14. Class Loading Mechanism • When loadClass(“C") is invoked on a class loader, the following is done by default: • check if a class names c has already been loaded by the same class loader • Otherwise, check if the parent can load the class • Hence certain classes will always be loaded by the bootstrap class loader – Why does this happen? Why is this good? • invoke the method findClass(“C") • The implementation of findClass differs between class loaders. • When you load a class, all referenced classes are recursively loaded by the same class loader • Including implemented interfaces and parent classes

  15. Back to our Example • In the previous example, the class loader didn’t reload the class since it previously loaded a class named C • So what should we do to reload a class? • Solution 1: Use a unique (randomized?) name each time we rewrite the code • Solution 2: Use a different user-defined class loader each time • make sure that this loader does not have a parent capable of loading class C • One way to implement this is using a new ClassLoader object obtained by instantiating java.net.URLClassLoader

  16. URLClassLoader • A URLClassLoader loads classes which are accessible via a URL (either a local file system URL or a remote URL) • It stores an array of URLs (“http://...”, “file://...”, etc.) of either directories or JAR files, and it loads classes from the resources of the URLs • Constructor: URLClassLoader(URLs,parent) • We will set the URLs to contain only the URL of “.”, and the parent to be null

  17. Fixed(?) Example URL[] urls ={newFile(".").toURL()}; createClass(code1); ClassLoader loader =new URLClassLoader(urls,null); Class classB = loader.loadClass("C"); ((Base)classB.newInstance()).run(); createClass(code1); loader =new URLClassLoader(urls,null); classB = loader.loadClass("C"); ((Base)classB.newInstance()).run(); What is the problem here?

  18. A Problem • The interface Base is also being loaded by the new class loader • But the system already has one interface called Base • Each newly created interface is deemed a unique interface that is different from the Base interface that is identified at compilation time and loaded by the system class loader. • Hence, it is impossible to cast C to Base

  19. Solutions • Solution 1: to invoke run(), use reflection rather than down casting • Solution 2: use the system class loader as a parent, but call findClass() directly, instead of loadClass() • problem: this method is protected • Solution? • Solution 3: Create a common parent to all these class loaders, capable of loading only the Base interface.

  20. Fixed(!) Example URL[] urls ={newFile(".").toURL()}; createClass(code1); ClassLoader loader =new URLClassLoader(urls,null); Class classB = loader.loadClass("C"); Method runMethod = classB.getMethod("run",null); runMethod.invoke(classB.newInstance(),null); createClass(code2); classB =new URLClassLoader(urls,null).loadClass("C"); classB.getMethod("run",null).invoke(classB.newInstance(),null);

  21. Finally, Different Outputs

More Related