Spring WebApplicationInitializer (ServletContainerInitializer, #HandlesTypes) with Embedded Tomcat - spring

I fail to understand why in the following minimal project my implementation of Spring's WebApplicationInitializer interface is found when running tests within Eclipse and IntelliJ, but not when using Maven (mvn clean test).
With Eclipse and IntellIJ I see INFO: Spring WebApplicationInitializers detected on classpath: [com.example.pack.DummyInitializer#26d678a4]
With mvn clean test I see INFO: No Spring WebApplicationInitializer types detected on classpath.
In the test I start an Embedded Tomcat:
String pathToWebXML = new File("src/main/webapp/").getAbsolutePath();
tomcat = new Tomcat();
tomcat.setBaseDir("embedded_tomcat");
tomcat.setPort(0);
tomcat.addWebapp("", pathToWebXML);
tomcat.start();
The web.xml references a ServletContextListener implementation which creates a new (and empty) AnnotationConfigWebApplicationContext.
I uploaded the example project to GitHub: https://github.com/C-Otto/webapplicationinitializer

As indicated in the comments, the classpath used by Maven Surefire (and Maven Failsafe) in the default setting is not scanned by Tomcat. Most classes are referenced using a MANIFEST.MF file inside a JAR file.
One option is to disable the useSystemClassLoader setting of the Maven plugins. However, this changes the details of the classloader, which may cause other problems.
As another option one could disable useManifestOnlyJar, which may cause problems on Windows machine.
In our project we decided to remove the initializer classes, and instead register whatever they were supposed to do manually. In a concrete example, as our implementation of AbstractSecurityWebApplicationInitializer was not found, we now register the security filter manually inside the contextInitialized method:
String filterName = AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME);
servletContext.addFilter(filterName, new DelegatingFilterProxy(filterName)).addMappingForUrlPatterns(EnumSet.allOf(DispatcherType.class), false, "/*");

You can tell Tomcat to include the jars that are referenced via the manifest file in the jar created by surefire. This can be done in context.xml setting the Jar Scanner attribute scanManifest to true. This is the default in newer versions of Tomcat as stated here: https://bz.apache.org/bugzilla/show_bug.cgi?id=59961.

Related

my application.properties from dependency is not available in spring boot application

I have spring boot application.
In this spring boot (fat-jar) application I have classpath:config/application.properties and classpath:application-env.properties.
I am starting this application using command:
java -Dspring.profiles.active=env -jar application.jar --some-parameter=some-value
Question: Why application.properties file is not available during initialization this application from classes (beans) localized in my dependency?
This file (application.properties) is localized in classpath:application.properties of my dependency.
I am expecting some properties with some specific prefix - using annotation:
#ConfigurationProperties(prefix = "someprefix")
and again the same in other words:
Application A have classpath:config/application.properties
+ Application A have/is using dependency to some artifact D
dependency (jar) D.jar have classpath:application.properties
this application.properies is not available during initialization of bean B with annotatin #ConfigurationProperties(prefix = "someprefix")
according to 24.3 Application property files "The classpath root" should be fine - but it is not.
This is fat-jar application - in one big jar we have everything - including folder 'lib' with all dependencies.
OK, :(
solution of my issue was trivial. My application was loading different classpath:/application.properites than I thought.
I had another dependency jar introduced to my project not-directly (it was dependency for my dependency) which contains different classpath:/application.properites.
In other words everything works fine but only one 'classpath:/application.properties' is loaded even you have two in two different dependencies.
I used /actuator/env to find out which classpath:/application.dependency was loaded.

Why isn't this jar packaging valid for Spring Boot?

I am trying to understand the packaging of Spring Boot into "fat" jars. From what I know "fat" jars have their own special classes that load up the main class when the jar is running and also sets the classpath accordingly.
What I cannot understand is why when I use Eclipse to extract all my dependencies into a folder structure in the jar, the jar no longer runs as a correct Spring Boot application.
To repeat what I have done here just take a simple Spring Boot app and from Eclipse select the following-:
Export --> Runnable Jar --> Select Main Class --> Extract required libraries into jar.
Just run the jar from the command line as you would any jar. Spring Boot initially starts up but fails with the following message-:
2017-05-02 22:06:40.484 WARN 3468 --- [ main]
ationConfigEmbeddedWebA pplicationContext : Exception encountered
during context initialization - cancel ling refresh attempt:
org.springframework.beans.factory.BeanDefinitionStoreExcep tion:
Failed to process import candidates for configuration class
[com.main.Test Main]; nested exception is
java.lang.IllegalArgumentException: No auto configuration classes
found in META-INF/spring.factories. If you are using a custom packa
ging, make sure that file is correct.
Can I somehow edit the spring.factories file to include my classses ?
I just trying to understand how Spring actually packages the files through its Maven plugin.
I think that because it's a Spring Boot application, you need to use their plugin for building. It is because, spring Boot has its own jar loading mechanism for that (the BOOT-INF introduction in Spring Boot 1.4).
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
From documentation:
The Spring Boot Maven Plugin provides Spring Boot support in Maven, allowing you to package executable jar or war archives and run an application “in-place”.
Link to documetantion (Appendix E)
Something about spring.factories and locating auto-configuration candidates - Auto-configuration

Use of spring-boot-maven-plugin

While creating a spring boot project I define property in pom.xml as <packaging>war</packaging> with which I can create a war and thereafter deploy the war into server maybe tomcat or WAS.
But I came across a plugin named spring-boot-maven-plugin whose documentation states that it's use is to package executable jar or war archives and run an application in-place.
My query is why do we need this at all ?
If my packaging can tell me what to create and then can deploy it to run, what is the used of this plugin.
I am trying to understand a new project so wanted to be sure that every line makes sense
The maven plugin will create an "executable" archive. In the case of the war packaging, you would be able to execute your app with java -jar my-app.war. If you intend to deploy your Spring Boot application in an existing Servlet container, then this plugin is, indeed, not necessary.
The maven plugin does more things like running your app from the shell or creating build information.
Check the documentation
The Spring Boot Maven Plugin provides Spring Boot support in Apache Maven, letting you package executable jar or war archives and run an application “in-place”.
Refer this - https://www.javaguides.net/2019/02/use-of-spring-boot-maven-plugin-with.html

Eclipselink Static Weaving and Spring Boot is not Working

In a Spring Boot project we use Eclipselink as ORM. We configured the build to weave statically and to package as jar. The interesting thing is that starting the program with mvn spring-boot:run works without problem, but starting with java -jar archive.jar works only if all entities are listed in the persistence.xml. Without having the class in the persistence.xml I get the error:
java.lang.IllegalArgumentException: No [ManagedType] was found for the key class [eltest.Customer] in the Metamodel - please verify that the [Managed] class was referenced in persistence.xml using a specific <class>eltest.Customer</class> property or a global <exclude-unlisted-classes>false</exclude-unlisted-classes> element
Also in the case, when we package the program as war, it starts without issues.
My questions are: Does the mvn spring-boot:runinvoke the static weaving at all, or does it weave at load-time? The same with the war deployment: does the war-build really invoke the static weaving, or is the weaving implicitly triggered, when the Tomcat starts the app? Is there a way to avoid listing the classes in the persistence.xml, and still go for statical weaving in a jar-packaging?
Here is an example:
https://github.com/gfinger/eltest
Build it with mvn clean package. If you start it with mvn spring-boot:run it uses Spring Data Rest to expose a Customer entity as REST resource. If you start it with java -jar target/static-eclipselink-0.0.1-SNAPSHOT.jar you get an error.

spring boot System.getProperty("java.class.path") doesn't include lib/ jars

I've got a spring boot app and I'm building a myApp.jar using the spring-boot antlib. When I jar -tf myApp.jar I see that I have a jar called lib/foo.jar. Yet when I print out System.getProperty("java.class.path") I don't see that jar file on the classpath. I also get a ClassNotFound exception from URLClassLoader when the code attempts to use this class for the first time. I'm using the JarLauncher since that's what the antlib defaults to.
Any ideas why this jar file would not be on the classpath?
You won't see a bundled JAR in System.getProperty('java.class.path'). The class path specifies where the JVM will look in the filesystem for classes you attempt to load.
Spring Boot uses fat JARs, which are loaded in a completely different way. Refer to the Spring Boot documentation.

Resources