¿Cómo instalar y configurar correctamente las bibliotecas JSF a través de Maven?
Estoy intentando implementar una aplicación basada en JSF en Tomcat 6. Por la forma en que está configurado mi sistema de compilación, WAR en sí no tiene bibliotecas, porque este servidor sirve un total de 43 aplicaciones. En cambio, las bibliotecas se copian en una carpeta de biblioteca compartida y se comparten entre las aplicaciones. Cuando lo implemento, aparece este error
SEVERE: Error deploying configuration descriptor SSOAdmin.xml
java.lang.ClassFormatError: Absent Code attribute in method that is not native or abstract in class file javax/faces/webapp/FacesServlet
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClassCond(ClassLoader.java:631)
at java.lang.ClassLoader.defineClass(ClassLoader.java:615)
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:141)
at java.net.URLClassLoader.defineClass(URLClassLoader.java:283)
at java.net.URLClassLoader.access$000(URLClassLoader.java:58)
at java.net.URLClassLoader$1.run(URLClassLoader.java:197)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1667)
at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1526)
at org.apache.catalina.startup.WebAnnotationSet.loadApplicationServletAnnotations(WebAnnotationSet.java:108)
at org.apache.catalina.startup.WebAnnotationSet.loadApplicationAnnotations(WebAnnotationSet.java:58)
at org.apache.catalina.startup.ContextConfig.applicationAnnotationsConfig(ContextConfig.java:297)
at org.apache.catalina.startup.ContextConfig.start(ContextConfig.java:1078)
at org.apache.catalina.startup.ContextConfig.lifecycleEvent(ContextConfig.java:261)
at org.apache.catalina.util.LifecycleSupport.fireLifecycleEvent(LifecycleSupport.java:142)
at org.apache.catalina.core.StandardContext.start(StandardContext.java:4611)
at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:799)
at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:779)
at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:601)
at org.apache.catalina.startup.HostConfig.deployDescriptor(HostConfig.java:675)
at org.apache.catalina.startup.HostConfig.deployDescriptors(HostConfig.java:601)
at org.apache.catalina.startup.HostConfig.deployApps(HostConfig.java:502)
at org.apache.catalina.startup.HostConfig.start(HostConfig.java:1315)
at org.apache.catalina.startup.HostConfig.lifecycleEvent(HostConfig.java:324)
at org.apache.catalina.util.LifecycleSupport.fireLifecycleEvent(LifecycleSupport.java:142)
at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1061)
at org.apache.catalina.core.StandardHost.start(StandardHost.java:840)
at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1053)
at org.apache.catalina.core.StandardEngine.start(StandardEngine.java:463)
at org.apache.catalina.core.StandardService.start(StandardService.java:525)
at org.apache.catalina.core.StandardServer.start(StandardServer.java:754)
at org.apache.catalina.startup.Catalina.start(Catalina.java:595)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:289)
at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:414)
Ahora, en mi investigación, veo que se supone que esto se resuelve descargando el código fuente JSF y compilándolo yo mismo. Esa es una solución horrible en mi caso. Eso causará grandes problemas en mi equipo con las diversas configuraciones con las que tendremos que lidiar. ¿Existe otra solución para esto?
Aquí está mi pom.xml
:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.nms.sso</groupId>
<artifactId>SSOAdmin</artifactId>
<version>09142011-BETA</version>
<packaging>war</packaging>
<dependencies>
<dependency>
<groupId>asm</groupId>
<artifactId>asm</artifactId>
<scope>${myExeScope}</scope>
</dependency>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<scope>${myExeScope}</scope>
</dependency>
<!-- <dependency> -->
<!-- <groupId>com.sun.faces</groupId> -->
<!-- <artifactId>jsf-api</artifactId> -->
<!-- <scope>${myExeScope}</scope> -->
<!-- </dependency> -->
<!-- <dependency> -->
<!-- <groupId>com.sun.faces</groupId> -->
<!-- <artifactId>jsf-impl</artifactId> -->
<!-- <scope>${myExeScope}</scope> -->
<!-- </dependency> -->
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<scope>${myExeScope}</scope>
</dependency>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
<version>6.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.faces</groupId>
<artifactId>javax.faces-api</artifactId>
<scope>${myExeScope}</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>${myExeScope}</scope>
</dependency>
<dependency>
<groupId>net.sf.jt400</groupId>
<artifactId>jt400</artifactId>
<scope>${myExeScope}</scope>
</dependency>
<dependency>
<groupId>nmsc</groupId>
<artifactId>nmsc_api</artifactId>
<version>09142011-BETA</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<scope>${myExeScope}</scope>
</dependency>
<dependency>
<groupId>org.icefaces</groupId>
<artifactId>icefaces</artifactId>
<scope>${myExeScope}</scope>
</dependency>
<dependency>
<groupId>org.icefaces</groupId>
<artifactId>icefaces-ace</artifactId>
<scope>${myExeScope}</scope>
</dependency>
<dependency>
<groupId>org.icefaces</groupId>
<artifactId>icefaces-compat</artifactId>
<scope>${myExeScope}</scope>
</dependency>
<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
<scope>${myExeScope}</scope>
</dependency>
<dependency>
<groupId>org.jibx</groupId>
<artifactId>jibx-extras</artifactId>
<scope>${myExeScope}</scope>
</dependency>
<dependency>
<groupId>org.jibx</groupId>
<artifactId>jibx-run</artifactId>
<scope>${myExeScope}</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<scope>${myExeScope}</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<scope>${myExeScope}</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<scope>${myExeScope}</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<scope>${myExeScope}</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<scope>${myExeScope}</scope>
</dependency>
<dependency>
<groupId>postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>${myExeScope}</scope>
</dependency>
</dependencies>
<parent>
<groupId>nmsc</groupId>
<artifactId>nmsc_lib</artifactId>
<version>0.0.1-SNAPSHOT</version>
<relativePath>../libs</relativePath>
</parent>
<build>
<finalName>SSOAdmin</finalName>
</build>
<name>SSOAdmin Maven Webapp</name>
</project>
Tiene que haber una solución aquí. No puedo creer ni por un segundo que Maven distribuible para JSF solo sea bueno para compilar y no para implementación.
Cuando se enfrenta a una excepción "extraña" que sugiere que las clases/métodos/archivos/componentes/etiquetas están ausentes o son diferentes mientras aparentemente están incluidos explícitamente en la aplicación web, como las que se muestran a continuación,
java.lang.ClassFormatError: atributo de código ausente en un método que no es nativo ni abstracto en el archivo de clase javax/faces/webapp/FacesServlet
java.util.MissingResourceException: no se puede encontrar el paquete javax.faces.LogStrings
com.sun.faces.vendor.WebContainerInjectionProvider no se puede transmitir a com.sun.faces.spi.InjectionProvider
com.sun.faces.config.ConfigurationException: FALLÓ LA CONFIGURACIÓN
La etiqueta denominada inputFile del espacio de nombres http://xmlns.jcp.org/jsf/html tiene una clase de controlador nula definida.
java.lang.NullPointerException en javax.faces.CurrentThreadToServletContext.getFallbackFactory
java.lang.AbstractMethodError en javax.faces.application.ViewHandlerWrapper.getWebsocketURL
java.lang.NullPointerException en com.sun.faces.config.InitFacesContext.cleanupInitMaps
o cuando se enfrenta a un comportamiento de tiempo de ejecución "extraño", como sesiones HTTP rotas ( jsessionid
aparecen en las URL de los enlaces en todas partes) y/o alcance de vista de Caras roto (se comporta como un alcance de solicitud) y/o CSS/JS/imagen roto recursos, entonces existe una gran posibilidad de que el classpath de tiempo de ejecución de la aplicación web esté contaminado con archivos JAR duplicados con diferentes versiones.
En su caso específico con el ClassFormatError
en FacesServlet
, significa que el archivo JAR que contiene la clase mencionada se encontró por primera vez es en realidad un archivo JAR API "modelo", destinado a proveedores de implementación (como desarrolladores que trabajan para Mojarra y MyFaces) . Contiene archivos de clase con firmas de clases y métodos únicamente, sin cuerpos de código ni archivos de recursos. Eso es exactamente lo que significa "atributo de código ausente". Está destinado exclusivamente a javadocs y compilación.
Marque siempre las bibliotecas proporcionadas por el servidor comoprovided
Todas las dependencias marcadas como " Especificaciones de Java " en Maven y que tienen -api
un sufijo en el ID del artefacto son esas API de modelo. No deberías tenerlos en absoluto en el classpath del tiempo de ejecución. Siempre debes marcarlos <scope>provided</scope>
si realmente necesitas tenerlo en tu pompón. Un ejemplo bien conocido es la API Jakarta EE (Web) (anteriormente conocida como Java EE):
<dependency>
<groupId>jakarta.platform</groupId>
<artifactId>jakarta.jakartaee-api</artifactId>
<version><!-- 8.0.0 or 9.0.0 or 9.1.0 or 10.0.0 or newer --></version>
<scope>provided</scope>
</dependency>
Si el provided
alcance está ausente, entonces este JAR terminará en la aplicación web /WEB-INF/lib
, causando todos los problemas que enfrenta ahora. Este JAR también contiene la clase de modelo de FacesServlet
.
En su caso específico, tiene una dependencia innecesaria de Faces API :
<dependency>
<groupId>jakarta.faces</groupId>
<artifactId>jakarta.faces-api</artifactId>
</dependency>
Esto está causando problemas porque contiene la clase de modelo de FacesServlet
. Eliminarlo y confiar en una provided
API Jakarta EE (Web) como se muestra arriba debería resolverlo.
Tomcat, como contenedor JSP/Servlet básico, ya proporciona JSP, Servlet y EL (y desde 8 también WebSocket) listos para usar. Por lo tanto, debes marcar al menos jsp-api
, servlet-api
y el-api
como provided
. Tomcat solo no proporciona Faces (ni JSTL ) listos para usar. Entonces necesitarás instalarlo a través de la aplicación web.
Los servidores completos de Jakarta EE, como WildFly, TomEE, GlassFish, Payara, WebSphere, etc., ya proporcionan toda la API de Jakarta EE lista para usar, incluido Faces. Por lo tanto, no es necesario instalar Faces a través de la aplicación web. Solo resultaría en conflictos si el servidor ya proporciona una implementación y/o versión diferente lista para usar. La única dependencia que necesita es jakartaee-api
exactamente como se muestra aquí arriba.
Consulte también ¿Cómo configurar correctamente las bibliotecas Jakarta EE en Maven pom.xml para Tomcat? para obtener explicaciones más detalladas y ejemplos de pom.xml
Tomcat 10 y 9.
Instalación de Faces en Tomcat 10 o posterior
Tomcat 10.0.x es la primera versión que utiliza jakarta.*
paquete en lugar de javax.*
paquete. Por lo tanto, para Tomcat 10.0.x necesitará un mínimo de Faces 3.0 en lugar de 2.3 porque el javax.*
nombre del paquete se cambió a jakarta.*
Faces 3.0 únicamente. En caso de que tenga Tomcat 10.1.x, necesitará una versión mínima de Faces 4.0.
Hay dos implementaciones de Faces: Mojarra y MyFaces . Deberías optar por instalar uno de ellos y, por tanto, no ambos.
Instalación de Mojarra 3.0 o 4.0 en Tomcat 10 o posterior:
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>jakarta.faces</artifactId>
<version><!-- Check https://eclipse-ee4j.github.io/mojarra --></version>
</dependency>
También puede consultar org.glassfish:jakarta.faces
el repositorio para conocer la última versión actual 3.0.x o 4.0.x (que actualmente es 3.0.5
y 4.0.3
). Consulte también las instrucciones de instalación de Mojarra para otras dependencias necesarias (CDI, BV, JSONP).
Instalación de MyFaces 3.0 o 4.0 en Tomcat 10 o posterior:
<dependency>
<groupId>org.apache.myfaces.core</groupId>
<artifactId>myfaces-impl</artifactId>
<version><!-- Check http://myfaces.apache.org --></version>
</dependency>
También puede consultar org.apache.myfaces.core:myfaces-impl
el repositorio para conocer la última versión actual 3.0.x o 4.0.x (que actualmente es 3.0.2
y 4.0.1
).
Por cierto, no olvides instalar al menos la API JSTL. Esto también está ausente en Tomcat.
<dependency>
<groupId>jakarta.servlet.jsp.jstl</groupId>
<artifactId>jakarta.servlet.jsp.jstl-api</artifactId>
<version><!-- 2.0.0 or 3.0.0 --></version>
</dependency>
No, no necesariamente necesita la implementación JSTL como se indica en ¿ Cómo instalar JSTL? El uri absoluto: http://java.sun.com/jstl/core no se puede resolver . Esto sólo es necesario cuando también desea utilizar JSTL en archivos JSP. Facelets tiene su propia implementación JSTL incorporada. En caso de que desee utilizar Facelets y JSP, elimine la dependencia de la API JSTL e instale la implementación JSTL como se indica en el enlace mencionado anteriormente.
También tenga en cuenta que desde Faces 2.3, CDI se ha convertido en una dependencia obligatoria. Esto está disponible de fábrica en servidores normales de Yakarta EE, pero no en contenedores de servlet como Tomcat. En este caso, diríjase a ¿Cómo instalar y usar CDI en Tomcat?
Para ser claros, después de haber instalado la implementación de Faces Mojarra o MyFaces, no es necesario declarar la jakarta.faces-api
dependencia por separado. Esto ya está incluido transitivamente a través de la implementación.
Instalación de Faces en Tomcat 9 o anterior
Solo puede usar como máximo Faces 2.3 en Tomcat 9 o anterior porque es la última versión que todavía usa javax.*
el paquete.
Instalación de Mojarra 2.3 en Tomcat 9 o anterior:
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>jakarta.faces</artifactId>
<version><!-- Check https://eclipse-ee4j.github.io/mojarra --></version>
</dependency>
También puede consultar org.glassfish:jakarta.faces
el repositorio para conocer la última versión 2.3.x actual (que actualmente es 2.3.20
). Consulte también las instrucciones de instalación de Mojarra para otras dependencias necesarias (CDI, BV, JSONP).
Instalación de MyFaces 2.3 en Tomcat 9 o anterior:
<dependency>
<groupId>org.apache.myfaces.core</groupId>
<artifactId>myfaces-impl</artifactId>
<version><!-- Check http://myfaces.apache.org --></version>
</dependency>
También puede consultar org.apache.myfaces.core:myfaces-impl
el repositorio para conocer la última versión 2.3.x actual (que actualmente es 2.3.10
).
Tenga en cuenta que Tomcat 6, como contenedor de Servlet 2.5, admite como máximo Faces 2.1.
Por cierto, no olvides instalar la API JSTL. Esto también está ausente en Tomcat.
<dependency>
<groupId>jakarta.servlet.jsp.jstl</groupId>
<artifactId>jakarta.servlet.jsp.jstl-api</artifactId>
<version>1.2.7</version>
</dependency>
También tenga en cuenta que desde Faces 2.3, CDI se ha convertido en una dependencia obligatoria. Esto está disponible de fábrica en servidores normales de Yakarta EE, pero no en contenedores de servlet como Tomcat. En este caso, diríjase a ¿Cómo instalar y usar CDI en Tomcat?
Ver también:
- ¿Qué es exactamente Java EE/Jakarta EE?
- ¿Cómo instalar JSTL en Tomcat a través de Maven?
- ¿Cómo instalar CDI en Tomcat a través de Maven?
- FacesServlet devuelve una página en blanco/sin analizar