The serializer - A Java Agent that serializes classes at load time
Introduction
The serializer is a Java agent that instruments classes as the JVM loads them by marking some of them as serializable. Marking a class serializable involves two steps:
- Adding the "java.io.Serializable" interface to the list of interfaces the class implements.
- Adding a private static final long serialVersionUID variable to the class, and initializing it appropriately.
The classes to be thus marked are specified via a set of system properties. At class load time, the serializer performs the following steps:
- If the class belongs to a handful of "untouchable" packages (such as those with names starting with "java.", "javax.", "com.sun.", "sun.misc.", etc.) it is not instrumented.
- If the class belongs to a set of packages that the user wants instrumented (as specified by the "makeser" system property), and also to a list of classes or sub-packages that the user does not wish to instrument (specified by the "ignoreser" system property), it is not instrumented.
- If the class does not belong to the set of packages that the user wants instrumented, it is not instrumented.
- If the class is an interface, it is not instrumented.
- If the class is abstract, it is not instrumented.
- If all the above checks "pass", the class is instrumented.
Defining the agent
Several things must be done to setup a Java agent (see references). Specifically, an entrypoint class must be created and declared in a manifest file entry (see com.subhajit.serializer.SerializerMain and the META-INF/MANIFEST.MF file provided in the source code). The SerializerMain class:

contains a method named "premain" which acts as the entry point into the agent. In our case, the "premain" method adds a "ClassFileTransformer" instance of the "SerializerTransformer" class (included in the provided source code). The SerializerTransformer class is where the meat of the instrumentation occurs.
The SerializerTransformer class uses two system properties, named "makeser" and "ignoreser" to read comma separated lists of packages which must be, and which must be instrumented, respectively. An example value for the "makeser" system property is "com.mycompany.project1.impl,com.mycompany.project1". The "ignoreser" system property must be declared similarly. If either of these system properties is missing, the SerializerTransformer class treats them as if they were empty strings. (This can have strange effects. If, for example, the "makeser" system property is not defined, no class is instrumented).
SerializerTransformer transformer first checks the class name (against untouchable packages and those that have been declared via the "makeser" and "ignoreser" system properties). It next checks the class bytes (by creating a (BCEL) JavaClass object and getting information about the class via this object). Finally, it instruments class bytes for those classes that it determines should be instrumented. The actual code that performs the instrumentation is surprisingly simple:

Using the serializer
To use the supplied source code, you must first build it using the supplied (ant) build script. The output produced by the build are two files named "dist/serializer.jar" and "dist/serializer.zip". Copy the zip file to a location where you want your applications to find it (eg. "/opt/serializer/" or "c:\ser\serializer\"), and unzip it therein to create three files, namely "serializer.jar", "becl-5.2.jar" and "src.zip". Include the "bcel-5.2.jar" in your application's class path.
Next, modify the launch script of your application in the following manner:
- Add the JVM option: -javaagent:{locationOfSerializerJars}/serializer.jar
- Add the "makeser" system property by setting its value to a comma-separated list of package names that must be instrumented (eg. -Dmakeser=com.mycompany.myproject1,com.mycompany.commonlib).
- Add the "ignoreser" system property by setting its value to a comma separated list of package and class names that must not be instrumentd.
That is it. When your application start up, you would see a number of messages from the serializer (in your standard output) indicating classes it has decided to instrument.
Source code and references
You can download the source code for the serializer here.
References for Java agents:
- 1. http://javahowto.blogspot.com/2006/07/javaagent-option.html
- 2.http://java.sun.com/javase/6/docs/api/java/lang/instrument/Instrumentation.html

Comments