Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Augmenting instead of overriding Maven configuration

Tags:

I saw this question and it motivated me to look again (without success) at Maven configurations for an alternative way of declaring configuration so it is appended to the parent POM's config instead of overriding it. In a Maven POM, if configuration declares the same elements as in the parent it overrides the parents configuration. As the accepted answer to the other question says, this is the expected behaviour.

But this is not always the desired behaviour. Should there be/is there a means in Maven to add to rather than override configuration?

For example: - Provide ability to declare elements of the configuration final, so that children can add to them but not replace? - Allow child configuration to declare element as an addition, so it is merged with the parent


A good example of when the override behaviour is not always desirable is for the aspectLibraries element of the aspectj-maven-plugin.

In my parent POM I define a configuration for the aspectj plugin that declares a tracing jar to be used as an aspectLibrary.

 <plugin>
   <groupId>org.codehaus.mojo</groupId>
   <artifactId>aspectj-maven-plugin</artifactId>
   <executions>
     <execution>
     <id>compile_with_aspectj</id>
       <goals>
         <goal>compile</goal>
       </goals>
     </execution>
   </executions>
   <configuration>
     <aspectLibraries>
       <aspectLibrary>
         <groupId>name.seller.rich</groupId>
         <artifactId>tracing</artifactId>
       </aspectLibrary>
     </aspectLibraries>
   </configuration>
   <dependencies>
     <dependency>
       <groupId>aspectj</groupId>
       <artifactId>aspectjtools</artifactId>
       <version>1.5.3</version>
     </dependency>
   </dependencies>
</plugin>

This is inherited by all the child projects and I get tracing in all the projects, which is nice. However if I define another aspectLibrary in a child POM, it replaces my tracing configuration.

Note I have a workaround to this particular problem, I'm interested in the general case and implications for Maven.

The simple answer would be to redeclare the configuration for the tracing jar in the child POM as well as the new jar, but this has maintenance implications, and if I want to declare the tracing configuration in a profile so it can be disabled if needed (which I do), I then need to reimplement the profile in the child.

The dependency declaration in the above sample is merged with other dependency declarations in the parent and elsewhere. I know dependencies are a special case, but it shows that it is feasible to implement.

like image 338
Rich Seller Avatar asked Jul 09 '09 07:07

Rich Seller


2 Answers

This was explained in a blog post by Sonatype.

In the parent pom, specify

<configuration>
  <aspectLibraries combine.children="append">
    <aspectLibrary>
      <groupId>name.seller.rich</groupId>
      <artifactId>tracing</artifactId>
    </aspectLibrary>
  </aspectLibraries>
</configuration>

In general, the configuration elements of children will override those specified in the parent for any given plugin. This keeps things simple by default: a fully-configured child would use exactly the configuration in its pom. However, the parent can enforce that lists should be extended instead of replaced by using the combine.children="append" setting on the desired configuration elements.

like image 157
Zac Thompson Avatar answered Oct 27 '22 05:10

Zac Thompson


I need to test this so let me get back to you on this, but I think the correct way to do this is to use properties, as noted here. In your case the code would look as follows:

<properties>
  <aspect.library.groupId>name.seller.rich</aspect.library.groupId>
  <aspect.library.artifactId>tracing</aspect.library.artifactId>
</properties>

<plugin>
   <groupId>org.codehaus.mojo</groupId>
   <artifactId>aspectj-maven-plugin</artifactId>
   <executions>
     <execution>
     <id>compile_with_aspectj</id>
       <goals>
         <goal>compile</goal>
       </goals>
     </execution>
   </executions>
   <configuration>
     <aspectLibraries>
       <aspectLibrary>
         <groupId>${aspect.library.groupId}</groupId>
         <artifactId>${aspect.library.artifactId}</artifactId>
       </aspectLibrary>
     </aspectLibraries>
   </configuration>
   <dependencies>
     <dependency>
       <groupId>aspectj</groupId>
       <artifactId>aspectjtools</artifactId>
       <version>1.5.3</version>
     </dependency>
   </dependencies>
</plugin>

Then in the child you would be able to change those properties, and the parent would automatically pick up the new values:

<properties>
  <aspect.library.groupId>name.seller.rich</aspect.library.groupId>
  <aspect.library.artifactId>something-else</aspect.library.artifactId>
</properties>

I think you may be asking for the ability to append configuration, however, so as to have an additional node in your child's configuration ontop of the one specified in your parent. For that case I can't think of an obvious solution.

like image 35
toluju Avatar answered Oct 27 '22 05:10

toluju