'Jersey compatibility with log4j2 - failing to start servlets

I'm having issues getting Jersey 1.19 to work with log4j2 on Tomcat7. My project's working assembly against log4j1 consists of the following:

  • slf4j-api: 1.5.6
  • slf4j-log4j12: 1.5.6
  • log4j: 1.2.14

I have a test project using log4j2 working successfully (logs are written to a file) with the following:

  • slf4j-api: 1.5.6
  • slf4j-log4j12: 1.5.6
  • log4j-1.2-api: 2.11.0
  • log4j-api: 2.11.0
  • log4j-core: 2.11.0

I am including log4j-1.2-api and the slf4j-log4j12 for the 'bridge' between log4j 1 and 2 per documentation, as there is legacy code I am unable to touch that uses log4j1.

As soon as I remove log4j 1.2.14 from my real project's assembly, and add in the bridge (log4j-1.2-api) and the api and core for log4j2, I run into the following exception when the the first HTTP request hits the server after startup. Reverting back to log4j1 resolves the issue.

My log4j2.xml file (which works on the test project) is located in the servlets /WEB-INF/classes folder. I've also tried it in the /WEB-INF folder.

asm.jar is 3.3.1 if that matters - I see it in the stacktrace.

Is there a compatibility issue I haven't read about getting these to play together?

java.lang.IllegalArgumentException
    jersey.repackaged.org.objectweb.asm.ClassReader.<init>(ClassReader.java:170)
    jersey.repackaged.org.objectweb.asm.ClassReader.<init>(ClassReader.java:153)
    jersey.repackaged.org.objectweb.asm.ClassReader.<init>(ClassReader.java:424)
    com.sun.jersey.spi.scanning.AnnotationScannerListener.onProcess(AnnotationScannerListener.java:138)
    com.sun.jersey.core.spi.scanning.JarFileScanner.scan(JarFileScanner.java:97)
    com.sun.jersey.spi.scanning.servlet.WebAppResourcesScanner$1.f(WebAppResourcesScanner.java:94)
    com.sun.jersey.core.util.Closing.f(Closing.java:71)
    com.sun.jersey.spi.scanning.servlet.WebAppResourcesScanner.scan(WebAppResourcesScanner.java:92)
    com.sun.jersey.spi.scanning.servlet.WebAppResourcesScanner.scan(WebAppResourcesScanner.java:79)
    com.sun.jersey.api.core.ScanningResourceConfig.init(ScanningResourceConfig.java:80)
    com.sun.jersey.api.core.servlet.WebAppResourceConfig.init(WebAppResourceConfig.java:102)
    com.sun.jersey.api.core.servlet.WebAppResourceConfig.<init>(WebAppResourceConfig.java:89)
    com.sun.jersey.api.core.servlet.WebAppResourceConfig.<init>(WebAppResourceConfig.java:74)
    com.sun.jersey.spi.container.servlet.WebComponent.getWebAppResourceConfig(WebComponent.java:668)
    com.sun.jersey.spi.container.servlet.ServletContainer.getDefaultResourceConfig(ServletContainer.java:435)
    com.sun.jersey.spi.container.servlet.ServletContainer.getDefaultResourceConfig(ServletContainer.java:602)
    com.sun.jersey.spi.container.servlet.WebServletConfig.getDefaultResourceConfig(WebServletConfig.java:87)
    com.sun.jersey.spi.container.servlet.WebComponent.createResourceConfig(WebComponent.java:699)
    com.sun.jersey.spi.container.servlet.WebComponent.createResourceConfig(WebComponent.java:674)
    com.sun.jersey.spi.container.servlet.WebComponent.init(WebComponent.java:205)
    com.sun.jersey.spi.container.servlet.ServletContainer.init(ServletContainer.java:394)
    com.sun.jersey.spi.container.servlet.ServletContainer.init(ServletContainer.java:577)
    javax.servlet.GenericServlet.init(GenericServlet.java:158)
    org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:506)
    org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103)
    org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:962)
    org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:445)
    org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1115)
    org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:637)
    org.apache.tomcat.util.net.AprEndpoint$SocketProcessor.doRun(AprEndpoint.java:2549)
    org.apache.tomcat.util.net.AprEndpoint$SocketProcessor.run(AprEndpoint.java:2538)
    java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    java.lang.Thread.run(Thread.java:748)


Solution 1:[1]

Remark: although this is an old question, even today there are some application using Jersey 1.19.x. Due to security problems they should upgrade to Log4j2 version 2.12.4 immediately if the run on Java 7 (which is itself a security risk) or the latest version if they run on Java 8+ (2.17.2 at the moment of writing). Since Jersey 1.19.x has no known security problems, its upgrade can be performed at a later time.

You have the same problem as in LOG4J2-3445: Log4j2 artifacts are multi-release, which means that most of the classes are compiled with Java 8 (supported by your old Jersey release), but some (in /META-INF/versions/9) are compiled with Java 9. The class scanner included in your Jersey version can not parse them.

You can try multiple workarounds:

  1. Let Tomcat scan the classes instead of Jersey. This is available since Servlet 3.0 (Tomcat 7). To enable container annotation scanning in Jersey declare your servlet without a <servlet-class> parameter and a <servlet-name> equal to javax.ws.rs.core.Application:
    <servlet>
        <servlet-name>javax.ws.rs.core.Application</servlet-name>
    </servlet>
    
    This should also save up some startup time, since multiple Java EE technologies can profit of a single class scan.
  2. If the workaround above does not solve your problem, you can restrict the paths scanned by Jersey using the com.sun.jersey.config.property.classpath servlet parameter (cf. javadoc). A setting of "/WEB-INF/classes" should be enough for most purposes.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1