Reflection vs. code generation
Avoid runtime reflection when marshaling data
By Michael J. Rettig With Martin Fowler, JavaWorld.com, 11/02/01
- Digg
- Reddit
- SlashDot
- Stumble
- del.icio.us
- Technorati
- dzone
Data marshaling (pulling data from an outside source and loading it into a Java object) can utilize the benefits of reflection
to create a reusable solution. The problem is simple enough: load data from a file into an object's fields. Now, what if the
target Java classes for the data change on a weekly basis? A straightforward solution still works, but you must continually
maintain the loading procedures to reflect any changes. To further complicate the situation, the same problem may crosscut
the system's breadth. Anyone who has dealt with a large system using XML has encountered this problem. Coding a load procedure
is often tedious and subject to frequent updates and rewrites due to changes to the source data or the target Java class.
A solution using reflection, which I'll describe here, often requires less coding, and updates itself when changes are made
to the target Java class.
Originally, I intended to demonstrate a solution using reflection during runtime for data marshaling. Initially a dynamic,
reflection-based program was far more attractive than a simpler approach. Over time, the novelty faded to reveal the complexity
and risk of runtime reflection. This article charts this evolution from runtime reflection to active code generation.
From simplicity to complexity
My first solution used a loading class to load the objects' data from a flat file. My source code contained several dozen
calls for the next token of a StringTokenizer object. After several refactorings (see Martin Fowler's Refactoring), my coding logic became straightforward, nearly systematic. The class structure dictated code. My initial solutions showed
me that I needed only to account for three basic objects:
- Strings
- Objects
- Arrays of objects
You could map the class's objects to generalized code blocks, as shown in the following table:
Objects mapped to generalized code blocks
| Field type |
Code block |
String |
fileIterator.nextString();
|
Object[] |
Vector collector = new Vector();
while(fileIterator.hasMoreDataForArray()){
Object data = initializeObject(fileIterator)collector.add(data);
}
Object[] objArray = new Object[collector.size()];
collector.copyInto(objArray);
|
Object |
initializeObject(fileIterator);
|
|
Having coded the solution several times, I knew the solution and the code structure before I wrote any of the code. The difficulty
arose from the classes' changing landscape. The class names, compositions, and structures could change at any moment, and
any change could force a rewrite. Given these changes, the structure and loading process still remained the same; I still
knew the code structure and composition before I wrote the code. I needed a way to translate the coding processes in my head
into a reproducible, automated form. Since I am an efficient (i.e., lazy) programmer, I quickly tired of writing nearly identical
code. Reflection came to my rescue.
Marshaling usually requires source and target data maps. Maps can take the shape of a schema, DTD (document type definition),
file format, and so on. In this case, reflection interprets an object's class definition as the target map for our mapping
process. Reflection can duplicate the code's functionality during runtime. So during a required rewrite, I replaced the load
procedure with reflection in the same amount of time it would have taken me to do the rewrite.
- Digg
- Reddit
- SlashDot
- Stumble
- del.icio.us
- Technorati
- dzone
Resources
- Obtain the source code for this article
http://www.javaworld.com/javaworld/jw-11-2001/codegen/jw-1102-codegen.zip
- The Pragmatic Programmer, Andrew Hunt and David Thomas (Addison-Wesley, 2000; ISBN020161622X) is an excellent source for advanced programming practices
and principles such as code generation
http://www.amazon.com/exec/obidos/ASIN/020161622X/javaworld
- "Continuous Integration," Martin Fowler with Matthew Foemmel, provides an informative look at successful continuous integration,
plus more information on how to use Ant for a painless integration effort
http://www.martinfowler.com/articles/continuousIntegration.html
- RefactoringImproving the Design of Existing Code, Martin Fowler (Addison-Wesley, 1999; ISBN0201485672) -- without well-factored code, the realization that code generation
is even a possibility is an impossibility
http://www.amazon.com/exec/obidos/ASIN/0201485672/javaworld
- Visit the Ant homepage to learn how to use Ant to automate your build process
http://jakarta.apache.org/ant/
- JUnit -- a simple, free unit-testing tool
http://junit.org
- "Make an EJB from Any Java Class with Java Reflection," Tony Loton (JavaWorld, December 2000)
http://www.javaworld.com/javaworld/jw-12-2000/jw-1215-anyclass.html
- "Code Generation Using Javadoc," Mark Pollack (JavaWorld, August 2000)
http://www.javaworld.com/javaworld/jw-08-2000/jw-0818-javadoc.html
- For more articles on Object-Oriented Design and Programming, check out JavaWorld's Topical Index
http://www.javaworld.com/channel_content/jw-oop-index.shtml
- For more articles on Java APIs, visit JavaWorld's Topical Index
http://www.javaworld.com/channel_content/jw-apis-index.shtml
- Subscribe to JavaWorld's free weekly email newsletters
http://www.idg.net/jw-subscribe
- Speak out in our Java Forum
http://forums.idg.net/webx?13@@.ee6b802
- You'll find a wealth of IT-related articles from our sister publications at IDG.net