Is it possible to force a Maven plugin to be included in a project from a dependency of that project? - maven

I have three Java projects. The first is an application, com.foo:foo-application:1.0.0, and the second is a module used as a dependency to that application, com.foo:foo-framework:1.0.0. The third is a Maven plugin authored by our team, com.foo:foo-plugin:1.0.0.
My intention is that any project, e.g. foo-application, which uses classes available in foo-framework must also validate that it has used those classes correctly, where said validation is enforced by foo-plugin.
Is there a way to enforce this behaviour within foo-framework's POM.xml, whereby any Maven module which declares it as a dependency in its own POM will have foo-plugin executed as part of its build lifecycle?

No (at least no way that I'm aware of).
when you declare a dependency on something, youre declaring a dependency on its output artifacts (and transitively their dependencies as optionally described in that artifact's pom.xml file). There's no place in a pom file to force anything on the build importing it - the build importing it may not even be a maven build.
it appears you may be able to do something similar via other tools though - for example checkstyle supports discovering rules from dependencies on the classpath (not exactly what you want and depends on users of your library running checkstyle configured just right)

Related

Gradle share dependencies in a cascade manner between related projects

I have the following Java projects structure:
Util
|
-- Core
|
-- Services
|
-- Tools
The projects: Tools and Services references to Core and Util projects, the thing is that I ended up writing the same dependency over each project, there must be a better way to inherit the dependencies of the referenced projects and add new ones if needed.
I know about multi projects in Gradle, but this is not like a multi project, since I can basically take the Core library, compile it (which will then contain Core + Util libs) and use it in another project.
I wonder what would be the best way to approach this?
Repeating the same dependencies in every project is usually reasonable because in a bigger project you'll never know when they become different, and you don't want to deal with compilation/runtime problems when someone changes common dependencies list.
I believe that it is more pragmatic to add dependency analyser plugin to your build. It will help you to remove unnecessary dependencies and explicitly add transitive dependencies. And if you add this plugin to your build chain, it will help you to keep your dependencies healthy in the future. Pick this plugin here gradle-dependency-analyze, or maybe there is a better fork or equivalent somewhere.
You are actually out of options in your case because there are only two kinds of dependencies: (1) external (some other jar artefact) or (2) internal (another module in a multimodule build).
2.1 When you use an external maven-like dependency it will come to you with own dependencies (they are named "transitive dependencies"). It means that if you do compile 'yourgroup:Core:1.0' then you will get Util as a transitive dependency. But as I mentioned above, it is better to list transitive dependencies explicitly if they are used during compilation or to prevent them from being accidentally removed and crash your application in runtime.
2.2. If your projects live in the same version control repository and usually change and build together, then the multimodule layout is your best choice. In this case, you will refer to Core dependency like compile project(':Util:Core') and it will grab Util as a transitive dependency as well. And you will be able to do what you asked for and define dependencies for Services and Tools once - inside subprojects {} closure in the Core/build.gradle.
Having multimodule built doesn't limit you from using Core library elsewhere. No matter if it is a multimodule build or not, you can always add maven-publish plugin to Core/build.gradle, execute publishToMavenLocal task and reference to Core.jar from another project the same way you do for external dependencies.
You can always put your common code (like the one which will add common dependencies) in the external gradle file or custom plugin and apply it in Services and Tools.

Installing BOM before Maven tries to resolves it

Is there a way to install a BOM as part of maven invocation before maven tries
to resolve it. See related questions for a normal dependency
Install local jar dependency as part of the lifecycle, before Maven attempts to resolve it
Is there are way to install maven dependencies before maven attempts to resolve them?
I have tried to run a plugin in validate phase, but maven always resolved the
bom first be it a import scope bom or used as a parent bom.
About BOM: http://www.baeldung.com/spring-maven-bom
The expected usage of maven BOM is within the dependencyManagement section of a pom.xml.
Maven documentation states:
Other projects that wish to use the library should import this pom into the dependencyManagement section of their pom. (Please refer to Introduction to the Dependency Mechanism)
In a multi-module project you would usually have a dependencyManagement section with the parent pom only.
Also, just for clarification: The bom is NOT causing dependencies to the artifacts indicated therein. It is merely indicating the versions of the "ingredients" that are intended to be used together (for dependencies that are composed of several artifacts expected to be used together) in case a dependency is added somewhere in a related pom such dependencyManagement applies to.
With such setup maven will resolve the bom at time of processing dependencyManagement section. This is time of evaluating the surrounding pom.xml (or any referencing sub-module). The bom is then added to the local repository like any other dependency.
So, under normal circumstances there is no need for "fetching the bom from the net and installing it into the local repository".
Now, why would a bom artifact not be available at the time a maven call is being started?
The artifact source (repository) is not accessible
Then, downloading the artifact and providing it into local repository would be the way to go.
The artifact version is not known before (or is decided at starting time, e.g. either be specifying a profile or indicating the version as a runtime parameter)
Then the dependency mechanisms of maven still would work as expected.
The bom artifact content (list of artifacts or respective versions) is not known before (e.g. as it is depending on outcome of some build step during the build run)
Then, you likely need to rethink your build process, as it looks like you are trying to force maven into something it is not designed to support. Likely, the "dynamic" part is intrinsic to your project and thus, the dynamic dependency really should be a sub-module within your (multi-module) project. But it is really hard to advise without more input on a specific use case.
While a specific artifact to be consumed within a build step might be provided late (by relying on lazy evaluation of dependencies), this will much more difficult with bom dependencies. As such are dependency management entities that need to be resolved before the first time any dependency needs to be resolved as maven can not known what artifacts are contained within the bom.
If actually there is a usecase that absolutely requires such bom to be provided dynamically, then the only chance is a two layer process, where the top layer is providing the bom and the lower layer is then using it. Please note, that such a solution absolutely needs two independent maven processes (so, NOT just a simple multi-module project) in order to get the resolution of the depenceManagement dependency deferred until it is known.

Java/Maven: how to remove content from shaded JAR at compile time?

I am in my project reusing an open source maven-based component that includes a bunch of shaded (e.g, using the maven-shade plugin) direct and transitive dependencies in the component uber-jar. Unfortunately some of those dependencies clash with dependencies that my own project has. Specifically, the component's dependencies transitively include servlet-api 2.x whereas I need 3.x in my project - and they appear to be in the same namespace. The component's top-level dependency that pulls in servlet-api (lucene-demo) is actually not needed for the functionality of the component, so I'd be happy to remove it if possible. My project is built with Gradle.
What is the recommended way of dealing with this type of situation? Is there any way of removing the offending dependencies from the reused uber-jar when I build my own project? Or should I rebuild the reused component myself, excluding the troublesome dependency? If so, can this be done in an automatic manner, such that I don't need to maintain my own fork of the open source component? The component is presently hosted in GitHub and published via Maven Central.
(As you might understand, I'm a bit of a beginner to both Maven and Gradle, so don't worry about dumbing things down).

deploy maven artifact with multiple profile dependencies

We are relatively new to Maven and now face a problem.
We have a Maven project (projectA) whose JAR is the dependency of several other projects. Some of the other projects are some custom web container while others are not, so some of projectA's dependency jars are provided in the case of the custom web container, but should be runtime scope in the case of other projects. We currently use exclusion list to filter out the provided jars in the case of the custom web container.
We are wondering if it would be better to use maven profiles. We know how to create the profiles with different dependencies (actually same dependencies different scope), and in both profiles, the built projectA jar is identical bit-wise. But what we don't know is, when we deploy/release the projectA jar artifact to a maven repository, what should the pom.xml look like? For these web container projects, the pom.xml should not include the provided jars, but for other projects, the pom.xml should include these jars.
We can use a different name for the jar in each profile and deploy each with a different pom.xml, but since these jars are identical bit-wise, it doesn't seem like a perfect solution. So we thought there's gotta be a better solution to this problem, only that we don't know since we are relatively new to Maven. Thanks.
The POM is the POM. You seem to be talking about managing transitive dependencies in other projects that reference "A". Your options in Maven are fairly limited:
You can use exclusions to remove transitive dependencies that you don't want.
You can declare dependencies in "A" as "provided", but this is only really correct if that jar actually is provided in A's target environment. It's primarily intended for Java EE api dependencies, like servlet-api, which are provided by containers and prohibited from being included in WAR files.
You can declare dependencies as optional, which is what people usually mean when they say "provided", and manually include those dependencies in the places where they're needed.
I'd personally choose the "optional" route because it's the job of each project to pull in the dependencies it needs, and if something is optional when using "A", it just means things that use "A" have to explicitly choose whether they'll use that optional part of it. This tends to be the best fit when building an artifact that has multiple, differing use cases.
For additional help in this area, you can also use the maven enforcer plugin to ban certain dependencies from builds so that you don't accidentally get jars that you don't want.

Is declaring maven "dependencies" in pom.xml really necessary?

I need some verification of how Maven works.
How important is it for us to specify the project dependencies explicitly (<dependencies>) in pom.xml? Some said that it's necessary only when we need a specific version of that jar, otherwise Maven will be able to find the jar in your local / Maven's remote repository. However, I find that sometimes I could not build or package a Maven project without specifying/declaring the dependencies.
So.. is the declaration really necessary?
If your code just uses "plain" Java and does not depend on any other libraries you do not need to declare any dependencies (because you do not depend on anything other than the Java runtime).
In most cases you will use some 3rd party libraries - thus you have to declare them as dependencies in your project to let maven construct a valid classpath which lets your build work (transitive dependencies will be resolved automatically - as already mentioned).
Regarding to the specific version of a jar have a look at the Project Dependencies section of the "Maven: The Complete Reference" book provided by Sonatype. You have several options to declare the version you need (including version ranges).
Do not expect that the declaration
<version>1.2.4</version>
will force Maven to use that version. That is only meant as "allow anything, but prefer 1.2.4". If you need to force maven to use a specific version and nothing else you have to use
<version>[1.2.4]</version>
Yes, the dependencies are needed. Most plugins use them to construct the necessary classpath, or to determine what to include in the artifact. Maven is declarative - you are declaring what you need, not how and where to find them locally.
You need not to declare Transitive dependencies of a JAR. Other than that, everything must be declared. Here is a good read on how maven mananges dependencies. http://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html
You always need to specify the dependencies. Maven can't predict, which libraries you need. What you in most times don't need to specify, are additional Maven repositories. You need that only when you have libraries as dependencies, which are not contained in Maven Central.
What you also can eliminate in your projects, are the version numbers of your dependencies, if you have a parent POM, where the versions are specified.

Resources