HomeDigital EditionSys-Con RadioSearch Java Cd
Advanced Java AWT Book Reviews/Excerpts Client Server Corba Editorials Embedded Java Enterprise Java IDE's Industry Watch Integration Interviews Java Applet Java & Databases Java & Web Services Java Fundamentals Java Native Interface Java Servlets Java Beans J2ME Libraries .NET Object Orientation Observations/IMHO Product Reviews Scalability & Performance Security Server Side Source Code Straight Talking Swing Threads Using Java with others Wireless XML
 

Conditional Compilation In java, by Sreedhar Chintalapaty

Conditional compilation is not available in Java - and Java's platform independence is the cited (and largely justified) reason. Nevertheless, one valuable use of conditional compilation, which is to cleanly insert debug code into applications, is thereby lost.

Several methods to work around this disadvantage are available. Joe Chou details these approaches in previous issues of Java Developer's Journal (see www.sys-con.com/java/article2a.cfm?id=409&count=1698&tot=10&page=2).

In this article I propose an approach that's arguably simpler, more scalable, and more flexible than any existing method. Although it can potentially be used for full-fledged conditional compilation, we'll limit ourselves to the problem of clean debug code.

Problem Statement
From a functional point of view, informational output can be classified as either:

  • Diagnostic messages: Designed to remain in the code even after release. These are what an as-released application writes out into its logs when executed in verbose mode.
  • Debug messages: Used by programmers in the development stage to debug their code. These correspond to the program's debug mode execution and would ideally be deleted from the release version of the code.
Therefore, we need a simple lightweight approach that can:
  1. Handle selection of classes to run in debug (or verbose) mode without having to recompile them.
  2. Leverage the compiler's built-in optimization capabilities to safely ignore debug code when compiling the release version of the application.

The Proposed Solution
The proposed solution consists of three components as shown in Figure 1:


Figure 1
  • Debug.properties: A text file containing class names and the desired debug mode, respectively.
  • DebugModeSettable: An interface used primarily to hold a final boolean value _DEVELOPMENT. This is set to true during _DEVELOPMENT. When the code is ready for shipping, this is set to false and the entire code is recompiled.
  • SmartDebug: A class that provides access into debug.properties via a properties object. This provides a mechanism for class-level control at runtime.
To see how this design leverages built-in optimization features of Java compilers to conditionally compile code, consider how Java compiles the class TestOne: with DebugModeSet-table._DEVELOPMENT set to true, the compiler expects to determine the value of TestOne.DEBUG at runtime by calling SmartDebug.getDebugMode(). Therefore, all code enclosed within if (DEBUG){...} is compiled.

However, with DebugModeSettable. _DEVELOPMENT set to false, Java knows that TestOne.DEBUG is always going to be evaluated to false. So it does not compile any code enclosed within if (DEBUG_){...}.

Verifying the above is trivial:

  1. Compile the class Test-One.java with DebugModeSettable._DEVELOPMENT set to true; decompile TestOne.class.
  2. Now compile TestOne.java with DebugModeSettable._DEVELOPMENT set to false and decompile TestOne.class.
  3. Compare the two decompiled versions.
VERBOSE, on the other hand, will always have to be evaluated at runtime. So any code enclosed within if (VERBOSE){...} will be compiled, regardless of the value of DebugModeSettable. _DEVELOPMENT.

Usage
Figure 2 illustrates the use of this approach.


Figure 2

As an example, assume that you would like to use this approach on a class called MyClass. The recipe, then, is as follows:

  1. Let MyClass implement DebugModeSettable.
  2. Set the following classwide variables in MyClass:
    private final String CLASSNAME = " MyClass ";
    private final boolean DEBUG = _DEVELOPMENT && SmartDebug
    .getDebugMode(CLASSNAME);
    private final boolean VERBOSE = SmartDebug.getDebugMode(CLASSNAME);
  3. Wrap debug code within if (DEBUG){...}, and diagnostic code within if (VERBOSE){...} respectively.
  4. Edit Debug.properties to add the following line:
    MyClass=true
    MyClass.java may look like the example shown in Listing 1.

Limitations
We have used this approach profitably in a couple of projects at PTC. The limitations of this approach are as follows:

  1. Every top-level class needs to implement the interface DebugModeSettable.
  2. It takes a little discipline on the part of programmers to enclose their debug/diagnostic code appropriately, but the gains far outweigh this burden.
Conclusion
This approach can be used to conditionally compile any code, not just debug/diagnostic code. On those rare occasions when programmers do need to port their Java code, it could prove just as valuable to Java as conditional compilation is to C/C++. Clean debug code, however, is its best and most uncontroversial use.

Author Bio
Sreedhar Chintalapaty is an implementation consultant with PTC. He is a java neophyte, currently involved in developing product data management and collaborative product commerce solutions using PTC's Windchill and NetMarkets products.
[email protected]

	


Listing 1

import ext.util.*;


public class MyClass implements DebugModeSettable {
   private static String CLASSNAME              = "MyClass";
   private static final boolean DEBUG   = _DEBUG && SmartDebug.getDebugMode(CLASSNAME);
   private static final boolean VERBOSE = SmartDebug.getDebugMode(CLASSNAME);


   // Some stuff here
   // resetStatus()
   // terminateProgram()


   public static void doSomething(String action) {
          if (VERBOSE) {
                System.out.println("Entered MyClass.doSomething - Action = " + action);
          }


          int currentStatus = getCurrentStatus();


          if (action.equalsIgnoreCase("TerminateProgram")) {
                if (DEBUG) {
                        System.out.println("In MyClass.doSomething - Terminating Program; 
						Exit Status is " + currentStatus);
                }
                terminateProgram(currentStatus);
          }


          if (action.equalsIgnoreCase("Reset")) {
                if (DEBUG) {
                        System.out.println("In MyClass.doSomething - Current Status " 
						+ currentStatus + " being reset");
                }
                resetStatus();
          }
        } // End doSomething


}



  
 

Download Assoicated Source Files (Zip format ~ 3.81 KB)

 

All Rights Reserved
Copyright ©  2004 SYS-CON Media, Inc.
  E-mail: [email protected]

Java and Java-based marks are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries. SYS-CON Publications, Inc. is independent of Sun Microsystems, Inc.