Dynamic Code Generation in Java Class Loading Class

  • Slides: 18
Download presentation
Dynamic Code Generation in Java

Dynamic Code Generation in Java

Class Loading • Class loading is the process of transforming a byte code (e.

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. for. Name("name") to generate a Class object, given its name

Dynamic Code Invocation • Using dynamic class loading, we can dynamically generate a. class

Dynamic Code Invocation • Using dynamic class loading, we can dynamically generate a. class file, load it, instantiate it (class. new. Instance()), and invoke its methods • Hence, we can dynamically write and invoke programs • How can we access a method of an object, if we do not know its type on compile time? • One way is to implement a known interface

Our Example • In the following example, we will invoke the method run() of

Our Example • In the following example, we will invoke the method run() of a dynamically created object of type Base public interface Base { public void run(); }

An Example public class Invoker { public static void main(String[] argv) throws Exception {

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" + " }}"; create. Class(code); Class class. B = Class. for. Name("C"); Base b = (Base)class. B. new. Instance(); b. run(); }

An Example public static void create. Class(String code) throws Exception { Output. Stream os

An Example public static void create. Class(String code) throws Exception { Output. Stream os = new File. Output. Stream(new File("C. java")); os. write(code. get. Bytes()); os. close(); Process p = Runtime. get. Runtime(). exec("javac -classpath. C. java"); p. wait. For(); } }

The Whole Process

The Whole Process

Assumptions The later code assumes the following: • The command javac is known to

Assumptions The later code assumes the following: • The command javac is known to the System - e. g. , the javac executable is in the PATH variable • The directory ". " is included in the class path of Java - Hence, Class. for. Name("C") will find that class

Class Reloading String code 1 = "public class C implements Base {n" + "public

Class Reloading String code 1 = "public class C implements Base {n" + "public void run() {n" + "System. out. println("+++++"); n" + "}}"; String code 2 = "public class C implements Base {n" + "public void run() {n" + "System. out. println("-----"); n" + "}}"; What is the problem here? create. Class(code 1); ((Base)Class. for. Name("C"). new. Instance()). run(); create. Class(code 2); ((Base)Class. for. Name("C"). new. Instance()). run();

The System Class Loader • Java classes are loaded using a class loader •

The System Class Loader • Java classes are loaded using a class loader • Class. for. Name(name) usually invokes load. Class(name) of the system class loader • The system class loader can be accessed by Class. Loader. get. System. Class. Loader() • Hence, a class can equivalently be loaded by Class. Loader. get. System. Class. Loader(). load. Class(name)

Bootstrap Class Loader • Another class loader that exists in the system is the

Bootstrap Class Loader • Another class loader that exists in the system is the bootstrap class loader • This class loader is built in with the JVM • This class is used to load built-in JVM classes, and is used early in the runtime startup • Classes that you write are usually loaded by the system class loader, and not by the bootstrap one

Class Loading Method • Every class loader has a parent class loader, which could

Class Loading Method • Every class loader has a parent class loader, which could be null • By default, class loading is done as follows: - check if a class with the given name has already been loaded by the same class loader - check if the parent can load the class • If parent is null, use the bootstrap class loader - invoke the method find. Class("class-name") • When you load a class, all referenced classes are recursively loaded by the same class loader

Back to our Example • So what should we do to reload a class?

Back to our Example • So what should we do to reload a class? • Answer: - use a new class loader to load the class C - make sure that this loader does not have a parent capable of loading class C • For that, we can obtain a Class. Loader object by instantiating java. net. URLClass. Loader

URLClass. Loader • A URLClass. Loader has an array of URLs (“http: //. .

URLClass. Loader • A URLClass. Loader has an array of URLs (“http: //. . . ”, “file: //. . . ”, etc. ) of either directories or JAR files, and it loads classes from the resources of the URLs • Constructor: URLClass. Loader(URLs, parent) • We will set the URLs to contain only the URL of “. ”, and the parent to be null

Fixed(? ) Example URL[] urls = {new File(". "). to. URL()}; create. Class(code 1);

Fixed(? ) Example URL[] urls = {new File(". "). to. URL()}; create. Class(code 1); Class. Loader loader = new URLClass. Loader(urls, null); Class class. B = loader. load. Class("C"); What is the problem here? ((Base)class. B. new. Instance()). run(); create. Class(code 1); loader = new URLClass. Loader(urls, null); class. B = loader. load. Class("C"); ((Base)class. B. new. Instance()). run();

A Problem • The interface Base is also being loaded by the new class

A Problem • The interface Base is also being loaded by the new class loaders - But the system already has one interface called Base • Each newly created interface is considered as a unique interface • Hence, it is impossible to cast C to Base

Solutions • Solution 1: to invoke run(), use reflection rather than down casting •

Solutions • Solution 1: to invoke run(), use reflection rather than down casting • Solution 2: use the system class loader as a parent, but call find. Class() directly, instead of load. Class() - problem: this method is protected - Solution? - Solution 2 is given in Exercise 3

Fixed(!) Example URL[] urls = {new File(". "). to. URL()}; create. Class(code 1); Class.

Fixed(!) Example URL[] urls = {new File(". "). to. URL()}; create. Class(code 1); Class. Loader loader = new URLClass. Loader(urls, null); Class class. B = loader. load. Class("C"); Method run. Method = class. B. get. Method("run", null); run. Method. invoke(class. B. new. Instance(), null); create. Class(code 2); class. B = new URLClass. Loader(urls, null). load. Class("C"); class. B. get. Method("run", null). invoke(class. B. new. Instance(), null);