Multiple different classpaths during maven test execution - java

For a java project I want to spin up a server application during integration test (maven-failsafe-plugin, can be switched).
Problem
The server application should be fetched via maven
My project and the server depend on a shared library
The version of my copy of the shared lib may be different then the one of the server application
(During test there is even a third application involved, but the same requirements apply)
Current solution
Create a classloader manually, built classpath manually, start server application in custom classpath
manual dependency resolution sucks. Has to be redone on dependency changes.
Put everything onto the classpath, remove stuff that breaks.
Also manual...
Wish
Specify a "dependency profile" in pom.xml for each component
During test call something like: Maven.getClassLoaderForProfile("server"), receiving a classloader with all dependencies (including transitive ones)
Load application in this classloader

Related

Gradle: Add dependency of subproject as dependency of the root project

We are running our Java EE applications in WAS 8.5 and Gradle 5.* to build them.
In the past we packaged our .war application in an .ear archive, which we then deployed on our server. We had to separate our libraries from our applications and include them as shared libraries, because in our experience it made deploying much slower and in some cases used up all system memory, crashing the server.
After some experimentation, we realized that we don't need to extract the dependencies into shared libraries, because we can include them in the lib folder of our .ear archive.
Currently, we get this done by defining the dependencies of our .war application as compileOnly and redefining them as earlib in the root project (which generates the .ear archive). I'm looking for a way to automate this procedure.
The script I used looks something like this:
project.configurations.named('deploy').getAllDependencies().withType(ProjectDependency.class).forEach({dependency ->
project.configurations.named('earlib').getAllDependencies()
.addAll(dependency.dependentProject.configurations.named('earlib').getAllDependencies())
})
// This loosely resembles the actual code I used. The thought process is right, it just might have a couple syntax errors.
// Obviously, I defined an `earlib` configuration in the subproject
I tried running this code in the configuration phase, as well as in the doFirst{} section of the ear task. They all had different problems.
The former didn't work, because it seems like in the configuration phase when this code ran, the dependencies weren't configured yet.
The latter didn't work, because I can't just add dependencies during runtime (thinking back, it sounds ridiculous that I even tried it).
My question is: Can I find a phase in the build lifecycle, where I can find and modify the dependencies? Is there another workaround to solve my problem?
The technical answer to your questions is that you can use either:
A configuration.incoming.beforeResolve hook to do it last minute, only when the configuration really needs to be resolved.
Use an afterEvaluate block, assuming all the other dependencies are not defined in an afterEvaluate themselves.
However, the right solution would be to leverage the dependency management engine of Gradle and effectively declare that your root project, the one building the EAR, has dependencies on the specific configurations of the subprojects.
Not knowing your full setup and details, I believe the above would still be the more correct solution, though you may have to filter the subproject artifacts from the resulting graph.
Ideas on how this works in recent Gradle version: https://docs.gradle.org/6.2/userguide/cross_project_publications.html Most of the things explained there should work with the latest 5.x versions.

Managing dependencies in a JAR - Test Automation

I'm not sure if this is the best place to post such a question, but here it is. I'm a test automation engineer that works primarily with backend, spring boot command line apps. My tests, at a high level, are designed to ensure that any type of data that is thrown at the app will be handled correctly. We are a Java shop.
As with any "good" testing practice, I am treating the app like a blackbox, in that I do not pull in the model objects to run my tests. I simply supply the app with data, execute a command line type script (run.sh) that takes my data and processes it. My tests are comprised mostly of JDBC (to interact with the database) and a slew of ArrayList utilities that I have put together to sort out result sets and get specific db information.
Thus far, I have been deploying my tests as a JAR. I bundle everything up and deploy it to the environment with a script that will execute the tests. The tests do not run when the app is run. Though they do live inside of the project, they are a separate entity with separate launcher classes. However, I am finding that managing dependencies in a JAR is a real headache. Is there a better way to deploy automation / integration tests for command line apps?
I'm pulling in maven shade plugin to bundle all of my dependencies into a "God JAR", but that isn't helping me to resolve the issues that occur when I attempt to execute the JAR. I get multiple bean instantiation errors, relating to the app itself, and not my tests. For this reason, I pull in the app model, and the app itself as dependencies. When I ran the tests in my initial testing, they worked just fine. Deployed to environment and they continued to work correctly. Fast forward a couple of months, a few changes made to the app, and now it's a dependency nightmare when I build the new JAR.
TLDR: I'm having trouble managing dependencies in a maven project, integration tests JAR. Is there a better way to deploy automation / integration tests for command line apps where dependency management is easier?
(Note: I'm relatively new to this world, so pardon me if the question seems a bit vague).
I think the error happens when you use the shade plugin to re-package the spring boot jar. The way spring boot works is to add dependencies into the jar as jars itself and configure its own class loader (in the meta config) that is capable of reading classes from jar files inside the jar file. The standard java class loader does not do this - thats probably why the shade plugin misses out some jars (probably the ones embedded in the spring boot uber jar).
what I would try is to create a test-version of the spring boot app that contains the test-classes in the compile scope and a dependency to the original spring boot jar (you don't need the uber jar - therefore you may have to add a classifier to the original (app) spring boot plugin config to have that jar still available as it is replaced by default) and use the spring boot plugin to package the test version of it (using the dependency and its classifier above you used for the original app).

How to specify order of running in multimodules maven webapp?

I have a multi-modules application which build on maven. In one of the modules i have some initialization logic (with ServletContextListener) which should be execute before other modules. My application server is WebSphere. How can i configure strict order of execution for my modules (maybe on application's level or maybe on Websphere's level)?.
UPD:i tried to add initializeInOrder property, but it does not work for me (order does not change).
UUPD:There is only one solution which i found. Starting weight configuration helps me. It is a WebSphere configuration for application with multiple modules. Module with lower weight should be execute earlier. But i want to solve this problem on ear's level.
Have you tried initializeInOrder element of ear:generate-application-xml plugin?

Gradle Local Repository to share jars easily?

So we a re considering Gradle instead of Maven. What I cant figure out is how to EASILY share built dependencies between completely seperate projects at a local level that will work anywhere.
So imagine I have 2 projects DBService and Middleware. Middleware depends on DBService but they are completely seperate (not sub projects nor multi modules etc...).
I make changes to the DBService and then in Maven I could have changes go to local Maven Repo (not global as i need to test them first) using:
mvn clean install
I then start coding on Middleware and import the changes by running the same command as normal (Nice!). The maven POM requires nothing special at all (besides standard ). No path to local directory containing the jar in a lib folder (nasty IMHO) or anything else. it just works (out of the box).
How can I achieve this very simple and very common scenario in Gradle. I know I can use a local Maven repo but this is this a first class citizen in Gradle? Does it not need special/ad-hoc, or even worse, environment specific setup (UGHH) in Gradle?.

How to prevent third-party JARs on the classpath from overriding my class dependencies?

I am writing an application plugin in Java, and my plugin has dependencies on several third-party JARs. I am bundling these dependencies with my plugin so that I can deploy just a single JAR file.
The host application may also be running plugins from other vendors. Unfortunately the host application puts all the plugins on the classpath, and I am not able to change this behavior. If another vendor's plugin is loaded before mine and uses an incompatible version of a dependency, my plugin could crash.
I am not able to test compatibility between my plugin and other plugins ahead of time. It is also not acceptable for me to say that there is an incompatibility between the plugins--if my plugin crashes, it reflects poorly on my company. The customer does not care why my plugin crashes, they will attribute it to poor programming on my end.
I am looking for a way to prevent other vendors' plugins from interfering with my own. Is it possible?
I've heard of custom classloaders but I'm not sure if that solution will work for me.
You can use Uberjar. What it does is move all your jars/classes to a custom namespace so that none of your classes clash because your dependencies have a different namespace.
You might want to look at maven-shade
You could try to embed an OSGi container in your plugin. This would allow you to run and load dependencies as OSGi bundles in isolation from the system classloader.
Instructions for Felix.

Categories