Class loading exceptions
What kind of class-loading error do you see when you develop an application or start an installed application?
ClassCastException
A class cast exception results when the following conditions exist and can be corrected by the following actions:
- The type of the source object is not an instance of the target class (type).
- The class loader that loaded the source object (class) is different from the class loader that loaded the target class.
- The application fails to perform or improperly performs a narrow operation.
- The type of the source object is not an instance of the target class (type).
- This is the typical class cast exception. We can diagnose whether the source object of a cast statement is not an instance of the target class (type) by examining the class signature of the source object class, then verifying that it does not contain the target class in its ancestry and the source object class is different than the target class. We can obtain class information by inserting a simple print statement in your code. For example:
System.out.println( source.getClass().getName() + ":" + target.getClass().getName() );Or use a javap command. For example:javap java.util.HashMap Compiled from "HashMap.java" public class java.util.HashMap extends java.util.AbstractMap implements java.util.Map,java.lang.Cloneable,java.io.Serializable {
- The class loader that loaded the source object (class) is different from the class loader that loaded the target class.
- Assuming that the type of the source object is an instance of the target class, a class cast exception occurs when the class loader that loaded the source object's class is different that the class loader that loaded the target class. This condition might occur when the target class is visible on the classpaths of more than one class loader in the WebSphere Application Server runtime environment. To correct this problem, use the Search and Search by class name console pages used to diagnose problems with class loaders:
- Click Troubleshooting > Class loader viewer > module_name > Search to access the Search page.
- For Search type, select Class/Package.
- For Search terms, type the name of the class that is loaded by two class loaders.
- Click OK. The Search by class name page is displayed, listing all class loaders that load the class.
If there is more than one class loader listed, then the target class was loaded by more than one class loader. Because the source object is an instance of the target class, the class loader that loaded the source object class is different from the class loader that loaded the target class.
- Return to the Class loader viewer page and examine the classpath to determine why two different class loaders load the class.
- Correct your code so that the class is visible only to the appropriate class loader.
- The application fails to perform or improperly performs a narrow operation.
- A class cast exception can occur because, when the application is resolving a remote enterprise bean (EJB) object, the application code does not perform a narrow operation as required. The application must perform a narrow operation after looking up a remote object. Examine the application and determine whether it looks up a remote object and, if so, the result of the lookup is submitted to a narrow method.
The narrow method must be invoked according to the EJB 2.0 programming model. In particular, the target class submitted to the narrow method must be the exact, most derived interface of the EJB. This also causes a class cast exception in the WAS runtime environment. Examine the application and determine whether the target class submitted to the narrow method is a super-interface of the EJB specified, not the exact EJB type; if so, modify the application to invoke narrow with the exact EJB interface.
Lastly, if a class cast exception occurs during a narrow operation, verify that the narrow method is being applied to the result of a remote EJB lookup, not to a local enterprise bean. A narrow is not used for local lookups. Examine the application or module deployment descriptor to ensure that the object being narrowed is not a local object.
ClassNotFoundException
A class not found exception results when the following conditions exist and can be corrected by the following actions:
- The class is not visible on the logical classpath of the context class loader.
- The application incorrectly uses a class loader API.
- A dependent class is not visible.
- The class is not visible on the logical classpath of the context class loader.
- The class not found is not in the logical class path of the class loader associated with the current thread. The logical classpath is the accumulation of all classpaths searched when a load operation is invoked on a class loader. To correct this problem, use the Search page to search by class name and by Java archive (JAR) name:
- Click Troubleshooting > Class loader viewer > module_name > Search to access the Search page.
- For Search type, select Class/Package.
- For Search terms, type the name of the class that is not found.
- Click OK. The Search by class name page is displayed, listing all class loaders that load the class.
- Examine the page to see if the class exists in the list.
- If the class is not in the list, return to the Search page. For Search terms, type the name of the .jar file for the class; for Search type, select JAR/Directory.
- Click OK. The Search by Path page is displayed, listing all directories that hold the JAR file.
If the JAR file is not in the list, the class likely is not in the logical class path, not readable or an alternate class is already loaded. Move the class to a location that enables it to be loaded.
- The application incorrectly uses a class loader API.
- An application can obtain an instance of a class loader and call either the loadClass method on that class loader, or it can call Class.forName(class_name, initialize, class_loader) with that class loader. The application may be incorrectly using the class loader API. For example, the class name is incorrect, the class is not visible on the logical classpath of that class loader, or the wrong class loader was engaged.
To correct this problem, determine whether the class exists and whether the application is properly using the class loader API. Follow the steps in The class is not visible on the logical classpath of the context class loader to determine whether the class is loaded. If the class has not been loaded, attempt to correct the application and see if the class loads. If the class is in the class path with proper permission and is not being overridden by another factory class, examine the API used to load the class.
- Click Troubleshooting > Class loader viewer > module_name > Search to access the class loader Search page.
- For Search type, select Class/Package.
- For Search terms, type the name of the class.
- Click OK. The Search by class name page is displayed, listing all class loaders that load the class.
- Examine the page to see if the class exists in the list.
- If the class is in the list and a ClassNotFound exception was thrown, then the .jar file or class is not in the correct context or a wrong API call in the current context was used.
If the class is not in the list, return to the Search page and do the following:
- Search for the class that generated the exception; that is, the class calling Class.forName.
- See which class loader loads the class.
- Determine whether the class loader has access or can load the class not found by evaluating the class path of the class loader.
- A dependent class is not visible.
- When a class loader clsldr loads a class cls, the JVM invokes clsldr to load the classes on which cls depends. Dependent classes must be visible on the logical classpath of clsldr, otherwise an exception occurs. This condition typically occurs when users make WAS classes visible to the JVM, or make application classes visible to the JVM or to the WebSphere extensions class loader. For example:
- Class A depends on Class B.
- Class A is visible to the WebSphere extensions class loader.
- Class B is visible on the local classpath of a WAR module class loader, not the WebSphere extensions class loader classpath.
When the JVM loads class A using the WebSphere extensions class loader, it then attempts to load Class B using the same class loader and ultimately creates a class not found exception.
To correct this problem:
- Make the application-specific classes visible to the appropriate application class loader.
- Search for the class not found (Class B).
- If Class B is in the proper location, search for the class that loads the dependent class (Class A) in the Class loader viewer.
- If the class is loaded and a ClassNotFound exception was thrown, then the .jar file or class is not in proper context or the wrong API call in the current context was used.
If no class was found, do the following:
- Search for the class that generated the exception; that is, the class calling Class.forName.
- See which class loader loads the class.
- Determine whether the class loader has access or can load the class not found by evaluating the class path of the class loader.
- Ensure that the caller class (Class B) is visible to the JVM or WebSphere extensions class loader.
NoClassDefFoundException
A no class definition found exception results when the following conditions exist and can be corrected by the following actions:
- The class is not in the logical class path.
- Refer to ClassNotFoundException for information.
- The class cannot load.
- There are various reasons for a class not loading. The reasons include: failure to load the dependent class, the dependent class has a bad format, or the version number of a class.
UnsatisfiedLinkError
A linkage error results when the following conditions exist and can be corrected by the following actions:
- A user action caused the error.
- (UNIX) System.mapLibraryName returns the wrong library file.
- The native library is already loaded.
- A dependent native library was used.
(UNIX)
- A user action caused the error.
Several user actions can result in a linkage error:
- A library extension name is incorrect for the platform.
(Windows) A library has the dynamic link library name library_name.dll.
(UNIX) A library has the name library_name.so or library_name.a.
- System.loadLibrary is passed an incorrect parameter.
(Windows) To load a dynamic link library named Name.dll, Name has to be passed to a loadLibrary call.
(UNIX) To load a library named libName.so or libName.a, libName is passed to the load library.
- The library is not visible.
- As a best practice, use the JVM class loader to find or load native libraries. WAS prints the Java library path (java.library.path) when starting up. If the JVM class loader is intended to load the library, verify that the path containing the native library file is in the Java library path. If not, append the path to the platform-specific native library environment variable or to the java.library.path system property of the server process definition.
In general, the Java virtual machine invokes findLibrary() on the class loader xxx that loads the class that calls System.loadLibrary(). If xxx.findLibrary() fails, the Java virtual machine attempts to find the library using the JVM class loader, which searches the JVM library path. If the library cannot be found, the Java virtual machine creates an UnsatisfiedLinkError exception.
Thus, if a WebSphere class loader is intended to find a native library myNativeLib, the library must be visible on the nativelibpath of the class loader that loads the class that calls System.loadLibrary(myNativeLib). This practice is necessary or desirable in the following situation:
- Native libraries for data source providers must be visible on the nativelibpath of the WebSphere extensions class loader. In this case, add the path containing the native library to the Native library path setting of the data source provider configuration.
- Shared libraries have a Native library path in their configuration. Because shared libraries enable the versioning of application-specific libraries, consider specifying the paths to any native libraries used by the shared library code in the shared library configuration.
Ensure that the correct WebSphere class loader loads the class that calls System.loadLibrary() and that the native library is visible on the Native library path setting.
- System.mapLibraryName returns the wrong library file.
- When loading a shared library, JVM calls mapLibraryName(libName) to convert libName to a platform specific name. On AIX, HP-UX or Solaris operating systems, this call might return a file name with the wrong extension (for example, libName.so rather than libName.a). To debug this, write a program to that calls System.mapLibraryName() and verify that it returns the correct file name.
- The native library is already loaded.
- This condition can result from either of the following errors:
- User error
- Check for multiple calls to System.loadLibrary and remove any extraneous calls.
- Error when an application restarts
- The JVM has a restriction that only one class loader can load a native library at a time. An error results when an application restarts before the garbage collector cleans up the class loader from the stopped application. When the class that loads the native library moves, all of the classes that depend on that native library and their dependencies also must move.
To correct this condition, move the loading of the native library to a class loader that does not reload:
- Locate all application classes that load native libraries or have native methods.
- Identify any dependent classes for the classes in step 1, such as logging packages.
- Create a server-associated shared library or an isolated shared library.
- Move the JAR files loaded for classes in steps 1 and 2 from the application to the shared library created in step 3.
- Save changes.
- Redeploy the application and rerun the scenario.
Classes within server-scoped libraries are loaded once for each server lifecycle, ensuring that the native library required by the application is loaded once for each Java virtual machine, regardless of the application's life cycle.
- A dependent native library was used.
- Dependent native libraries must be found or loaded by the JVM class loader. That is, if a native library NL is dependent on another native library, DNL, the JVM class loader must find DNL on the Java library path. This is because the JVM runs native code when loading NL; when it encounters the dependency on DNL, the JVM native code can call only to the JVM class loader to resolve the dependency. A WebSphere class loader cannot load a dependent native library.
Modify the platform-specific environment variable defining the Java library path (LIBPATH) to include the path containing the unresolved native library.
Related:
Class loaders Create shared libraries Configure class loaders of a server Class loading Class loader viewer settings Enterprise application topology Search settings Shared library settings Web resource is not displayed Application startup errors Demystifying class loading problems, Part 2 Basic class loading exceptions