Presentation is loading. Please wait.

Presentation is loading. Please wait.

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.

Similar presentations


Presentation on theme: "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."— Presentation transcript:

1 Dynamic Code Generation in Java

2 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 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 An Example public class Invoker { public static void main(String[] argv) throws Exception { String code = "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(); } public interface Base { public void run(); }

6 An Example public static void createClassFile(String code) throws Exception { OutputStream os = new FileOutputStream(new File("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 correctly under 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 String code1 = "public class C implements Base {\n" + "public void run() {\n" + "System.out.println(\" \");\n" + "}}"; String code2 = "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 = {new File(".").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 = {new File(".").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


Download ppt "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."

Similar presentations


Ads by Google