Spring Boot with Jetty: disable o.a.tomcat.util.scan.StandardJarScanner - spring-boot

I use Spring Boot with Jetty and JSP/JSTL:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>apache-jsp</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>apache-jstl</artifactId>
</dependency>
During startup, I get a number of warnings like:
WARN 18439 --- [ main] o.a.tomcat.util.scan.StandardJarScanner : Failed to scan [file:/home/user/.m2/repository/.../guava.jar] from classloader hierarchy
There are spurious jars in these warnings. Why tomcat scans anything if it is absent from the configuration files and it is Jetty which runs? Is the scan needed for e.g. JSP/JSTL? Can it be disabled? I can't use this because no Tomcat libraries are available in the application.
EDIT: Tomcat (?) sources are apparently called by Jasper, used in turn by Jetty. Thus, I put this into pom.xml in order to disable Jar scanning by Jetty:
<plugin>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<configuration>
<webApp>
<!-- no need to scan anything as we're using servlet 2.5 and moreover, we're not using Servl
<!-- for more relevant information regarding scanning of classes refer to https://java.net/j
<webInfIncludeJarPattern>^$</webInfIncludeJarPattern>
<containerIncludeJarPattern>^$</containerIncludeJarPattern>
<!--<webInfIncludeJarPattern>.*/spring-[^/]*\.jar$|.*/.*jsp-api-[^/]\.jar$|./.*jsp-[^/]\.jar
</webApp>
</configuration>
</plugin>
but it did not have any effect.

Your org.apache.tomcat.util.scan.StandardJarScanner is coming from the apache-jsp-<ver>.jar on the classpath.
Apache Jasper JSP needs to scan your classpath for TLDs when it does the JSPC steps.
Since you are using spring-boot, there's no real separation of WebAppClassLoader and SystemClassLoader, so it's forced to scan the entire classloader hierarchy to find those TLDs.
This scan is independent of Jetty, so that means the webInfIncludeJarPattern and containerIncludeJarPattern configurations will have no impact.
The best advice here is to precompile your JSP's with jspc during build-time and just have the runtime Jasper JSP never have the need to kick off JSPC and it's associated TLD scan.
If you still want runtime JSPC, consider setting the following property at Server startup, before your Context has started to initialize.
System.setProperty(
org.apache.tomcat.util.scan.Constants.SKIP_JARS_PROPERTY,
"*.jar");
That will tell the StandardJarScanFilter to skip all files ending in .jar.
Note that there is also a Constants.SCAN_JARS_PROPERTY which you get to specify specific jars to scan. (I don't know if this property supports globs, or relative references)

Related

How to bundle custom NiFi processor which uses multiple bundles?

I have written one Custom NiFi processor which uses some Hadoop classes, processes flow files and serializes flow files to and from Avro.
As per my knowledge
to use Hadoop classes without packaging them as part of NAR I will need nifi-hadoop-nar bundle AND
to serialize flow file contents to/from Avro, I will need RecordSetWriter and reader which are part of record-serialization-services-api.
Please correct me if my assumption is wrong.
I have written code, tested it and everything works as expected until I try to deploy NAR to NiFi.
When I deploy NAR and restart NiFi, it throws java.lang.ClassNotFoundException: org.apache.nifi.serialization.RecordSetWriterFactory exception.
My NAR's pom.xml looks like below:
<dependencies>
<dependency>
<groupId>com.my_company.is.data.tools</groupId>
<artifactId>custom-data-movement-processors</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.apache.nifi</groupId>
<artifactId>nifi-hadoop-nar</artifactId>
<version>1.5.0</version>
<type>nar</type>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.nifi</groupId>
<artifactId>nifi-record-serialization-service-api</artifactId>
<version>1.5.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
and processor's pom.xml file looks like below:
<dependencies>
<dependency>
<groupId>org.apache.nifi</groupId>
<artifactId>nifi-record-serialization-services</artifactId>
<version>1.5.0</version>
<scope>provided</scope>
<dependency>
<dependency>
<groupId>org.apache.nifi</groupId>
<artifactId>nifi-record-serialization-services-api</artifactId>
<version>1.5.0</version>
<scope>provided</scope>
<dependency>
</dependencies>
Since I have marked nifi-record-serialization-services-api as provided, it doesn't get bundled in resulting NAR file.
Now I can do a quick fix and remove scope altogether and create NAR BUT then NiFi complains about next class not found error.
I would like to know:
In NiFi project's code I found multiple nested bundles which have relation something like this nifi-nar-bundles -> nifi--bundle -> . How to refer two bundles in my processor? As per my knowledge custom processor can have only one parent NAR and NAR = bundle?
What is the preferred way to specify multiple NiFi bundles in pom.xml
Ideally I do not want to bundle Hadoop related dependencies or NiFi dependencies in my NAR file. or is it mandetory in NiFi to bundle these dependencies?
<packaging>nar</packaging>
<dependencies>
<dependency>
<groupId>org.apache.nifi</groupId>
<artifactId>nifi-hadoop-nar</artifactId>
<version>1.5.0</version>
<type>nar</type>
</dependency>
should be enough to get in resulted nar META-INF\MANIFEST.MF
attributes Nar-Dependency-*
Nar-Dependency-Id: nifi-hadoop-nar
Nar-Dependency-Group: org.apache.nifi
Nar-Dependency-Version: 1.5.0

Spring boot 2.1.7 having tomcat-embed-core conflit

I am migrating existing Spring project into Spring boot.unable to run spring boot application its showing following error.
The error log says there is a conflict on tomcat-embed-core.
In eclipse Dependency hierarchy of porm.xml is given below
i exclude the maven architect ,and try to run the application its showing following error
porm.xml
<modelVersion>4.0.0</modelVersion>
<artifactId>MyService</artifactId>
<packaging>jar</packaging>
<properties>
<java.version>1.8</java.version>
<!-- 2.1.3.RELEASE -->
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<springframework.boot.version>2.1.7.RELEASE</springframework.boot.version>
</properties>
<name>MyService</name>
<url>http://maven.apache.org</url>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.sybase.jdbc3.jdbc</groupId>
<artifactId>jconn3</artifactId>
<version>${jconn3.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-juli</artifactId>
<version>${tomcat.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-jdbc</artifactId>
<version>${tomcat.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
what was wrong in this porm.xml
Where is
${tomcat.version}
defined?
That version probably does not match the tomcat version that auto magically is included with spring boot items.
And thus the conflict.
Go here:
https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-web/2.1.7.RELEASE
And start following the COMPILE dependencies, and you'll find the versions that are auto included with 2.1.7.RELEASE. and you have to alter the other includes that are overwriting the springboot auto include tomcat versions.
Again, follow the COMPILED dependency trail.
So below is what you should find by crawling the COMPILED dependency trail (from immediately above in my answer)
https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-tomcat/2.1.7.RELEASE
And you'll find you need to set
tomcat.version to
9.0.22
By defining tomcat.version as 8.x, you are breaking it.
Another way to put it
You have to go ~way~ back to springboot 1.5.2.RELEASE or 1.5.3.RELEASE
https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-tomcat/1.5.2.RELEASE
https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-tomcat/1.5.3.RELEASE
(Again, in the two above links, looked at the COMPILE dependencies)
To find a version of tomcat (that is auto included with springboot) that gets close to tomcat 8.5.x (where 8.5.x is the one you are attempting to use)
That's pretty old.
The principal you are missing is that springboot auto includes dependencies. And anything else you import has to play nice with everything springboot auto includes.
And your current value for tomcat.version is NOT playing nice with everything springboot 2.1.7.RELEASE is auto including.
And now that you've been through all of that. You'll find you'll make your life easier if you engage the springboot world more completely.
Alot of times, springboot will have a (sub)package that will bring in the thing you really desire.
spring-boot-starter-jdbc
https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-jdbc/2.1.7.RELEASE
You would probably be better off bringing that package in, vs hand-picking ones. Aka, get rid of your "tomcat-jdbc" include and see if the spring-boot-starter-jdbc can give you what you want.
The curse/blessing of spring-boot is that it is its own universe. But if you engage, you probably want to play by its rules more often than not.
PS
It is pom.xml, not porm.xml
Try adding spring-boot-starter-tomcat as a dependency:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
Remove tomcat-juli and tomcat-jdbc dependencies. If you need JDBC support, add the corresponding starter:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
If you use JSP views, you will probably need the following dependencies as well:
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
</dependency>
Also, pay attention to your dependencies versions. Spring Boot's parent POM defines version management for many common artifacts so you don't need to set the <version></version> for these libraries. See https://docs.spring.io/spring-boot/docs/2.1.7.RELEASE/reference/htmlsingle/#appendix-dependency-versions

Autoconfiguation excluded but embedded servlet container is still being used

I've followed all the steps mentioned in the documentation to enable the traditional war deployment for spring boot app i.e excluded the EmbeddedServletContainerAutoConfiguration from the #EnableAutoConfiguration and I only have one such instance. Also extended SpringBootServletInitializer and make sure the packaged war doesnt have any tomcat starter dependency. Also ran the spring boot report and confirmed the EmbeddedServletContainerAutoConfiguration is in the exclusion list.
Apart from all the changes when I deploy the war it is still creating a embedded application context with embedded servlet contatiner.
What did I miss and what other areas can I inspect ? Spring boot version 1.5.13.
>
Hi Veeram,
We do not need to exclude the AutoConfiguration-classes, but excluding the tomcat dependency is needed.
You need to do is omit tomcat starter dependency from pom.xml. It gets pulled from spring-boot-starter-web as a transitive dependency. So, you need to add exclusion for it:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
Now, as you are using <packaging>war</packaging> and using SpringBootServletInitializer, we would need servlet-api dependency on the classpath.
So, add the servlet dependency to your pom.xml
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.0.1</version>
<scope>provided</scope>
</dependency>
Hope this helps!

Spring Boot logging with Log4j2

Written simple POC to prove and test Spring Boot and log4j2 compatibility. Once successful I will move it to real application.
Please refer my POC source code:
https://github.com/Dennyss/SpringBootLog4j2POC
I know/read about Spring version and log4j2 compatibility from:
How to set up Spring Boot and log4j2 properly?
Found and tried recommendations described here:
Spring-Boot logging with log4j2?
But still not working. The problem is that both application logs and Spring logs are printing to console only.
Please refer maven dependencies below (from POC):
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.6.2</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.6.2</version>
</dependency>
</dependencies>
If I don't exclude Spring's logback and don't add boot-starter-log4j2 then application logs are printing to application file but Spring logs are not printing at all. I feel the problem somewhere with dependencies. Appreciate any help.
According to the Spring Boot Logging documentation, the location of the logging configuration file can be specified using the logging.config property. I noticed that your start.sh script is passing -Dlog4j.configurationFile. Normally, this would be sufficient for direct Log4J 2 integration, but Spring Boot uses logging.config.
After switching to this, it writes to the log files:
java -Dlogging.config=/share/LogPOC/log4j2.xml -cp poc.jar:libs/* com.poc.logger.Application

why is the scope of RestEasy compile in the pom.xml when the container (JBOSS) provides it?

Here is the relevant portion of pom.xml
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jackson-provider</artifactId>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.jboss.spec</groupId>
<artifactId>jboss-javaee-all-5.0</artifactId>
<scope>provided</scope>
</dependency>
Why is the scope of resteasy compile (which is default, when none is provided) but that of javax.servlet is provided. I am deploying this on Jboss which ships with resteasy. so shouldn't the scope of resteasy be provided as well?
and btw, I do not see any version mentioned. so what is the default version that gets picked up?
If you are using jboss 7, resteasy-jackson-provider is included, so it would be correct to use a provided scope.
I guess default version is being picked up from a bom declared in the dependencyManagement section of your pom, could that be right?
For older jboss versions, resteasy is not included, so you will have to add the jars to your WEB-INF/lib directory.
Necessary jars can be obtained using maven (compile scope) or check out this link http://www.mastertheboss.com/jboss-frameworks/resteasy/resteasy-tutorial
The RESTEasy API and runtime is provided by newer versions of JBoss. Usually you import a Java EE-spec pom in the dependencyManagaement section and add the needed APIs in the dependency section, e.g for JBoss AS7:
<dependencyManagement>
<dependency>
<groupId>org.jboss.spec</groupId>
<artifactId>jboss-javaee-6.0</artifactId>
<version>3.0.2.Final</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.jboss.spec.javax.ws.rs</groupId>
<artifactId>jboss-jaxrs-api_1.1_spec</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
The runtime will use the JSON-Provider which is found on the classpath. So it makes sense to add them with scope compile to your project. If you want to use Jettison you'd add following to your pom:
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jettison-provider</artifactId>
</dependency>
If you don't add one your application server may provide a default one. JBoss AS7 / Wildfly for instance will use resteasy-jackson-provider if you don't add a provider to the classpath.
JBoss 5 does not provide the JAX-RS libs as far as I know so there it makes sense to add the resteasy-jackson-provider with scope compile.

Resources