One developer, 2 modifications
A developer has made 2 modifications, one to a client class, and a second to component classes. The client and component classes are packaged separately, but deployed together. When the developer tries to run the application, a "NoSuchMethodError" exception is thrown.
The "NoSuchMethodError" problem is a common one seen by developers new to Java. The exception is difficult to track down. Everything compiles and works on the developers box, but the error occurs when the application is deployed. Generally, "NoSuchMethodError" is caused with when the method signature of a class has changed. So why is the problem only showing up when the application is deployed? The CLASSPATH variable is the first place I look.
When the virtual machine starts up, the VM searches for and loads classes in the following order:
- Bootstrap classes - Classes that comprise the Java platform.
- Extension classes - Classes that use the Java Extension mechanism and are located in the extensions directory.
- User classes - These are classes located by the -classpath option on the command line (the preferred method) or by using the CLASSPATH environment variable.
The VM searches for user classes in the global and an application classpath. The global provides default values set at the system level. In NT this is the User or System environment variables. The application classpath is the one set on the load of the application with the -classpath option.
The preferred method
The preferred method is to use the application -classpath and NOT the global environment CLASSPATH variable.
- The JVM I've worked with, if a class shows up multiple times in the classpath, the first class is used and the second occurrence is ignored. Therefore, it cannot be expected to override the default global class with an updated jar on the java command line.
- Most likely a variety of applications will be running on a server. Different apps may/will require different versions of the same component. With the proliferation of open source, it is not uncommon to see multiple versions of Log4j or ORO on a box. Requiring all the Java applications to use a single version Log4j will eventually lead to problems.
- Pollution of the JVM space. A simple application may not require any supporting jars, but placing classes in the global classpath forces the JVM to deal with a support package each time an application is started. [Yes, the JVM has gotten much smarter about this problem, but I wouldn't expect every JVM to work the same, or handle the problem 100% perfectly.]
The nightmare begins
In IT environments with servers configured by an administrator, things get crazy. Some admins place common JARS in the java\lib directory; others have complex login scripts that dynamically change the environmental variables. Understanding the classpath in these settings becomes a nightmare. It only gets worse with different versions of J2EE environments. Some J2EE engines have started to use more and more open source components. If an application and a J2EE container are using the same open source component, with a different method signature, BOOM. Even if the application is J2EE compliant, that doesnt necessarily mean the app will run correctly on all application servers.
At least the "NoSuchMethodError" indicates that there is a problem, and gives a clue of where to look. Many times the method has changed, but the method signature has not. These problems are much more difficult to track down. Clearing the CLASSPATH will require a little more work on initial configuration of each application, but it will save a host of problems.