Maven-2: Module depends upon another within same project (Two questions) - maven

Here is a my file system setup:
.m2/ <--- Local Directory
app/
pom.xml
module1/
module2/
module3/
target/ <--- Package directory
Question A
In the parent pom.xml, it has a dependency that all the modules depend upon. Though, when it goes into compile phase, module2 will need to depend on something that just compiled in module1 and module3 needs to depend on something in module2. How would you go about doing this without making two or three "maven projects"? Is it possible to run the compile, install, and package phases on each module individually one at a time (I'd rather do this solution)?
Question B
Also, I know when you install the module, all the "stuff" is updated and added to the local repo. When you are in the compile phase, by default, it grabs all the stuff it needs to depend on from the local repo (Correct if I'm wrong). Also, if I were able to achieve Question A, instead of using the local repo to obtain all the information needed for my dependencies, it possible use those same files from the packaged target directory instead?
Can these questions be answered by a simple pom manipulation and/or adding a plug-in? If this is possible, how would I go about doing this?

Maven is built with the idea of one project-one artifact. What you would normally do in the situation you describe is create a separate POM in each of the modules with the top level POM specified as the parent. Each of the sub modules would then inherit the dependencies of te parent and be free to add additional module specific dependencies. In the top level Pom, you then use the declaration to declare the three sub modules.
One key advantage is that if there are dependencies between the sub modules (like you describe), then maven will automatically figure out the correct order to build them in based in those dependencies.

Related

Gradle search local maven or gradle repository

I am using gradle and its local repository is at \.gradle\caches\modules-2\files-2.1 which has all the downloaded jar but not my modules.Is there any specific place I should be searching it for ?
I need it as is in settings.gradle I am having a dependency path specified like :
include ':model'
project (':model').projectDir = new File(settingsDir, './model')
in a new project. Also I don't want to give path in that way because if I have a dependency from multiple projects on this project then mentioning path will be difficult and weird.
How can I make gradle search it from local maven or gradle repositories.
I'm still not sure what is being asked here, and I suspect there is some confusion over how multi-project builds work. So I'm going to attempt to provide a general-purpose answer.
The first question you need to answer is whether you're interested in dependencies between projects that are part of the same build — as in part of a multi-project build — or in separate builds.
Project dependencies (multi-project builds)
Project dependencies are covered in the user manual and only apply to multi-project builds. They use a logical path, using colons as 'path' separators, to specify the location of the target module, like so:
dependencies {
implementation project(":model")
}
At this point, Gradle needs to know where ":model" exists on the file system. There's no getting around that. You have a few options:
Follow the convention of directory structure matching the logical path structure, i.e. have a MyBigProject/model directory containing the ":model" child project
Specify the file path of ":model" in settings.gradle, e.g. with project(":model").projectDir = new File(rootDir, "unusual/path/to/model")
Automate the discovery of projects
The most common approach is the first one. The second is not unusual, particularly if you want to put child projects into a separate directory, like subprojects — something the build of Gradle itself does. I haven't seen the last option done, and I don't know whether it runs into problems.
For the sake of completeness, and at your own risk if you use something like it, here's an example of automatic discovery of projects in the settings.gradle file:
rootDir.eachDir { File dir ->
if ("build.gradle" in dir.listFiles()*.name) {
include dir.name
}
}
This fragment basically looks for directories within the root project folder that have a build.gradle file in them and adds them as child projects. The child projects' directory names become the projects' names.
It's not particularly clever, and you should really use different names for the build files, but it may give you some ideas to work with.
Non-project dependencies
As with project dependencies, Gradle needs to know where to get the corresponding JAR or other form of artifact for a specified module. You normally specify Maven Central or something similar for this, but there are other useful, but less common, options:
Copy a project's artifacts into the local Maven repository — both the Maven Plugin and Maven Publish Plugin support this
Publish to a Maven-compatible repository using a file:// URL rather than an HTTP/HTTPS one, which protects your projects from corruption of Maven Local
Worth noting is that Gradle supports composite builds that allow you to substitute a normal dependency with (effectively) a project dependency from another build. So if model were part of a separate build but you had the source code and build locally, you could make changes and immediately test them in another build's project without going through the whole "install" intermediate step that's common in the Maven world (and Gradle pre-composite-builds).
Hope all this makes sense.

Maven module dependency source instead of repository jars

I have a multi-module project, i.e.
parent
module1
module2
In one dev cycle, I added a class mod1.A to module1. Class mod2.B in module2 depends on it.
I do not have the artifacts in my local .m2/repository. Running this:
$ cd prj/module2
$ mvn -o exec:java -Dexec.mainClass=mod2.B
results in an error along the lines of:
The following artifacts could not be resolved: com.example:module1:jar:1.0-SNAPSHOT
After I install the artifacts via mvn install while in the prj folder, it all works as expected.
However, this presents an issue in at least two ways:
I have to go through the slower install phase instead of the faster compile phase
I have two versions of the same project and conflicting modifications in these. I cannot run the same Java class with their respective modifications, only the currently installed modifications, considering they are both the same SNAPSHOT version
There are workaround for both (skip parts of the build for the first, different snapshot versions for the second), but they are far from usable in practice.
Is there a way to make maven use the local modules, instead of using artifacts from local maven repository?
If I understand your question correctly, it seems like you are living a bit outside the norm here: you have two local "copies" of the project with different modifications, that you want to work with alternately when running "exec:java". And Maven is getting in your way: it expects your local .m2 repository area to be in play, but the version strings in each copy are the same, so you end up with the changes interfering among the copies.
To me, it sounds like what you are trying to do is to test your changes. I suggest you just write an actual JUnit or TestNG test in module2 that tests what you want (it can just call mod2.B Main if you want). Then, from your chosen project directory, you can run mvn test -Dtest=MyTestName. It won't "install" anything and it will find the dependencies the way you want it to.
Otherwise, I can see three options.
Change the version string locally in one of the copies (mvn versions:set -DnewVersion=B-SNAPSHOT can do this for you). That way any "installed" jars from your work on that copy will not be considered by the other copy, and vice-versa. You refer to this as being "far from usable" ... I think it should be fine? These are different versions of the project! They should have different version strings! I strongly recommend this option out of the three. (You can do mvn versions:revert when done if you used :set, or you can rely on version control to undo the change.)
Select a different local repository used by Maven when working on one of the projects, with a command-line flag as per https://stackoverflow.com/a/7071791/58549. I don't really think this is a good solution, since you would have to be very careful about using the right flags every time with both projects. Also you'd end up having to re-download Maven plugins and any other dependencies into your new local repository anyway, which is kind of a waste of time.
Try to avoid using any local repository at all. You seem to be trying to make this option work. I don't think this is a great approach either; you're fighting against Maven's expectations, and it limits your flexibility a lot. Maven will indeed find dependencies from the "reactor" (i.e., the executing mvn process) first, but this means all of the required modules must be available in the reactor to be found, which means you can only run mvn at the top level. So if instead you want to just do "mvn exec:java" inside a single module, mvn needs to find that module's dependencies somewhere ... and that's what the local repo is generally used for.
If you're dead set on going with option 3 (instead of option 1), then I suggest you follow the comments on your question and create a profile that runs your exec selectively against module2 and binds it to a lifecycle phase. But this is in practice very close to just wrapping it with a test.
For IntelliJ users:
I solved this problem using IntelliJ's Run configuration. It has the options Resolve workspace artifacts and Add before launch task -> Build. See this picture for clarification:
Run configuration example
The whole point of modules in Maven is to create decoupling between them. You either build each module independently, so that you can work on one module without touching the other, or include both modules as sub-modules in the parent pom and build the parent, which will resolve dependencies between its sub-modules and trigger their builds.
It looks like you have two options here:
Review the structure of your project. Do you really need to split it into two separate modules, if you change code in both of them simultaneously?
Import the project into a Maven-aware IDE (IntelliJ IDEA is very good at working with Maven), and let the IDE handle the compilation. Once finished and stabilized the code-base, build normally with Maven.

How to tell Maven to compile auto-generated maven modules?

In a project I'm working on, we auto generate the interfaces API in a folder called api/ which contains several sub-folders, where each of them has a pom file able to compile the content of the module.
project-root
- api
- module-api-1
- pom.xml
- module-api-2
- pom.xml
- module-api-3
- pom.xml
- module-api-4
- pom.xml
- build
- pom.xml
Basically the pom.xml triggers the code generator which then generates all the api/* modules. By the time I run maven clean install within the folder build/, the api folder is empty, because it will be filled by the code generator in the generate-code Maven phase.
Is there a way to tell the build/pom.xml to handle the modules inside api (the names are known) within the same build?
If I specify a <module> which does not exist, maven verify will complain.
Thanks
I believe the resolution depends on flexibility of the API's list
if the list of API-modules is dynamic, it's simply not possible to declare a dependency on a particular module - nobody knows them in advance. I would consider generation of source folders and adding them to a single module. As the result, you'll have single all-in-one module, which will contain all generated and compiled code. Other projects can use it as dependency
if the list of API-modules is fixed, their POM files, which declare GAVs, should not be generated. Then other projects can use any of them as dependencies, although their code is generated only during the build
If it was my Project, I would declare the references to the modules static in the pom (modules/ module-api-1 module-api-2 ...) and also have the module-Projects in a generated state so it theoretically could compile without generating the apis. So what I'm saying is - just treat these modules as full fledged module projects.
Then and I assume this is important for you, if you have a Change in the code that causes a Change in one or more apis, i would run the Generator. If you need to reflect this changed api in a repo, you can still just install the changed module.
I know this propably isnt what you wanted to do, but I'm pretty sure you'll have less Problems taking "the conservative way".

Maven dependency vs multimodule?

Very new to Maven, can someone please explain to me the difference between using maven modules vs just adding a dependency to your maven project to another maven project in your workspace? When would you use one over the other?
A dependency is a pre-built entity. You get the artifact for that dependency from Maven Central (or Nexus or the like.) It is common to use dependencies for code that belongs to other teams or projects. For example, suppose you need a CSV library in Android. You'd pull it as a dependency.
A Maven module gets built just like your project does. It is common to use Maven modules for components that the project owns. For example, maybe your project creates three jar files.
A dependency can be thought of as a lib/jar (aka Artifact in Maven parlance) that you need to use for building and/or running your code.
This artifact can either be built by your one of the modules of your multi module project or a third party pre-build library (for example log4j).
One of the concepts of maven is that each module is going to output a single artifact (say a jar). So in case of a complex project it is good idea to split your project to multiple modules. And these modules can be dependent on each other via declared dependencies.
See http://books.sonatype.com/mvnex-book/reference/multimodule-sect-intro.html for example of how a web app is split to parent and child modules and how they are linked.
One of the most confusing aspects of Maven is the fact that the parent pom can act as both a parent and as an aggregator.
99% of the functionality you think about in Maven is the parent pom aspect, where you inherit things like repositories, plugins, and most importantly, dependencies.
Dependencies are hard, tangible relationships between your libs that are evaluated during each build. If you think of your software as a meal, it's basically saying A requires ingredient B.
So let's say you're preparing lasagne. Then your dependency chain would look something like this:
lasagne
<- meatSauce
<- groundBeef
<- tomatoPaste
<- cheese
<- noodles
The key thing is, each of the above items (meatSause, groundBeef, cheese, etc) are individual builds that have their individual set of dependencies.
By contrast, the only section of your pom that pertains to aggregation is the modules section:
<modules>
<module>meatSauce</module>
<module>groundBeef</module>
<module>tomatoPaste</module>
<module>cheese</module>
<module>noodles</module>
</modules>
Aggregation simply tells your build engine that it should run these 5 builds in rapid succession:
groundBeef -> tomatoPaste -> cheese -> noodles -> meatSauce
The main benefit of aggregation is the convenience (just click build once) and ensuring the builds are in the correct order (e.g. you wouldn't want to build meatSauce before tomatoPaste).
Here's the thing though: even if you organize the libs as standalone projects without module aggregation, your build will still come out the same provided you build in the correct order.
Moreover, both Jenkins and Eclipse have mechanisms for triggering builds if a dependent project has changed (e.g. changing groundBeef will automatically trigger meatSauce).
Therefore if you're building out of Jenkins or Eclipse, there is no need for aggregation

Adding a set of dependencies in maven

I have read how to take a jar file that I have and add it to the dependency system in maven in this link
But what i want is, I have a set of 30 to 40 jar files that I have to add to the dependency system. Do i need to add all the jar files by using the
mvn install:install-file -DgroupId=com.stackoverflow... -DartifactId=yourartifactid... -Dversion=1.0 -Dpackaging=jar -Dfile=/path/to/jarfile,
followed by,
2.
<dependencies>
...
<dependency>
<groupId>com.stackoverflow...</groupId>
<artifactId>artifactId...</artifactId>
<version>1.0</version>
</dependency>
...
</dependencies>
or is there a simple way by which i can wrap up all the dependent jar files into one maven project using mvn:install, to which my main project can be made dependent?
Thanks in advance.
If most of the 30-40 jar files you are referring to are standard open source libraries, then you would not need to install them to your local repository manually. It is also possible that many of them are transitive, i.e. one dependency in turn pulling in another. In this case, you would need to only add as dependency the primary dependencies. This will in turn pull in the transitive ones.
If most of the dependencies are proprietary and you manage them yourself, then chances are you have them in your source code management system in some specific folder, say lib. If so, you can skip the install step and just specify dependencies using <system> scope (refer here).
You could define a single maven project (as pom type) to specify all the dependencies and have your main project dependant on it, if that simplifies things.
The first answer in this link really solved my doubt..
"Projects should explicitly list all their dependencies and not rely on inheriting them (IMHO). It means you have to declare your logger a few times but it will save you pain later. (You can of course use a separate POM project to group together dependencies that are related and hence usually specified together, like the hibernate example in your link). If you want to centralize versions of dependencies, you can put a dependencyManagement section in the parent POM, which means you still declare the dependency in the child project, but the version comes from the parent, thus ensuring consistency. Children that don't declare the dependency don't end up with it at all."
So the practice should be to create separate POM (Child) project for all the dependencies, and if we want, we can wrap them up using aggregation to a Parent-POM which can be referred singly in our project. But we have to however create a child project separately for each dependent JAR. Bit time taking process, but seems to be the only answer.

Resources