How are dependencies shared in a maven multi-module project? - maven

I am a bit curious about how this works - if I have 5 module projects in a Maven multi-module project, can you import the content and packages into other modules without adding that project as a dependency? Or do you in-fact need the .jar (or a snapshot jar) in order to use structures/functions from other modules?
Thank you,

Inter-module dependencies (adding one module as a dependency in another module's pom.xml) is meaningful in the world of Maven (as a build tool, not an IDE). When you build your multi-module projects from command-line, you don't need concern the dependencies between each module yourself, Maven will topologically sort the modules such that dependencies are always build (hence generate the jar file) before dependent modules (so that it can reference generated jar file as a dependency).
This is not necessary (in theory) if you use IDE like Eclipse, as you can achieve the same result (adding one project as a dependency of another) by some manual settings in Eclipse Right click project and choose Properties -> Java Build Path -> Projects -> Add, which is automatically handled when Eclipse import your multi-module project, if you define inter-module dependency in pom.xml.
The question is why you want to do something unusual (without adding that project as a dependency) that you cannot gain any benefit from it.

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.

Is it possible to build a "sub jar" of a Maven project?

I have a situation at the moment where I have:
Project A which is built into a fat jar using Maven assembly plugin.
Project B which uses the jar built in Project A. It is added to the project as a resource and launched in a separate process using a process builder.
I wonder if it's possible to achieve similar behaviour using just one Maven project. I.e build the jar containing only the classes and dependencies required for project A, and then build the rest of the project with the prebuilt jar.
Sorry if I'm not being very clear here.
This is against a few of Maven's core concepts:
One project, one model (POM). Two projects (A, B), two models (POMs).
There's one artifactId in a POM. What is a second artifact (jar) supposed to be named?
One project leads to one artifact. There is no additional "prebuilt jar" built within the very same project.
Dependencies are for the whole project (and possible sub-module projects). I'm not aware of how to "containing only the classes and dependencies required for project A".
Artifacts are stored:
in <project>/target temporarily
in the local Maven repository (default: ~/.m2/repository)
possibly in a remote Maven repository
... while resources are taken from <project>/src/main/resources during the build.
There might be some tricky solutions (which have possibly pitfalls, too) to achieve this if one thinks about it thoroughly. But I'd never ever recommend such.

Gradle Maven like multi module project

When you define multi module project in Maven, you have one root project and its modules. When you build the root project, Maven transitivelly builds all its modules in correct order. So far pretty similar to Gradle.
But with Maven, you can clone only one submodule from repository and build it locally without need to download the whole project structure. This is because you define dependencies on other modules within the same project just as any other external dependency and it is downloaded and cached from your local repository (Nexus).
With Gradle, you define cross module dependencies as compile project(':other'). So you need to clone whole project structure from repository in order to resolve and build correctly. Is there any way to use Gradle multi module project support, without having to locally clone whole project structure?
I would argue that Maven's multi-module support is a slapped on after-thought. Unlike Gradle, a project dependency is not a first class concept. Instead the maven "reactor" substitutes local artifacts for dependencies when the GAV (group/artifact/version) matches.
If you'd like to use the same approach in Gradle then you can specify your dependencies using the GAV notation and then use the new composite build feature to join two or more separate gradle builds together and substitute repository dependencies for local source dependencies. Note that that you can define the projects included in the composite using groovy so you could easily script this based on custom logic (eg if a subfolder exists in some root folder etc)
Note that composite build support is a new feature added in Gradle 3.1. Prior to Gradle 3.1 you can use Prezi Pride to achieve the same

Getting Intellij to link sources between OSGI/Tycho modules

I have a large osgi project with many bundles/modules that I'm trying to get working with Intellij. Currently users edit MANIFEST.MF files in each bundle to manage dependencies and tycho is used to populate the pom.xml files that actually build the project. The target platform is built by maven as a p2 repository.
I've loaded this project into Intellij as a bunch of maven modules in a single project that each have an OSGI facet. At this point everything works pretty well, but I can't get Intellij to resolve sources between bundles.
Concretely, I have two modules in my project, A and B, and B references a class in A. B's manifest imports the package from A that contains the class. When I 'jump to definition' on the class from A within B it takes me to the decompiled class file, rather than the sources in module A. When have multiple maven modules without tycho in an Intellij project however this resolution occurs automatically.
I'd like to be able to resolve sources between such modules when they are built through tycho.

Dependency on non-maven module

The entire java project has an ant build; however couple of module(s) have maven build too.
My new module (maven built, say A) has dependency over an existing module(or simply a folder?, say B) which is being built using ant which just packages the src into jar and drops it inside the project.
Maven build for module A fails (unable to locate moduleB files); Options -
1. Package module B using maven, push to m2_repo
I do not want to go with this option.
Please let me know what are the other options available for the same.
If you have control over the source of all your modules, and if you decided that Maven is your way to go forward, then I recommend to to go all-in as soon as possible. If you do not then you will have continuous problems for the two build strategies to play along. And not only during build time but also at deploy time when it is time to collect all your runtime dependencies. Unless you build one uber-JAR as your only deployable artifact.
If your modules will (almost) always release in sync, then consider using a multi-module project setup.
When I say "all-in" then I do not mean that you have to give up Ant completely. You can use the maven-antrun-plugin to kick of your existing ant builds.
You should also consider running your own repository server, e.g. Nexus, to take full advantage of your maven builds.

Resources