Dynamic Java beans
Dynamic Java Beans
(Available under http://blogs.sun.com/adventures/)
Introduction
In this article, I show how to
dynamically create Java bean classes and load them using application
defined custom class loaders. Java beans are useful in a number of
application domains [1,2]. Traditionally, Java beans are created by
first writing source code for the desired bean and then compiling it.
This works best for applications in which the Java bean classes to be
used are known before hand. There are some applications, however,
that need to create Java beans dynamically,
that is, they need to create ad-hoc beans as they run.
There are two tasks
to the problem of creating dynamic Java beans at runtime, namely:
- Generating the
byte code of the Java bean classes. - Loading the
generated byte code via specified class loaders.
In this exercise,
we accomplish these tasks as follows:
- Specify a name
for the Java bean to be created (“com.subhajit.synthetic.Point”). - Specify the
fields (names and types) that the Java bean must contain (“x” of
type “int” and “y” of type “int”). - Generate the
byte codes of the Java bean class. - Load these
byte codes via a specified class loader.
Here is a snippet
for code that shows how the above steps are performed:

Here, “BeanCreator”
is the “com.subhajit.superbean.BeanCreator” class which is
provided in the source code accompanying this article (see download
link below).
Having gone over what we accomplish in the provided source code, let
us delve deeper into steps 3 (generating byte code) and 4 (loading
byte code).
Generating byte code
Byte code may be generated by several
means. With the advent of the compiler API in Java 6 [3], one might
generate source code for the intended Java bean, compile it, and
obtain the bytes of the resulting class [4]. On the other hand, one
might choose to use a byte code generation library (such as ASM [5]
or Apache BCEL [6]) to generate byte code directly.
Recognizing that byte code may be
generated in a number of different ways, we define an interface named
“ClassGenerationStrategy” to hide the actual strategy used to
generate the byte code:
You may define your own byte code
generation strategy by implementing this interface, and construct an
instance of the “BeanCreator” class. Alternatively, you may use
the default implementation (“BcelClassGenerator”).
The “generateClassBytes” method of
“BcelClassGenerator” shows how to use BCEL to generate byte code
for Java beans. There are methods to declare the Java bean class, add
a default constructor, add private fields for the desired bean
properties and add “getter” and “setter” methods for each
property. The code is somewhat involved if (like me) you are not
familiar with the JVM's byte code format. If you really want to dig
deeper into these steps, see [7,8].
Loading byte code
Generating byte code for a class is
well and good, but the byte code by itself of little use unless it
can be loaded as a Java class. After all, it is only after we have a
Java class is it possible to do useful things like instantiating the
class to create new objects, setting up instances with different
values, followed by presumably doing something useful with these
instances.
The “standard” way to convert a
byte array to a Java class is via one of the overloads of the
“defineClass” method in the “java.lang.ClassLoader” class.
This final method accepts a class name (of the resulting class), a
byte array, an offset (within the byte array) and length of bytes
(within the byte array, starting at the offset), and returns a Java
class (see the Java doc for the “java.lang.ClassLoader” class for
details). The “standard” way to get access to the “defineClass”
method is to implement a custom class loader class, override the
“findClass” method, and call “defineClass” therefrom.
In this exercise, we use a different
technique. We modify the user defined URLClassLoader (passed in as a
constructor argument to the “BeanCreator” class) by adding a
special URL to its list of URL's. Generated byte code that we wish to
load with this class loader is placed in this special URL. Subsequent
requests to this class loader to load the class causes it to go
through its built in class finding and loading mechanism, which
ultimately results in the class being found and loaded.
The “special” URL added to the user
defined URLClassLoader uses a special protocol (“mem”) made up to
facilitate URL's that refer to memory locations instead of
directories and files on disk. Basically, URL's using the “mem”
protocol are backed by a singleton instance of a concurrent hash map
in memory, which maps String names to byte arrays. Information is
saved into memory URL's just as it would be saved into any other URL
using the following steps:
- Connect to the URL and get an
URLConnection object. - Setup the URLConnection to perform
output. - Obtain an OutputStream from the
URLConnection object. - Write the byte array to the
OutputStream. - Flush and close the OutputStream.
The following code snippet illustrates
these steps:

Before delving into the details
of implementing this scheme, let us see what this scheme buys us from
the perspectives of code that produces (generates)
byte code, and code that consumes
(uses) the generated
byte code. Code that produces byte code “writes” the generated
bytes to a special URL. Code that consumes byte code simply “loads”
generated classes using the specified URLClassLoader.
To accomplish this scheme, we need to
lay some groundwork:
-
Make the “mem” URL protocol
“known” to the Java runtime. Note that some protocols like
“file” and “http” are built into the standard libraries,
allowing the creation of new URL's using these protocols using code
such as:
Trying to create
an URL using the “mem” protocol results in an error (a
MalformedURLException is thrown):
-
Custom URL protocols (such as the
“mem” protocol) are supported by user defined “url stream
handler factories”, and “registering” instances of these
factories to handle specific custom protocols. Accordingly, we
create a user defined class named
“com.subhajit.memoryurl.MemoryURLStreamHandler” that implements
the “java.net.URLStreamHandlerFactory” interface, and
registering a default instance thereof using the code:
The “createURLStreamHandler”
method of the “URLStreamHandlerfactory” interface is implemented
as follows:
The
URLStreamHandler returned by this method is an extension of the
“java.net.URLConnection” class named
“com.subhajit.memoryurl.MemoryURLConnection”.
The “BeanCreator” class modifies
the URLClassLoader passed in by the user by appending a memory URL to
the end of the URL's managed by the URLClassLoader. This memory URL
uses the following scheme to identify classes :
“mem://prefix/fullyQualifiedClassNameInJVMFormat.class” (eg.
“mem://0/com/subhajit/beans/Point.class”). The prefix is uniquely
created per BeanCreator instance so that different URLClassLoaders
created by the application cannot “see” classes created on memory
URL's added to other user defined URLClassLoader instances.
The following code (of the
“setClassBytesInMemoryURL” method of the “BeanCreator” class)
shows how a producer of Java byte code “publishes” classes:

answered is how the “BeanCreator” class modifies the list of
URL's managed by user defined URLClassLoader instances. Looking at
the implementation of the URLClassLoader class, it is apparent that
the field named “ucp” (of type “sun.misc.URLClassPath”) is
responsible for managing an URLClassLoader's URL's. Using reflection,
the “ucp” field's “addURL” method is invoked (with the memory
URL) to accomplish the modification. The “updateUrlClassPath”
method in “BeanCreator” shows these steps:

In general, using undocumented
functionality, especially when it is not intended to be used, is a
very bad idea. In this case, we use it simply because it is a means
to an end in accomplishing a dynamic activity (loading classes).
The “BeanCreator” class's
“defineClass” method defines bean classes with the following
twists:
- If the class that is sought to be
defined has already been defined, the previously defined class is
returned. - If any of the constituent members
of a bean that is being defined belong to classes that are not
visible to this BeanCreator's modified class loader, the classes are
read as resources and redefined in this class loader so that it can
load the generated class.
Examples of use
The “com.subhajit.superbean.test.TestSuite” class illustrates
the use of this code generation scheme. Some examples of use are
presented below.
The following code snippet shows how to create a “Point” class
containing two integer properties named “x” and “y”, followed
by creating a “Line” class containing two “Point” properties
named “start” and “end”:

References
-
http://java.sun.com/javase/technologies/desktop/javabeans/index.jsp
-
http://en.wikipedia.org/wiki/JavaBeans
-
http://java.sun.com/javase/6/docs/technotes/guides/javac/index.html
-
http://www.juixe.com/techknow/index.php/2006/12/13/java-se-6-compiler-api/
-
-
http://jakarta.apache.org/bcel/
-
http://java.sun.com/docs/books/jvms/second_edition/html/VMSpecTOC.doc.html
-
http://en.wikipedia.org/wiki/JVM
Code download
http://blogs.sun.com/adventures/resource/beancreator.zip



Comments