Archive Packaging and Assembly Rules
JBoss Enterprise Application Platform 6 uses a modular classloading system for controlling the class paths of deployed applications. This system provides more flexibility and control than the traditional system of hierarchical class loaders. This can simplify packaging of archives and eliminate the need to bundle Java EE 6 and other common classes. The following are general rules for assembly of archives or directories that are deployed to JBoss Enterprise Application Platform 6:
-
Archives may be nested within other archived deployments.
-
Extracted directories may be nested in extracted deployments.
-
Archives may be nested in extracted deployments.
-
Extracted directories may NOT be nested in archived deployments. You must recreate archives for the nested artifacts.
-
In WebLogic, an extracted WAR, EAR, or other archive can be deployed without the archive extension in the directory name. In JBoss, the extension must appear on the extracted directory name, for example myEnterpriseApp.ear or myWebApp.war.
-
The JBoss AS 7 installation includes Java EE 6, JBoss Logging, Hibernate, and other commonly used classes in the server install modules/ directory. You can also create custom dynamic modules to make third-party JARs and other resources available to all applications running on the server. Modules are only loaded when a deployment requests them and these JARs or classes should not be bundled within the application archives.
-
For web applications, it is generally better to avoid the use of a web.xml file if possible. If this file is required, it should be located under the root of the application WEB-INF/ directory.
-
If your enterprise application requires an application.xml file, it should be located under the META-INF/ directory in the root of the EAR.
Debug and Resolve ClassCastExceptions and ClassNotFoundExceptions
A ClassCastException can occur because a class is being loaded by a different class loader than the class it extends. It can also be a result of the same class existing in multiple JARs. A ClassNotFoundException can be a result of missing JARs or a mismatch of API versions. Due to the modular class loading system used by JBoss AS 7, you may need to modify deployment descriptors, remove JARs, or change the packaging structure of your EAR or WAR.
JBoss AS ships with a number of classes, or modules, that are commonly used by applications. These classes are located in the JBOSS_HOME/modules/system/layers/base/ directory and include all the application server provided APIs, the Java EE APIs, as well as other APIs such as JBoss Logging. If your WebLogic application packages a JAR that is also included in the server modules/system/layers/base/ directory, you may see a ClassCastException when you deploy or run your application. If your application needs a version of the classes that is different than the classes located in the JBOSS_HOME/modules/system/layers/base/ directory, you may see a ClassCastException or a ClassNotFoundException.
For more information about class loading and modules, refer to the chapter entitled Class Loading and Modules in the Development Guide for JBoss Enterprise Application Platform 6 on the Customer Portal .
Resolve ClassCastExceptions Caused by Duplicate JARs
Because JBoss AS 7 ships with a number of classes, or modules, that are commonly used by applications, packaging these common JARs with your application can result in a ClassCastException. For example, if you bundle the jstl.jar and standard.jar with the application archive, you may see a ClassCastException similar to the following:
08:38:01,867 ERROR [org.apache.catalina.core.ContainerBase.[jboss.web].[default-host].[/].[MVCUserInterface]] (http-localhost/127.0.0.1:8080-2)
Servlet.service() for servlet MVCUserInterface threw exception: java.lang.ClassCastException: javax.servlet.jsp.jstl.fmt.LocalizationContext cannot be cast to java.lang.String at org.apache.taglibs.standard.tag.common.fmt.BundleSupport.getLocalizationContext(BundleSupport.java:178)
[jboss-jstl-api_1.2_spec-1.0.3.Final-redhat-2.jar:1.0.3.Final-redhat-2]
The following is an example of the procedure used to resolve this type issue.
To resolve this issue:
-
Find the JBoss module that contains the class named by the ClassCastException. In this case, the jboss-jstl-api_1.2_spec-1.0.3.Final-redhat-2.jar can be found in the EAP_HOME/modules/system/layers/base/javax/servlet/jstl/api/main directory.
-
Explicitly define the dependency in either the MANIFEST.MF file or in the jboss-deployment-structure.xml file. The following is an example of a jboss-deployment-structure file that defines the module dependency:
<jboss-deployment-structure xmlns="urn:jboss:deployment-structure:1.2">
<deployment>
<dependencies>
<module name="javax.servlet.jstl.api" slot="main" />
</dependencies>
</deployment>
</jboss-deployment-structure>
-
Search the application archive to find all JAR(s) that are packaged with the application that contain the class named by the ClassCastException. In this case, the jstl.jar and standard.jar JARs were packaged in the lib/ folder of the application archive. Remove the duplicate JAR(s) from the application's packaged WAR or EAR file.
Resolve ClassCastExceptions and ClassNotFoundExceptions Caused by API Version Differences
If your application uses a version of an API other than the default API included in the main/ module of the modules/system/layers/base/ directory, you may see a ClassCastException or a ClassNotFoundException when you run the application.
For example, if your application uses JSF 1.2 instead of the default JSF 2.0, you may see you may see a ClassCastException or ClassNotFoundException like the following:
Caused by: java.lang.ClassNotFoundException: javax.faces.FacesException from \[Module "deployment.weblogic-example.ear:main" from Service Module Loader\]
at org.jboss.modules.ModuleClassLoader.findClass(ModuleClassLoader.java:191)
In this case, it cannot find the class javax.faces.FacesException due to a mismatch in API versions. The default JSF module for JBoss AS 7 is version JSF 2.0 and the application is using JSF 1.2. To resolve the mismatch, you must explicitly include the JSF 1.2 dependency and exclude the JSF 2.0 dependency.
To resolve this issue:
-
Find the JBoss module that contains the class named by the ClassNotFoundException. In this case, there are 2 modules for the javax.faces.api classes. The default module for JSF 2.0 is located in the EAP_HOME/modules/system/layers/base/javax/faces/api/main directory and a module for JSF 1.2 is located in the EAP_HOME/modules/system/layers/base/javax/faces/api/1.2 directory.
-
Explicitly define the dependency on the older JSF 1.2 version in the jboss-deployment-structure.xml file and exclude the default JSF 2.0 module as follows:
<jboss-deployment-structure xmlns="urn:jboss:deployment-structure:1.0">
<deployment>
<exclusions>
<module name="javax.faces.api" slot="main"/>
<module name="com.sun.jsf-impl" slot="main"/>
</exclusions>
<dependencies>
<module name="javax.faces.api" slot="1.2" export="true"/>
<module name="com.sun.jsf-impl" slot="1.2" export="true"/>
</dependencies>
</deployment>
</jboss-deployment-structure>
-
Search the application archives and remove any jsf-api JARs from the packaged application.