28

Scenario:

  1. Given
    1. Parent POM which defines a profile and a child (as module)
    2. Child project(s) that will be using the profile by referring to the parent POM.
  2. The intent is to skip profile execution in the parent and execute it in the child only
  3. Profile has activation section <activation><property><name>foo</name></property><activation>
  4. Since parent does not define foo property - the profile is inactive and will not be executed for the parent build
  5. Now, I'm defining <properties><foo>true</foo></properties> in the child with hope that the property will be picked up when child build is executed and profile will be activated. No such luck. Profile is never activated, which tells me that property is never set.
  6. Just to note: mvn package -Dfoo=true activates profile in both parent and child

Am I trying to do the impossible or just doing it wrong?

P.S. Hmmm - even if I define property in the parent, the profile is not triggered. What gives?

Rich Seller
  • 83,208
  • 23
  • 172
  • 177
Bostone
  • 36,858
  • 39
  • 167
  • 227

3 Answers3

10

To expand on @rich-seller's answer, and @Bostone's self-answer, it seems to be impossible to have a setup where the parent POM defines a few profiles as alternatives, and child POMs select one of these profiles by default, while allowing you to override the choice for a child temporarily (i.e. on the CLI). Consider a parent POM for projects which use some framework and an associated plugin, both of whose versions we can assume are defined by properties:

<profiles>
  <profile>
    <id>newest</id>
    <activation>
      <activeByDefault>true</activeByDefault>
    </activation>
    <properties>
      <framework.version>2.0</framework.version>
      <plugin.version>2.0</plugin.version>
    </properties>
  </profile>
  <profile>
    <id>older</id>
    <activation>
      <property>
        <name>older.framework</name>
        <value>true</value>
      </property>
    </activation>
    <properties>
      <framework.version>1.1</framework.version>
      <plugin.version>1.1</plugin.version>
    </properties>
  </profile>
</profiles>

Now a child inheriting from this parent POM by default will use 2.0 as you would expect, and -Polder or -Dolder.framework=true will work to try building it with the older framework (e.g. to test compatibility). However you cannot write in the child POM

<properties>
  <older.framework>true</older.framework>
</properties>

and have the older profile be activated automatically. You could use file-based activation to make this module build against 1.1 if newest were not active by default, but then it is not easy to temporarily run it against 2.0: as far as I know both older and newest profiles would be active if you passed -Pnewest, so you need to explicitly disable other profiles which is unreasonable if you have a dozen of them. So there is just no solution except to copy the profile information to the child POM:

<properties>
  <framework.version>1.1</framework.version>
  <plugin.version>1.1</plugin.version>
</properties>

at which point -Pnewest will not work to override these properties, so you need to use -Dframework.version=2.0 -Dplugin.version=2.0.

In other words, the profiles are only useful if all the child modules can use the same profile (here newest) by default. If some of them are normally built with 1.1 and some with 2.0, the profiles are useless.

Seems like this is a use case for a Maven core enhancement, or perhaps a Maven 3 build extension. http://docs.codehaus.org/display/MAVEN/Custom+Profile+Activators and https://github.com/maoo/maven-tiles come to mind.

Jesse Glick
  • 24,539
  • 10
  • 90
  • 112
  • Yep. I'm accepting this since it builds on my answer and I generally don't like to accept my own – Bostone Aug 31 '12 at 17:04
  • Very useful info. And thanks for the tip about file-based activation; that solved my issue very cleanly. – Allan Nov 30 '12 at 17:27
7

The profile can only be activated by properties passed from the command line. This is because properties in the POM can only be processed once the POM has been parsed, at which point it is too late to resolve the profile activation.

You're in a bit of a catch-22 with this approach unless you are able to pass the property from the command line, specify profile activation in your settings.xml (generally not a great idea), or use the workaround in my previous answer to use the presence of a marker file.

One final alternative if you're on Maven 2.1.0+ is to deactivate the profile via the command line for the parent POM only, this is still obviously not ideal.

You can deactivate a profile with either the character '!' or '-' like this:

mvn install -P !profile-1,!profile-2
Community
  • 1
  • 1
Rich Seller
  • 83,208
  • 23
  • 172
  • 177
  • I was afraid so. It actually seems that execution of profile is set and cannot be changed after build is started (even with the marker file). With deactivation what are these -1 and -2 are referring to? If I have parent and child and profile "build" will the following suppose to cancel profile on parent? (In my tests it's not) `mvn install -P !buiild-1` – Bostone Oct 01 '09 at 20:42
  • I don't get it exactly. Why don't the `` or `` profile triggers work for you? – Pascal Thivent Oct 01 '09 at 22:29
  • the example is to deactivate two profiles called `profile-1` and `profile-2`, there is no special significance to the `-1` or `-2`. In your case it would simply be `mvn install -P !build` – Rich Seller Oct 02 '09 at 13:29
  • But that would deactivate the whole profile and it will not be execute nether on parent nor on child? Or am I missing something? – Bostone Oct 02 '09 at 15:18
  • You would only pass the argument to the build of the parent project so the profile would not be active when the parent is installed/deployed. The profile would however be in the installed pom, so that when a child is built the profile is inherited and active (assuming you don't explicitly deactivate it with the argument) – Rich Seller Oct 02 '09 at 15:23
  • I don't know what's wrong with me but I cannot visualize what you describing. I'm passing argument on command line - right? That will start the build and disable profile so it will not be executed in parent. However - when in the next step the child is build, that profile will still be disabled and that's exactly what I experience. Sorry for being so persistent but I want to get to the bottom of this, can you maybe post an example? – Bostone Oct 02 '09 at 19:47
  • Sorry I see your problem now, it won't work in a reactor build as the properties are defined at the build level so will be applied for all builds in the reactor. I don't see a way to resolve this unless you make your parent not specify the child as a module and instead use a separate aggregator pom – Rich Seller Oct 02 '09 at 20:28
  • Bummer. Does that that apply to "missing file" trick as well? – Bostone Oct 02 '09 at 21:06
  • no, the the file is checked within each project, in each project it either exists or it is missing, so you can control the profile activations that way – Rich Seller Oct 02 '09 at 21:28
  • I couldn't make it work with file. Same behavior as with property. Pardon a silly question but did you actually run it and verified that it is working? I would love to see that code – Bostone Oct 03 '09 at 18:52
7

To directly answer my own question: in multi-module build all properties are set before build is run so it is impossible to activate/deactivate profile in one of the modules during the build based on setting the propety in the child POM. However if you are looking for way of doing it by using other means please read this comment

Community
  • 1
  • 1
Bostone
  • 36,858
  • 39
  • 167
  • 227