Maven plugin configuration vs properties - java

What are pros and cons of configuring Maven plugins through properties as oppose to configuration?
For example, maven-compiler-plugin documentation explicitly shows configuring source and target as
shown below, presumably going even further with pluginManagement.
https://maven.apache.org/plugins/maven-compiler-plugin/examples/set-compiler-source-and-target.html
<project>
[...]
<build>
[...]
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.3</version>
<configuration>
<source>1.4</source>
<target>1.4</target>
</configuration>
</plugin>
</plugins>
[...]
</build>
[...]
</project>
Wouldn't it be more succinct to use user properties instead, with no dependency on specific version?
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>

First of all, many parameters of many goals do not have any associated user property, so can only be set via <configuration>.
For those which do have a user property (such as these examples), it depends. A few user properties are specifically coördinated between multiple goals or even plugins, as #khmarbaise points out.
User properties can be overridden from the command line, as #kdoteu points out, which is useful in certain cases—though very likely not for Java source/target level which would normally be intrinsic to the project (something you would change in a versioned commit alongside source file changes). User properties can also be overridden from external profiles such as in settings.xml, which is occasionally important.
On the other hand, plugin configuration is more explicit: it is expressly associated with a particular goal (or all goals in a plugin using the same parameter name). Some IDEs can offer code completion. You need not worry about accidentally having some other unrelated plugin interpret a property name (though plugin authors try to use unique-looking prefixes for most user property names). Surprisingly, Maven (3.8.1) will not fail the build if you mistype the parameter name, however—it will just quietly ignore the extra element.

You can influence the properties druing build time with commandline parameters. And you can use them in multimodule projects.
So wie are using them to configure findbugs or some urls for deploying.

There are some properties which are automatically taken by plugins. One for example are the given target/source information. An other is the project.build.sourceEncoding which is taken into account of several plugins like maven-compiler-plugin, maven-resources-plugin etc. So it makes sense to use properties which reduces the size and number of your configurations for plugins.

Related

Global changes to maven surefire plugin in .m2/settings.xml

I would like to change the default setting for maven-surefire-plugin, and instead of using <reportFormat>brief</reportFormat>, I would like to use <reportFormat>plain</reportFormat>.
Usually, I would achieve this by modifying an individual pom for a project, such as:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<redirectTestOutputToFile>true</redirectTestOutputToFile>
<reportFormat>plain</reportFormat>
</configuration>
</plugin>
However, is it possible to somehow modify ~/.m2/settings.xml file and set <reportFormat>plain</reportFormat> as a default behaviour for all maven projects I want to compile.
I do an analysis of many maven projects, so I would prefer to change the behaviour on global level rather than modifying pom files for each individual project.
The settings.xml configuration file doesn't go down at this level of detail. The plugin configuration can be specified only in the pom.xml
The best way to check it is studying the settings.xml schema :
https://maven.apache.org/xsd/settings-1.0.0.xsd
You could see that the single elements referencing the "plugin" word have no relation with the plugin configuration in the build.
For your requirement, the single solution that has also its drawbacks if bad used is using a parent pom that defines the plugin configuration and that all Maven modules should have as parent to inherit from the plugin configuration and potentially from other things.
If your applicative projets use a multi module/parent pom structure, I think that a nicer solution would be to declare this configuration in the parent pom of each multi module/parent pom.
In this way you declare it multiple times but a single time by set of related projects.

Maven Shade - add local JAR file [duplicate]

I already found an answer here on Stack Overflow how to include a 3rd party JAR in a project without installing it to a "local repository":
Can I add jars to maven 2 build classpath without installing them?
But, when I use the Maven Shade Plugin to create a JAR that includes all the dependencies of the project as well, the 3rd party JAR is not included automatically.
How can I make the Maven Shade Plugin add such a 3rd party JAR in to the shaded JAR?
As per the answer gotten, I made it work. What I did was, added this snippet to the beginning of my pom.xml:
<repositories>
<repository>
<id>repo</id>
<url>file://${basedir}/repo</url>
</repository>
</repositories>
Then added a dependency for my project, also to pom.xml:
<dependencies>
<dependency>
<groupId>dummy</groupId>
<artifactId>dummy</artifactId>
<version>0.0.0</version>
<scope>compile</scope>
</dependency>
</dependencies>
And then ran a command line to add a package to 'repo':
mvn org.apache.maven.plugins:maven-install-plugin:2.3.1:install-file
-Dfile=<my-jar>.jar -DgroupId=dummy -DartifactId=dummy
-Dversion=0.0.0 -Dpackaging=jar -DlocalRepositoryPath=`pwd`/repo/
(Not sure if the repo path needs to be a full path, but didn't want to take chances.)
The contents of the repo subdirectory is now:
repo/dummy/dummy/0.0.0/dummy-0.0.0.jar
repo/dummy/dummy/0.0.0/dummy-0.0.0.pom
repo/dummy/dummy/maven-metadata-local.xml
Now I can check this in to version control, and have no local or remote dependencies.
But, when I use the Maven Shade Plugin to create a JAR that includes all the dependencies of the project as well, the 3rd party JAR is not included automatically.
Yes, because the system scoped dependencies are assumed to be always present (this is exactly what the system scope is about) so they won't be included. People actually don't understand what system scope dependencies are, they just keep abusing them (yes, this is abuse), and then get side effects and wonder why (as Brian pointed out in his answer).
I already wrote many, many, really many times about this here on SO and in 99% of the cases, system scoped dependencies should be avoided. And I'll repeat what the Dependency Scopes mini guide says one more time:
system: This dependency is required in some phase of your project's lifecycle, but is system-specific. Use of this scope is discouraged: This is considered an "advanced" kind of feature and should only be used when you truly understand all the ramifications of its use, which can be extremely hard if not actually impossible to quantify. This scope by definition renders your build non-portable. It may be necessary in certain edge cases. The system scope includes the <systemPath> element which points to the physical location of this dependency on the local machine. It is thus used to refer to some artifact expected to be present on the given local machine an not in a repository; and whose path may vary machine-to-machine. The systemPath element can refer to environment variables in its path: ${JAVA_HOME} for instance.
So, instead of using the system scope, either:
Add your libraries to your local repository via install:install-file. This is a quick and dirty way to get things working, it might be an option if you're alone but it makes your build non portable.
Install and run an "enterprise repository" like Nexus, Archiva, or Artifactory and add your libraries via deploy:deploy-file. This is the ideal scenario.
Setup a file based repository as described in this previous answer and put your libraries in there. This is the best compromise if you don't have a corporate repository but need to work as a team and don't want to sacrifice portability.
Please, stop using the system scope.
The Maven addjars plugin solves this problem - see
http://code.google.com/p/addjars-maven-plugin/wiki/UsagePage
Used <resources> to include my lib with all jars. i.e:
<build>
<resources>
<resource>
<directory>${project.basedir}</directory>
<includes>
<include>lib/*.jar</include>
</includes>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.3</version>
<configuration>
<createDependencyReducedPom>false</createDependencyReducedPom>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
If you only need a quick and dirty solution, you can add the content of the extracted jar file to your src/main/resource directory.

Arranging Profiles and Plugins in pom.xml

I have these things in my pom.xml
profile1
profile2
These profiles are for separate build environment.
I need to make these plugins as common to both profiles.
plugin1
plugin2
plugin3
Where should I place these common plugins?
You can simply put them in the default build section. Since the plugins are common to both profiles: this the best way to do it.
Remark that if the configuration of plugins is slightly different for the different profiles you can use properties in the plugin configuration and define the values of those properties in the profile.
<build>
<plugins>
<plugin>
<groupId>someGroup</groupId>
<artifactId>plugin1</artifactId>
...
</plugin>
<plugin>
<groupId>someGroup</groupId>
<artifactId>plugin2</artifactId>
...
</plugin>
<plugin>
<groupId>someGroup</groupId>
<artifactId>plugin3</artifactId>
...
</plugin>
</plugins>
</build>
EDIT
Note that this solution will enable the plugins even when no profiles are activated. Not sure this what you need. (you maybe have a third build environment: for instance the developper computer where no profile are defined). In this case the solution of a third profile is the way to go.
mvn clean install -Pprofile1,profile-common
or
mvn clean install -Pprofile2, profile-common
and your common plugins defined in profile-common
You can have multiple profiles active at any given point of time. As such you can create a common profile( profile3) and keep the plugins there. The plugins/config which are dependent on specific profiles, can be kept in specific profile1 and profile2.
-P profile-1,profile-3

Implicit compilation in maven

With javac, it is possible to implicitly compile java files to class files from a particular source tree. In other words, it's possible to point at a given source tree and only compile the java files that are required by the explicitly mentioned java files. Is it possible to get this same functionality when building with maven. And, if so, how would I go about doing this?
Edit: I am not speaking of defining a specific list of java source files. The standard java compiler allows for a switch which causes the compiler itself to determine the dependencies based upon the imports. If the imported classes cannot be found in the classpath, then the source path is examined to see if there is a java file for the given class. If there is, then that java file is added to the compilation.
You will have to configure the maven compiler to set which files to include/exclude:
<project>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugi ns</groupId>
<artifactId>maven-compiler-plug in</artifactId>
<configuration>
<!-- put your configurations here -->
</configuration>
</plugin>
</plugins>
</build>
</project>
You could also do this for different maven profiles if you wanted to include/exclude different sets of files.
For the maven-compiler-plugin you can use includes and excludes sets, where you can specify patters for file names for exclusion and inclusion to the compilation. You can also use Ant scripts.
For details see http://maven.apache.org/plugins/maven-compiler-plugin/compile-mojo.html.

Is it possible consistently pass -Djava.library.path to a maven test from inside a POM file?

I have an external library that needs to be dynamically linked with a test in my java project. The project is setup using maven, and I need to add the following to my vm arguments in eclipse for the test to pass:
-Djava.library.path=${env_var:HOME}/.m2/repository/natives/dist/lib -ea
Unfortunately this means that running the test from maven using: mvn test will always fail.
One work around is to call mvn with a -DargLine argument like so:
mvn test -DargLine="-Djava.library.path=/Users/rob/.m2/repository/natives/dist/lib -ea"
However, clearly this has the problem of being specific to my machine, so I can't put it directly in the pom file. I guess what I'm looking for is a way of modifying that string on a per machine basis kinda like the first line does for eclipse.
I'm also curious how I could put it into the POM file, I've tried placing it inside of <argLine> tags, but that doesn't seems to work, is there something I'm missing:
<argLine>-Djava.library.path=/Users/rob/.m2/repository/natives/dist/lib -ea</argLine>
After some research I've discovered a decent solution to my problem.
In maven your settings.xml file, you can define a location for the localRepository here are the defaults if you set nothing:
Unix/Mac OS X – ~/.m2
Windows – C:\Documents and Settings\username.m2
As you can see this matches at least the first part of the directory I was trying to set: /Users/rob/.m2
Since dynamic linking is OS specific, you may also want to setup a profile for alternate path suffixes. You can do this in a .pom like this:
<profile>
<id>OSX</id>
<activation>
<os>
<family>mac</family>
</os>
</activation>
<properties>
<dynamic.libLoc>${settings.localRepository}/natives/dist/lib</dynamic.libLoc>
</properties>
</profile>
You can then use this property in the .pom for the project you wish to test. Under the plugins category you can add:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<argLine>-Djava.library.path=${dynamic.libLoc}</argLine>
</configuration>
</plugin>
Now maven can run those tests without users having to specify the location of the dynamically linked libraries. You can also handle users with different operating systems by just adding another profile.
Note: With regards to my problem with <argLine> earlier. I think I was just using it in the wrong .pom

Categories