Maven build order - maven

I have a multi-module maven build and I need one particular module (lets call it project-A) to be build at the end. It depends on a module (lets call it project-B) that holds native code that gets compiled to a dll and installed into the maven repository as a zip file using some maven trickery. As it doesn't depends on it directly because the native code is not a java jar, I use Maven Dependency Plugin to unpack the zip file and place the native dll in my build directory. Everything is working fine except for the building order. It builds first project-A in spite of being declared the other way around in the tag in the parent. I would like to tell maven that project-A depends on project-B. I tried to add project-B as a dependency, but as it builds no jar it throws an ERROR, also this seemed hacky to me. Any help would be appreciated.

Just declare dependency in project A to project B and it will work fine. It does not matter if the project B is a native rather than a java project. Just make sure you declare the dependency correctly taking the packaging into account as type.. (which is probably pom so you would have
<dependency>
<groupId>...</groupId>
<artifactId>B</artifactId>
<version>...</version>
<type>pom</type>
</dependency>
in Project A)

The order in which you specify the modules in the parent Pom is also relevant. Maven actually builds in this order unless it has to build a module out of sequence due to direct dependencies.

Related

include jar of one module to another

I have maven projet with this architecture:
++parent-project
+module-a
+module-b
module-b is a web application. it will be run on Jboss AS 7.1.1. I'm using netbeans IDE.
Now module-b depend on module-a. this is a porm section of module-b:
<dependency>
<groupId>groupid</groupId>
<artifactId>module-a</artifactId>
<scope>compile</scope>
</dependency>
When i build the war file of module-b, module-a is not present to lib folder ( in war file. i open it with archive explorer ). therefore JBoss return ClassNotFoundException.
I'm tried differends scope ( compile , provided , runtime , test ). But nothing.
Please how can i solve this.
First of all, I think you should try to see how does it work in "pure" maven, without the IDE at all (NetBeans). So my answer will be based only on maven knowledge:
A couple of facts:
Module b has to have the following in pom: <packaging>war</packaging> This will instruct maven that you really want to get a war from this module.
When packaging WAR is specified in some pom, maven will take all the dependencies defined in this pom and will put them into the WEB-INF/lib folder of the war. Automatically. Of course, you can customize the output, but its more advanced stuff (see Maven WAR plugin if required)
All the dependencies have to be defined with group id, artifact id, and version at least. So make sure that you have the dependency on module a with version. There is no need to fiddle with scopes in this case. The default scope (if you don't specify a scope at all) is 'compile' which is fine.
Go to the directory of module b and from within the directory type: mvn dependency:tree. Once its done, please carefully observe the output, especially make sure that module a is listed (with a correct version) in a tree.
Sometime to make sure that no stale artifacts reside in the local m2 repository you might want to delete all the jars of your project from there and then execute the mvn package command again. The war has to be created in module b/target - and this is the WAR you should check out.
Note, all these steps are done without any interaction with NetBeans at all.

maven project dependency is a generated jar (not in maven repo)

I am a maven newbie. My project depends on another maven project (ProjectA) in that I need to run mvn clean package on ProjectA which gives me JarA.
Then, I need to run java JarA feeding it with an xml configuration file which gives me another JarB. I need both JarA and JarB as dependencies on my project (ProjectB).
Any comments on whether it is possible to achieve these steps in projectB's pom file? Would having parent-submodule type of a configuration help? Thanks!
Maybe. The most simple solution to get JarB would be to add a unit test to project A. But that doesn't tell Maven about this JAR, so it will ignore it.
The next step would be to get the test to write JarB as JarA-config into the target/ folder of project A. Maven supports multiple artifacts as "build results". You can then use the "qualifier" to distinguish between them.
Use build-helper:attach-artifact to tell Maven about the second JAR. See "Attach additional artifacts to your project" for an example.
Note that package happens after test, so your test case can create the second JAR and build-helper will then find it.
In project B, you can then use this to depend on both JARs
<dependency>
<groupId>x</groupId>
<artifactId>jarA</artifactId>
</dependency>
<dependency>
<groupId>x</groupId>
<artifactId>jarA</artifactId>
<classifier>config</classifier>
</dependency>
Note the additional <classifier> element.
Note: For this to work, you need to run mvn install in project A.

Using maven and Intellij IDEA, how can I modify a dependency without needing to manually install it every time?

I'm using Intellij-IDEA 11. If there's a solution that works in 12, I'd be willing to upgrade for that.
I built a library that many projects depend on but the library changes often. This library is added to my project's pom.xml as a normal dependency:
<dependency>
<groupId>my.company</groupId>
<artifactId>MyLibrary</artifactId>
</dependency>
This is a typical series of steps I need to take when I add a feature to my project:
Modify some code in my project
Modify some code in the library I depend on
Check to see if the feature works
If not, repeat
Outside of my IDE (which happens to be Intellij-IDEA), this is a straight forward process: I add step 2.5 which is to cd into the dependency's project folder and then mvn install the library.
But I don't know a convenient way to do this in Intellij-IDEA. Ideally, I'd modify the source of the library inside Intellij, click the green play button and the IDE would figure out to use the modified sources of the library.
Right now, since the library is a dependency, it just uses what's already in my local repo. So modifying the source of the library doesn't have an affect until I manually mvn install it.
Note: I've figured out a trick that seems to work. If I modify the project's parent pom to include the library as a maven module and then include the same library as an intellij module, it uses that source instead of the jar in my local repo. But I don't like this solution because I'd never want to commit that modified pom (because the module has to point to a file system path that only exists on my local file system).
I've found a bug in the Intellij-IDEA bug tracker that seems to relate to this: http://youtrack.jetbrains.com/issue/IDEA-25146
I found out a way to do this. First, you add the library's pom.xml in the Maven Projects tool window. Then you Edit your configurations so that they run the install goal of your library. And image of how to do this is provided below.
Click here for a full sized link
Open module setting (F4 on a module), go to Modules, select the dependencies tab in module that depepends on your library.
If the library is a module add a module dependency
If the library isn't a module, I assume it gets built and put somewhere, add that directory to the module dependencies.
The higher up the list the higher its priority
I've similar architecture and here is what I do (and it works very well).
Create an IDEA maven project based on the pom.xml of my main project (the project using the frequently changing library).
Add maven project to my main project (click on the "+" icon in the maven projects tab and choose the pom.xml of my frequently changing library)
EDIT
note: all the modules (from the library and from the main project) have a *-SNAPSHOT version
In more details, the pom.xml of my library project :
<groupId>com.company</groupId>
<artifactId>mylibrary</artifactId>
<version>2.0.1-SNAPSHOT</version>
And the pom.xml of my main project
<groupId>com.company</groupId>
<artifactId>myproject</artifactId>
<version>1.1-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>com.company</groupId>
<artifactId>mylibrary</artifactId>
<version>2.0.1-SNAPSHOT</version>
</dependency>
</dependencies>
I think that IDEA is smart enough to see that the dependency is a SNAPSHOT and that this library is in the current IDEA project (i.e. same IDEA window)... and so IDEA don't look in the local repo since the SNAPSHOT is in the current "workspace".
Hope it clarify the situation.
If I need to run something, I have different options either
defining a new maven run configuration in IDEA to run any maven goal (from any pom.xml in my IDEA project) with any profile.
defining a simple unit test configuration in IDEA (not directly linked with maven except that the classpath is derived from the classpath defined in pom.xml)
defining a new Tomcat/JBoss configuration in IDEA and deploying some artifact in it. (IDEA detect deployable artifacts -like war or ejb- from the pom.xml)
I have the same scenario than you and I am using Intellij 2016.02.
Here is how I solved it:
1 - On Intellij open the maven panel going to View -> Tool Windows -> Maven Projects, then click at the plus green button (add maven project) and select the pom.xml file from the dependency project
2 - On Run/Debug configuration settings, add a before launch task as a maven goal, choosing the Working Directory of the dependency project and in command line just type "install".
3 - Now edit anything in your dependency project, and redeploy your main application, and the changes may affect.
EDITED:
I found a new solution, and it's solved the "update classes and resources" downside, here is what I did:
1 - Do the first step from the previous solution, but remove the install goal from before launch task if you add it on step 2.
2 - Edit the exploded artifact, and add the dependency project "compiled output" element from "Available elements" panel to output left panel.
Changes may work without need to install, and now my "Update classes and resources" works like a charm :)

Maven Assembly plugin. Any way to unzip/untar an archive straight from the descriptor file, rather than relying on antrun plugin?

I'm using maven assembly plugin version 2.2.1 to build a package in a custom, proprietary format.
As a part of this process, I need to extract a bunch of external archives (by external I mean they are not listed as maven dependencies, but they are arbitrary files on the filesystem).
Do you know if maven assembly is able to do that ? I've looked and apparently, it is able to extract a bunch of dependencies in an arbitrary folder, but it is unable to extract an external archive.
Using the <unpack>true</unpack> in your <dependencySet> is the way to go.
External archives are not supported by Maven. So you will need to attach them using, e.g. build-helper:attach-artifact then you can reference it via the <dependencySet>
Update
One of the comments wanted to know how you could avoid installing the attached artifact into the maven repository (local/remote)
The solution to that is to use a dummy module that is a non-transitive dependency.
We are relying on the assembly being built not being used as a transitive dependency.
So you start with a dummy module, which will look a little something like
<project>
...
<packaging>pom</packaging>
...
<properties>
<maven.deploy.skip>true</maven.deploy.skip>
<maven.install.skip>true</maven.install.skip>
<!-- or you could override the plugin configuration for a safer - but less quick - solution -->
</properties>
...
</project>
That dummy module can attach the files using build-helper:attach-artifacts
The your assembly module will just list the dependencies with <scope>provided</scope> and <optional>true</optional> as a guard against becoming transitive dependencies. (not necessary if the assembly is say the installer bundle and will not be consumed by other Maven builds.
And there you go, the compressed content will be streamed from one archive to the other and the raw file will not be copied to the remote repo... but you will always need to build the hack module in any reactor that builds the assembly.
"arbitrary files on the filesystem" does not mean much, from maven point of view.
You should be able to run your maven pom from any point "your machine", "the integration server (jenkins...)". Ant is a tool for "home made" build, maven promotes convention over configuration, and reusability.
Therefore, any resources your project depend on should be either a dependency, or somehow included in your project .
I expect all my projects to be buildable as id, with a simple svn check out. Anything that is not in the project should be downloaded from mvn repositories.
So When I have to write an assembly project, I make sure everything is available in the project, as resources. If not, you can always build a simple project/pom for shared resources, or use some special plugins that do that for you.

Why does maven recognize dependencies on only installed POM files?

I've got a project with Maven in which one subproject (A) wants to depend on another subproject (B) which uses "pom" packaging.
If I do this the straightforward way, where A specifies a dependency on B with <type>pom</type>, things work perfectly if I do "mvn install", but if I run any phase earlier than install, such as mvn compile or mvn package, then it fails while trying to build A: it goes looking for B's pom in the repository, and doesn't find it.
I don't really want this pom in the repository, because it's part of our active source code and changes frequently.
For all the jar-packaged projects we build, it seems to work fine to keep them out of the repository, build with mvn package, and Maven knows how to find all the dependencies in the source and build trees it manages without resorting to the repository; however for the pom-packaged project it always wants to go to the repository.
A couple things I learned while trying to understand this:
Maven best practices encourage you to use pom-packaged projects to group dependencies, but with the added step of "mvn install" on the POM project
Maven lifecycle documentation says "a project that is purely metadata (packaging value is pom) only binds goals to the install and deploy phases"; maybe this is why the POM project is invisible as a dependency target unless I invoke the install phase? I tried binding the compiler plugin to the compile phase and this didn't seem to help.
Is there a way that I can specify the POM subproject as a dependency of another subproject in the same parent project, without installing the POM project to the repository?
It isn't purely a question of which goals are bound to which lifecycle phases for POM projects. If it were, then binding the "package" goal would solve the problem.
When building a multi-module project, Maven reads the POMs of all modules to determine dependencies between modules, so that it can build the depended-upon modules before the depending modules. It's able to achieve this even when running the "package" goal (such that the depended-upon modules are not yet in the local repository).
Therefore, the code that constructs the classpath for builds must be managing several cases, notably:
extra-project jar dependency, where it looks for the POM in the local repository, handles its dependencies, and adds the POM's jar to the classpath
extra-project pom dependency, where it looks for the POM in the local repository and handles its dependencies
intra-project jar dependency, where it looks for the POM within the project tree, handles its dependencies, and adds that module's target/classes folder to the classpath
intra-project pom dependency, where for some reason it doesn't look for the POM within the project tree, and therefore doesn't handle it's dependencies.
Notice the asymmetry in the last two cases, as compared to the first two.
I can see two solutions to your problem. One is to file a bug report, or rather a request to change the behaviour (since it's obviously intentional), perhaps only for the case of intra-project dependencies on multi-module projects. Or indeed propose a patch. But since the behaviour is intentional, you might meet a refusal. In the best of cases, you're in for a long wait. (I'd vote for your bug report though - I've been stung by that same behaviour, in a different context.)
The other solution is simply to run an install on your project. I don't really understand why you don't want the POM project in your repository: if needs be, you can use a snapshot repository, where it doesn't matter if things change frequently, to avoid polluting your main repository.
Configuring maven-install-plugin to run during the compile phase, and copy the relevant pom.xml to the repository, seems to accomplish what I wanted as far as Maven itself is concerned, though m2eclipse still is not happy (it throws "failed to read artifact descriptor" errors with no additional description for the pom.xml that has a dependency on the other POM project).

Resources