Response to Maven Problems on the JBoss Wiki, Part Three

December 06, 2009 By Brian Fox

5 minute read time

In parts one and two of this series, I addressed several concerns raised on the Jboss wiki. In this post, I address several more topics.

No separation of build instructions vs. general project information

both the set of build instructions (lifecycle) and general information about the project and dependency information. IMO this is a flawed model. Instead of having a single file, there should be some separation between the build instructions and the project information needed in the repository....When a POM is used as a dependency (not a parent) from the repository only certain information is useful to the calling project. Information like the project identifiers (groupId, artifactId), general project information (name, description, scm, etc). Other information is ignored: everything in the build and reporting sections, the distributionManagement...

I've had the same thoughts recently as we begin to think about dealing with POM model changes. Many of the changes we would want to make specifically only apply to the <build> section. Having separate files for this information is one way to solve the model / parsing problem, but it doesn't solve it completely, since we also want to extend things in the dependency section like scope, global excludes, etc.

In hindsight, the separation may have made our work today easier, but separating it now doesn't push us forward in a meaningful way by itself, and now we have history and convention to consider.

If a POM is used in a parent/child relationship, then the this information will be used. The problem with the parent/child model that Maven uses, is that build information can only be picked up from a single source. This means that I can't get some build configuration from one POM and other information from another.

Yep, I addressed this in part one, but in Maven 3.x we will support the concept of "mixins" which is a way to introduce composition to the pom. This will completely solve this concern.

The project configuration (POM) used locally is not necessarily the same as what should be released/deployed. For example, in a local build configuration we might want to avoid using a specific version of a dependency and instead just let the dependency resolver get the latest released version. In the repository however, the released and/or deployed POM should always specify the version of the dependency that was used during the build. Maven recently has some workarounds for this problem such as the versions-maven-plugin which helps to keep dependency versions up to date, but the problem still exists that I have to manually use this plugin to update the dependencies. In an ideal build tool, this functionality would be automatic.

I tend to agree here as well. I've spent quite a bit of time considering how to deal with this recently, but every time I think it's figured out, I find a reason it won't work.

The implication here is that in your build you define a version of some dependency, let's choose a range like anything between 1.0 and 2.0 not including 2.0 ( that would be [1.0,2.0) in the pom) . At the time I build my module, I resolve against 1.7 for some unimportant reason. My pom is deployed to the repository with a dependency version of "1.7". Life seems fine.

Someone else comes along and depends upon my JAR. He wants to use 2.1, since the deployed POM now says 1.7, my range information has been lost and Maven doesn't know that the developer has really said that it only works with 1.x.

In summary, replacing the requested version with the version resolved at build time results in a loss of fidelity that may affect consumers of my JAR.

One solution to this may be to include the resolved version alongside the requested version in the deployed POM, but we'd have to think through what the resolution strategy would do differently in this case.

No easy way to add plugin configurations to a lifecycle

An... example is the compile vs. test-compile goals, these two goals are the same logic with a slightly different configuration. Ant has a single compile task and compile vs. test-compile is just a different configuration of the same task.

It is technically possible for us to change the lifecycle configuration to allow the plugin config to be defined, and you're right this would allow some plugin goals to be collapsed down into one.

However, we would need to think through the implications of tying the config into the lifecycle when it comes to plugin versions. If the lifecycle defines some default configuration that changes between plugin versions, what happens when the user chooses that version in their pom?

Currently you almost never have to change a lifecycle, and you especially don't have to do it to support different plugin versions. I feel like linking the lifecycle and plugin this tightly would cause more problems than it solves.

After all, if you code your plugin correctly, making another goal with slightly different default parameters is a trivial endeavor.

Limited Access to the Build Lifecycle.

There is no simple way in Maven to add a new phase to the build lifecycle.

Absolutely and I think that's a benefit of Maven not a problem. If you have any Maven build, you can sit down and know immediately how to run tests, compile, package etc. You don't have to go read the build file to see if it's "clean-test, test-clean, jar, package" etc.

Every Maven build has the exact same set of targets and it should always stay that way.

No way to handle renamed artifacts and/or link two dependency resolution IDs

There are many situations where it would be useful to link two dependency IDs to tell Maven that the two IDs refer to the same artifact. For example when a dependency is moved to a new groupId, the old groupId/artifactId is treated as a completely separate artifact. The old groupId/artifactId must then be excluded from each location where it appears in the dependency tree. Maven should have a way to link these together and ignore any occurrences of the old groupId/artifactId.

This has always been supported with the relocation element. See:

Maven only allows a single source directory per project

In some cases it's useful to separate source code into multiple directories that have different compilation parameters. Unfortunately this is not allowed in Maven.

While it's true that the POM model only allows a single source directory in the POM, Maven internally supports as many source folders as you want.

Typically additional source folders are needed in cases where code is generated and you want to keep that separate from your code that needs to be in SCM. The plugin that does the generation is responsible for adding the additional folder directly into the model in memory.

The build-helper plugin has goals to allow you to attach arbitrary folders if you need them. Perhaps when we solve the POM model problem, we can consider allowing multiple source folders directly in the POM. It's probably already possible to do this with the polyglot stuff Jason has been working on.

Stay tuned for part 4 to see the conclusion.

Tags: Sonatype Says

Written by Brian Fox

Brian Fox is a software developer, innovator and entrepreneur. He is an active contributor within the open source development community, most prominently as a member of the Apache Software Foundation and former Chair of the Apache Maven project. As the CTO and co-founder of Sonatype, he is focused on building a platform for developers and DevOps professionals to build high-quality, secure applications with open source components.