Embedding Maven

It is a very rare usecase, but sometimes you need it. How to embed Maven in your application, so that you can programatically run goals?

Short answer is: it’s tricky. I dabbled into the matter for my java webapp automatic syncing project, and at some point I decided not to embed it. Ultimately, I used a library that does what I needed, but anyway, here are the steps and tools that might be helpful.

What you usually need the embedded maven for, is to execute some goals on a maven project. There are two scenarios.

The first one is, if you are running inside the maven container, i.e. you are writing a mojo/plugin. Then it’s fairly easy, because you have everything managed by the already-initialized plexus container. In that case you can use the mojo-executor. Easy to use, but expects a “project”, “pluginManager” and “session”, which you can’t easily obtain.

The second scenario is completely embedded maven. There is a library that does what I needed it to do (thanks to MariuszS for pointing it out) – it’s Maven Embedder. Its usage is described in this SO question. Use both the first and the second answer.

Before finding that library, I tried two more libraries: the jenkins maven embedded and the Maven Invoker. The problem in both libraries is: they need a maven home. That is, the path to where a maven installation resides. Which is kind of contrary to the idea of “embedded” maven. If the Maven Embedder suits you, you can stop reading. However, there might be cases where the Maven Embedder might not be what you are looking for. In that case, you should use one of the two aforementioned libraries. So, how to find and set a maven home?

  • Ask the user to specify it. Not too much of a hassle, probably
  • Use M2_HOME. One of the libraries uses that by default, but the problem is it might not be set. I don’t usually set it, for example. If it is not, you can fallback to the previous approach
  • Scan the entire file system for a maven installation – sounds ok, and it can be done only once, and then stored in some entry. The problem is – there might not be a maven installation. Even if it’s a developer’s machine – IDEs (Eclipse, at least) have an “embedded” maven. And while it probably stores it somewhere internally in the same format a manual installation would, it may change it’s path or structure depending on the version. You can, of course, re-scan the file tree every once in a while to find such an installation
  • Download Maven programatically yourself. Then you can be sure where it is located and that it will always be located there in the same format. The problem here is version mismatch – the user might be using another version of maven. Making the version configurable is an option.

All of these work in some cases, and don’t work in others.

So, in order of preference: 1. make sure you really need to embed maven 2. use the Maven Embedder 3. use another option with its implications.

It is a very rare usecase, but sometimes you need it. How to embed Maven in your application, so that you can programatically run goals?

Short answer is: it’s tricky. I dabbled into the matter for my java webapp automatic syncing project, and at some point I decided not to embed it. Ultimately, I used a library that does what I needed, but anyway, here are the steps and tools that might be helpful.

What you usually need the embedded maven for, is to execute some goals on a maven project. There are two scenarios.

The first one is, if you are running inside the maven container, i.e. you are writing a mojo/plugin. Then it’s fairly easy, because you have everything managed by the already-initialized plexus container. In that case you can use the mojo-executor. Easy to use, but expects a “project”, “pluginManager” and “session”, which you can’t easily obtain.

The second scenario is completely embedded maven. There is a library that does what I needed it to do (thanks to MariuszS for pointing it out) – it’s Maven Embedder. Its usage is described in this SO question. Use both the first and the second answer.

Before finding that library, I tried two more libraries: the jenkins maven embedded and the Maven Invoker. The problem in both libraries is: they need a maven home. That is, the path to where a maven installation resides. Which is kind of contrary to the idea of “embedded” maven. If the Maven Embedder suits you, you can stop reading. However, there might be cases where the Maven Embedder might not be what you are looking for. In that case, you should use one of the two aforementioned libraries. So, how to find and set a maven home?

  • Ask the user to specify it. Not too much of a hassle, probably
  • Use M2_HOME. One of the libraries uses that by default, but the problem is it might not be set. I don’t usually set it, for example. If it is not, you can fallback to the previous approach
  • Scan the entire file system for a maven installation – sounds ok, and it can be done only once, and then stored in some entry. The problem is – there might not be a maven installation. Even if it’s a developer’s machine – IDEs (Eclipse, at least) have an “embedded” maven. And while it probably stores it somewhere internally in the same format a manual installation would, it may change it’s path or structure depending on the version. You can, of course, re-scan the file tree every once in a while to find such an installation
  • Download Maven programatically yourself. Then you can be sure where it is located and that it will always be located there in the same format. The problem here is version mismatch – the user might be using another version of maven. Making the version configurable is an option.

All of these work in some cases, and don’t work in others.

So, in order of preference: 1. make sure you really need to embed maven 2. use the Maven Embedder 3. use another option with its implications.