Spring Boot Webflux + Elastic APM Monitoring - spring

I am currently new to Elastic APM.
I am currently developing an application using spring-webflux and want to monitor my application using Elastic APM, but unfortunately, it's not working for me.
Dependecies
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.6.RELEASE</version>
</parent>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-test</artifactId>
<scope>test</scope>
</dependency>
APM Java Agent Version - 1.8.0
Elastic search - 7.2.0
APM server - 7.2.0
Exception observed -
2020-05-07 00:03:31.529 [main] INFO co.elastic.apm.agent.bci.bytebuddy.ErrorLoggingListener - org.springframework.web.context.support.GenericWebApplicationContext refers to a missing class
java.lang.IllegalStateException: Cannot resolve type description for javax.servlet.ServletContext
at co.elastic.apm.agent.shaded.bytebuddy.pool.TypePool$Resolution$Illegal.resolve(TypePool.java:159)
at co.elastic.apm.agent.shaded.bytebuddy.pool.TypePool$Default$LazyTypeDescription$TokenizedGenericType.toErasure(TypePool.java:6241)
at co.elastic.apm.agent.shaded.bytebuddy.pool.TypePool$Default$LazyTypeDescription$GenericTypeToken$Resolution$Raw$RawAnnotatedType.of(TypePool.java:3412)
at co.elastic.apm.agent.shaded.bytebuddy.pool.TypePool$Default$LazyTypeDescription$GenericTypeToken$Resolution$Raw.resolveReturnType(TypePool.java:3302)
at co.elastic.apm.agent.shaded.bytebuddy.pool.TypePool$Default$LazyTypeDescription$LazyMethodDescription.getReturnType(TypePool.java:6796)
at co.elastic.apm.agent.shaded.bytebuddy.description.method.MethodDescription$AbstractBase.asSignatureToken(MethodDescription.java:838)
at co.elastic.apm.agent.bci.bytebuddy.FailSafeDeclaredMethodsCompiler.compile(FailSafeDeclaredMethodsCompiler.java:85)
at co.elastic.apm.agent.bci.bytebuddy.FailSafeDeclaredMethodsCompiler.compile(FailSafeDeclaredMethodsCompiler.java:66)
at co.elastic.apm.agent.shaded.bytebuddy.dynamic.scaffold.MethodRegistry$Default.prepare(MethodRegistry.java:471)
at co.elastic.apm.agent.shaded.bytebuddy.dynamic.scaffold.inline.RedefinitionDynamicTypeBuilder.make(RedefinitionDynamicTypeBuilder.java:198)
at co.elastic.apm.agent.shaded.bytebuddy.agent.builder.AgentBuilder$Default$ExecutingTransformer.doTransform(AgentBuilder.java:10327)
at co.elastic.apm.agent.shaded.bytebuddy.agent.builder.AgentBuilder$Default$ExecutingTransformer.transform(AgentBuilder.java:10263)
at co.elastic.apm.agent.shaded.bytebuddy.agent.builder.AgentBuilder$Default$ExecutingTransformer.access$1600(AgentBuilder.java:10029)
at co.elastic.apm.agent.shaded.bytebuddy.agent.builder.AgentBuilder$Default$ExecutingTransformer$LegacyVmDispatcher.run(AgentBuilder.java:10648)
at co.elastic.apm.agent.shaded.bytebuddy.agent.builder.AgentBuilder$Default$ExecutingTransformer$LegacyVmDispatcher.run(AgentBuilder.java:10595)
at java.security.AccessController.doPrivileged(Native Method)
at co.elastic.apm.agent.shaded.bytebuddy.agent.builder.AgentBuilder$Default$ExecutingTransformer.transform(AgentBuilder.java:10186)
at sun.instrument.TransformerManager.transform(Unknown Source)
at sun.instrument.InstrumentationImpl.transform(Unknown Source)
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(Unknown Source)
at java.security.SecureClassLoader.defineClass(Unknown Source)
at java.net.URLClassLoader.defineClass(Unknown Source)
at java.net.URLClassLoader.access$100(Unknown Source)
at java.net.URLClassLoader$1.run(Unknown Source)
at java.net.URLClassLoader$1.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at org.springframework.boot.autoconfigure.condition.FilteringSpringBootCondition.resolve(FilteringSpringBootCondition.java:108)
at org.springframework.boot.autoconfigure.condition.FilteringSpringBootCondition$ClassNameFilter.isPresent(FilteringSpringBootCondition.java:140)
at org.springframework.boot.autoconfigure.condition.OnWebApplicationCondition.getOutcome(OnWebApplicationCondition.java:71)
at org.springframework.boot.autoconfigure.condition.OnWebApplicationCondition.getOutcomes(OnWebApplicationCondition.java:58)
at org.springframework.boot.autoconfigure.condition.FilteringSpringBootCondition.match(FilteringSpringBootCondition.java:49)
at org.springframework.boot.autoconfigure.AutoConfigurationImportSelector.filter(AutoConfigurationImportSelector.java:246)
at org.springframework.boot.autoconfigure.AutoConfigurationImportSelector.getAutoConfigurationEntry(AutoConfigurationImportSelector.java:121)
at org.springframework.boot.autoconfigure.AutoConfigurationImportSelector$AutoConfigurationGroup.process(AutoConfigurationImportSelector.java:396)
at org.springframework.context.annotation.ConfigurationClassParser$DeferredImportSelectorGrouping.getImports(ConfigurationClassParser.java:882)
at org.springframework.context.annotation.ConfigurationClassParser$DeferredImportSelectorGroupingHandler.processGroupImports(ConfigurationClassParser.java:808)
at org.springframework.context.annotation.ConfigurationClassParser$DeferredImportSelectorHandler.process(ConfigurationClassParser.java:779)
at org.springframework.context.annotation.ConfigurationClassParser.parse(ConfigurationClassParser.java:192)
at org.springframework.context.annotation.ConfigurationClassPostProcessor.processConfigBeanDefinitions(ConfigurationClassPostProcessor.java:319)
at org.springframework.context.annotation.ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry(ConfigurationClassPostProcessor.java:236)
at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanDefinitionRegistryPostProcessors(PostProcessorRegistrationDelegate.java:275)
at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:95)
at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:706)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:532)
at org.springframework.boot.web.reactive.context.ReactiveWebServerApplicationContext.refresh(ReactiveWebServerApplicationContext.java:66)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:747)
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:397)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:315)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1226)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1215)
at com.dhisco.hotel.search.HotelSearchApp.main(HotelSearchApp.java:14)
Could someone please suggest what I am missing ?

Elastic APM now supports Webflux (either Tomcat or Netty):
https://github.com/elastic/apm-agent-java/pull/1305
Since Elastic APM 1.25.0, this is enabled by setting enable_experimental_instrumentations to true, either in elasticapm.properties, or as JVM argument:
enable_experimental_instrumentations=true
Before this, it was enabled by setting disable_instrumentations to empty string:
disable_instrumentations=
https://github.com/elastic/apm-agent-java/issues/60#issuecomment-822419013
Features
Test application:
available as an executable jar and also used for unit-testing instrumentation
provides both functional and annotated controllers endpoints
executable with netty or tomcat as server, which allows to cover Webflux with or without Servlets
provides a client to call itself (based on Webflux client), thus using any third-party HTTP client is not necessary
Instrumentation:
Webflux server: covers both functional and annotated endpoints variants
Webflux client: not covered yet, see add support for Webflux client instrumentation #1306
using new plugin API and indy dispatcher.
adds reactor instrumentation for context-propagation

Looks like there is no support from elastic for WebFlux yet
Check here https://github.com/elastic/apm-agent-java/issues/60
They are currently working on it, but there is not a date to be ready yet

WebFlux can run on Servlet containers with support for the Servlet 3.1 Non-Blocking IO API as well as on other async runtimes such as Netty and Undertow.
Each Spring Boot web application includes an embedded web server.
For reactive stack applications, the spring-boot-starter-webflux includes Reactor Netty by default I guess. And it does not include Servlet API (Netty is non-Servlet runtime), but it looks like your Elastic APM expects this API to be present.
Try to use spring-boot-starter-tomcat instead of Netty. When switching to a different HTTP server, you need to exclude the default dependencies in addition to including the one you need.
Here is an example:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
<exclusions>
<!-- Exclude the Netty dependency -->
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-reactor-netty</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- Use Tomcat instead -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</dependency>
Tomcat dependency brings Servlet API. Perhaps it will resolve your issue.

Related

java.lang.ClassNotFoundException: io.netty.handler.logging.ByteBufFormat

I'm on integrating a third-party library into our application. For that I have added all the dependencies, however facing below error stack on application run.
Error stack-trace:
`
Caused by: java.lang.ClassNotFoundException: io.netty.handler.logging.ByteBufFormat
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:581)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)
... 31 common frames omitted
`
Maven dependencies:
`
<dependency>
<groupId>com.affinda.api</groupId>
<artifactId>affinda-api-client</artifactId>
<version>0.4.2</version>
</dependency>
<dependency>
<groupId>com.microsoft.rest</groupId>
<artifactId>client-runtime</artifactId>
<version>1.7.14</version>
</dependency>
<dependency>
<groupId>com.microsoft.azure</groupId>
<artifactId>azure-client-runtime</artifactId>
<version>1.7.14</version>
</dependency>
<dependency>
<groupId>com.microsoft.azure</groupId>
<artifactId>azure-client-authentication</artifactId>
<version>1.7.14</version>
</dependency>
<dependency>
<groupId>com.azure</groupId>
<artifactId>azure-identity</artifactId>
<version>1.5.0</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.84.Final</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-handler</artifactId>
<version>4.1.84.Final</version>
</dependency>
`
I did check that ByteBufFormat is in netty-handler library from the docs and did check the dependency tree but haven't got any clue.
It might be too late, however I had the same problem.
The cause is that another dependency is overriding the netty version in your final pom. In my case it was spring boot dependencies (2.2.0-RELEASE) which was overriding netty to version 4.1.42Final instead of needed 4.1.86Final.
If you want to check who is responsible, you can run maven with goal help:effective-pom and search for the effective netty version management owner.
In order to solve the issue you can just specify the netty version among maven properties:
<properties>
.
.
<netty.version>4.1.86.Final</netty.version>
</properties>
In this way you will put back the expected netty version and everything will work like a charm.
Be careful to check that the other library is still working as well.

Errors when running SpringBoot Admin app

I am trying to use Springboot admin app and am unable to get the basics working.
I started with the simplest springboot web app (using starter-web and starter-test) and added the springboot-admin-server and springboot-admin-server-ui to the list of dependencies.
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- Added Dependency for Admin Server and its UI -->
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-server</artifactId>
<version>1.4.5</version>
</dependency>
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-server-ui</artifactId>
<version>1.4.5</version>
</dependency>
</dependencies>
Trying to execute mvn clean package throws up errors. The root cause is shown below.
Caused by: java.lang.ClassNotFoundException: org.springframework.boot.context.embedded.ServletRegistrationBean
at java.net.URLClassLoader.findClass(URLClassLoader.java:381) ~[na:1.8.0_112]
at java.lang.ClassLoader.loadClass(ClassLoader.java:424) ~[na:1.8.0_112]
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331) ~[na:1.8.0_112]
at java.lang.ClassLoader.loadClass(ClassLoader.java:357) ~[na:1.8.0_112]
... 51 common frames omitted
The springboot app has absolutely the barebones implementation (the addition of the EnableAdminServer annotation as shown below)
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import de.codecentric.boot.admin.config.EnableAdminServer;
#SpringBootApplication
#EnableAdminServer
public class WorkingExampleSpringBootAdminApplication {
public static void main(String[] args) {
SpringApplication.run(WorkingExampleSpringBootAdminApplication.class, args);
}
}
I am guessing that this error occurs because this class (org.springframework.boot.context.embedded.ServletRegistrationBean) has been replaced with org.springframework.boot.web.servlet.ServletRegistrationBean (in 1.5.x)and this is likely used by the spring-boot-admin-server components.
I got around this issue by switching to an earlier version of Springboot (say 1.4.4). Is that the right thing to do? Or am I making any mistakes in my configuration?
Using the version 1.4.6 of spring-boot-admin-server and spring-boot-admin-server-ui instead of 1.4.5 fixes the issue.

Spring Boot Servlet API Version

I'm trying to run a Spring Boot app on Tomcat 7. From my understanding, it should be compatible with servlet 3.0 spec.
In my dependency, I mark tomcat as provided:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope> <!-- Mark as provided so it doesn't interfere when we deploy in container -->
</dependency>
Edit: And I've added the property <tomcat.version>7.0.59</tomcat.version>
But I still can't start it in tomcat. I'm getting this error:
Caused by: java.lang.NoSuchMethodError: javax.servlet.ServletContext.getVirtualServerName()Ljava/lang/String;
at org.apache.tomcat.websocket.server.WsServerContainer.(WsServerContainer.java:147)
at org.apache.tomcat.websocket.server.WsSci.init(WsSci.java:131)
at org.apache.tomcat.websocket.server.WsSci.onStartup(WsSci.java:47)
Which are because it apparently needs servlet spec 3.1.
Am I missing something?
The problem is, spring-boot also configure websocket support on spring-boot-starter-tomcat, which is includes by spring-boot-starter-web. And according to Apache, you must use Java 7 if you want web socket with Tomcat 7.
Here: http://tomcat.apache.org/whichversion.html
Either compile with Java 7 or exclude websocket support
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-websocket</artifactId>
</exclusion>
</exclusions>
</dependency>

Adding spring-boot-starter-security to Spring Boot application causes error 'entityManagerFactory' or 'persistenceUnitName' is required

I created a Spring Boot (0.5.0.BUILD-SNAPSHOT) application using Spring Initializr (http://start.spring.io/), and I added a single #RestController, a single CrudRepository interface, and a single #Entity class - nothing complicated. My Maven POM contains the following dependencies:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
</dependency>
The Application class contains the default:
#ComponentScan
#EnableAutoConfiguration
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
The simple application runs without errors, but I decided to add Spring Security to the POM to secure the management endpoints:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
Now the application won't start, and I get the following:
java.lang.IllegalArgumentException: 'entityManagerFactory' or 'persistenceUnitName' is required
Caused by: java.lang.IllegalArgumentException: 'entityManagerFactory' or 'persistenceUnitName' is required
at org.springframework.orm.jpa.JpaTransactionManager.afterPropertiesSet(JpaTransactionManager.java:304)
at org.springframework.orm.jpa.JpaTransactionManager.<init>(JpaTransactionManager.java:141)
at org.springframework.boot.autoconfigure.orm.jpa.JpaBaseConfiguration.transactionManager(JpaBaseConfiguration.java:68)
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.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:166)
... 18 more
When I remove the spring-boot-starter-security dependency, the application runs fine but without security enabled. What does the error mean? The application already uses JPA and Hibernate without Spring Security enabled.
There is a bug there. The cause is really deeply technical and related to the internals in a Spring BeanFactory. Look at the Github issue if you want to get some more understanding, but probably you should be able to just refresh your snapshot dependencies and get the fix.

How to properly install and configure JSF libraries via Maven?

I'm trying to deploy a JSF based application to Tomcat 6. The way my build system is setup, the WAR itself doesn't have any libraries in it, because this server is serving a total of 43 apps. Instead, the libraries are copied into a shared library folder and shared among the apps. When I deploy, I get this 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)
Now in my research, I see that this is supposed to be solved by downloading the JSF source code and compiling it myself. That is a horrible solution in my case. That will cause huge problems on my team with the various configurations we have to contend with. Is there another fix for this?
Here is my 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>
There has got to be a solution here. I can't for a second believe that the Maven distributable for JSF is only good for compiling and not good for deployment.
When you're facing a "weird" exception suggesting that classes/methods/files/components/tags are absent or different while they are seemingly explicitly included in the web application such as the ones below,
java.lang.ClassFormatError: Absent Code attribute in method that is not native or abstract in class file javax/faces/webapp/FacesServlet
java.util.MissingResourceException: Can't find javax.faces.LogStrings bundle
com.sun.faces.vendor.WebContainerInjectionProvider cannot be cast to com.sun.faces.spi.InjectionProvider
com.sun.faces.config.ConfigurationException: CONFIGURATION FAILED
The tag named inputFile from namespace http://xmlns.jcp.org/jsf/html has a null handler-class defined.
java.lang.NullPointerException at javax.faces.CurrentThreadToServletContext.getFallbackFactory
java.lang.AbstractMethodError at javax.faces.application.ViewHandlerWrapper.getWebsocketURL
java.lang.NullPointerException at com.sun.faces.config.InitFacesContext.cleanupInitMaps
or when you're facing "weird" runtime behavior such as broken HTTP sessions (jsessionid appears in link URLs over all place), and/or broken Faces view scope (it behaves as request scoped), and/or broken CSS/JS/image resources, then the chance is big that the webapp's runtime classpath is polluted with duplicate different versioned JAR files.
In your specific case with the ClassFormatError on the FacesServlet, it means that the JAR file containing the mentioned class has been found for the first time is actually a "blueprint" API JAR file, intented for implementation vendors (such as developers working for Mojarra and MyFaces). It contains class files with only class and method signatures, without any code bodies and resource files. That's exactly what "absent code attribute" means. It's purely intented for javadocs and compilation.
Always mark server-provided libraries as provided
All dependencies marked "Java Specifications" in Maven and having -api suffix in the artifact ID are those blueprint APIs. You should absolutely not have them in the runtime classpath. You should always mark them <scope>provided</scope> if you really need to have it in your pom. A well known example is the Jakarta EE (Web) API (formerly known as 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>
If the provided scope is absent, then this JAR will end up in webapp's /WEB-INF/lib, causing all trouble you're facing now. This JAR also contains the blueprint class of FacesServlet.
In your specific case, you have an unnecessary Faces API dependency:
<dependency>
<groupId>jakarta.faces</groupId>
<artifactId>jakarta.faces-api</artifactId>
</dependency>
This is causing trouble because this contains the blueprint class of FacesServlet. Removing it and relying on a provided Jakarta EE (Web) API as shown above should solve it.
Tomcat as being a barebones JSP/Servlet container already provides JSP, Servlet and EL (and since 8 also WebSocket) out the box. So you should mark at least jsp-api, servlet-api, and el-api as provided. Tomcat only doesn't provide Faces (and JSTL) out the box. So you'd need to install it via the webapp.
Full fledged Jakarta EE servers such as WildFly, TomEE, GlassFish, Payara, WebSphere, etc already provide the entire Jakarta EE API out the box, including Faces. So you do absolutely not need to install Faces via the webapp. It would only result in conflicts if the server already provides a different implementation and/or version out the box. The only dependency you need is the jakartaee-api exactly as shown here above.
See also How to properly configure Jakarta EE libraries in Maven pom.xml for Tomcat? for more elaborate explanation and examples of pom.xml for Tomcat 10 and 9.
Installing Faces on Tomcat 10 or newer
Tomcat 10.0.x is the first version using jakarta.* package instead of javax.* package. You'll for Tomcat 10.0.x thus need a minimum of Faces 3.0 instead of 2.3 because the javax.* package has been renamed to jakarta.* since Faces 3.0 only. In case you have Tomcat 10.1.x, then you need a minimum Faces version of 4.0.
There are two Faces implementations: Mojarra and MyFaces. You should choose to install one of them and thus not both.
Installing Mojarra 3.0 on Tomcat 10 or newer:
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>jakarta.faces</artifactId>
<version><!-- Check https://eclipse-ee4j.github.io/mojarra --></version>
</dependency>
You can also check org.glassfish:jakarta.faces repository for current latest 3.0.x release version (which is currently 3.0.3). See also Mojarra installation instructions for other necessary dependencies (CDI, BV, JSONP).
Installing MyFaces 3.0 on Tomcat 10 or newer:
<dependency>
<groupId>org.apache.myfaces.core</groupId>
<artifactId>myfaces-impl</artifactId>
<version><!-- Check http://myfaces.apache.org --></version>
</dependency>
You can also check org.apache.myfaces.core:myfaces-impl repository for current latest 3.0.x release version (which is currently 3.0.2).
Don't forget to install JSTL API along, by the way. This is also absent in Tomcat.
<dependency>
<groupId>jakarta.servlet.jsp.jstl</groupId>
<artifactId>jakarta.servlet.jsp.jstl-api</artifactId>
<version>2.0.0</version>
</dependency>
Also note that since Faces 2.3, CDI has become a required dependency. This is available out the box in normal Jakarta EE servers but not on servletcontainers such as Tomcat. In this case head to How to install and use CDI on Tomcat?
Installing Faces on Tomcat 9 or older
You can only use at maximum Faces 2.3 on Tomcat 9 or older because it is the latest version still using javax.* package.
Installing Mojarra 2.3 on Tomcat 9 or older:
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>jakarta.faces</artifactId>
<version><!-- Check https://eclipse-ee4j.github.io/mojarra --></version>
</dependency>
You can also check org.glassfish:jakarta.faces repository for current latest 2.3.x release version (which is currently 2.3.18). See also Mojarra installation instructions for other necessary dependencies (CDI, BV, JSONP).
Installing MyFaces 2.3 on Tomcat 9 or older:
<dependency>
<groupId>org.apache.myfaces.core</groupId>
<artifactId>myfaces-impl</artifactId>
<version><!-- Check http://myfaces.apache.org --></version>
</dependency>
You can also check org.apache.myfaces.core:myfaces-impl repository for current latest 2.3.x release version (which is currently 2.3.9).
Note that Tomcat 6 as being Servlet 2.5 container supports at maximum Faces 2.1.
Don't forget to install JSTL API along, by the way. This is also absent in Tomcat.
<dependency>
<groupId>jakarta.servlet.jsp.jstl</groupId>
<artifactId>jakarta.servlet.jsp.jstl-api</artifactId>
<version>1.2.7</version>
</dependency>
Also note that since Faces 2.3, CDI has become a required dependency. This is available out the box in normal Jakarta EE servers but not on servletcontainers such as Tomcat. In this case head to How to install and use CDI on Tomcat?
See also:
What exactly is Java EE / Jakarta EE?
How to install JSTL on Tomcat via Maven?
How to install CDI on Tomcat via Maven?
FacesServlet returns blank/unparsed page

Resources