Build Jar with dependencies including multiple main classes using Gradle in IntelliJ - scala

We are currently using Maven to build a Scala Application. Now we are trying to convert this project into Gradle. I have 3/4 main classes in this project and I want to build a jar with dependencies that include all the main classes and execute this jar with spark-submit by calling any of the classes.
I'm new to Gradle and facing issues with Gradle. Could some one help me.
Contents of pom.xml :
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org-groupId</groupId>
<artifactId>project-name</artifactId>
<version>3.0-SNAPSHOT</version>
<properties>
<scala.version>2.11.12</scala.version>
<scala.compat.version>2.11</scala.compat.version>
<scala.test.version>3.0.4</scala.test.version>
<project.type>application</project.type>
</properties>
<dependencies>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.2</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.42.Final</version>
</dependency>
<dependency>
<groupId>org.scalatest</groupId>
<artifactId>scalatest_${scala.compat.version}</artifactId>
<version>3.0.4</version>
<scope>test</scope>
</dependency>
</dependencies>
<repositories>
<repository>
<id>maven-repo</id>
<name>Maven central repository</name>
<url>https://repo1.maven.org/maven2</url>
</repository>
</repositories>
<build>
<sourceDirectory>src/main/scala</sourceDirectory>
<testSourceDirectory>src/test/scala</testSourceDirectory>
<plugins>
<plugin>
<groupId>org.scalatest</groupId>
<artifactId>scalatest-maven-plugin</artifactId>
<version>1.0</version>
<configuration>
<reportsDirectory>${project.build.directory}/surefire-reports</reportsDirectory>
<junitxml>.</junitxml>
</configuration>
<executions>
<execution>
<id>test</id>
<goals>
<goal>test</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.0.0</version>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/lib</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>net.alchim31.maven</groupId>
<artifactId>scala-maven-plugin</artifactId>
<version>4.3.0</version>
<executions>
<execution>
<id>scala-compile-first</id>
<phase>process-resources</phase>
<goals>
<goal>add-source</goal>
<goal>compile</goal>
</goals>
</execution>
<execution>
<id>scala-test-compile</id>
<phase>process-test-resources</phase>
<goals>
<goal>testCompile</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<release>11</release>
</configuration>
<executions>
<execution>
<phase>compile</phase>
<goals>
<goal>compile</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.6</version>
<executions>
<execution>
<goals>
<goal>test-jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.scalastyle</groupId>
<artifactId>scalastyle-maven-plugin</artifactId>
<version>1.0.0</version>
<configuration>
<verbose>false</verbose>
<failOnViolation>true</failOnViolation>
<includeTestSourceDirectory>true</includeTestSourceDirectory>
<failOnWarning>false</failOnWarning>
<sourceDirectory>src/main/scala</sourceDirectory>
<testSourceDirectory>src/test/scala</testSourceDirectory>
<configLocation>${project.basedir}/src/main/resources/plugin/scalastyle_config.xml</configLocation>
<outputFile>${project.build.directory}/scalastyle-output.xml</outputFile>
<outputEncoding>UTF-8</outputEncoding>
</configuration>
<executions>
<execution>
<goals>
<goal>check</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
Contents of build.gradle:
apply plugin: 'java'
apply plugin: 'scala'
apply plugin: 'idea'
apply plugin: 'eclipse'
apply plugin: 'maven'
apply plugin: 'maven-publish'
repositories {
mavenLocal()
mavenCentral()
maven {
url = uri('https://repo1.maven.org/maven2')
}
}
dependencies {
// Some internal dependencies
implementation 'com.google.code.gson:gson:2.8.2'
implementation 'io.netty:netty-all:4.1.42.Final'
testImplementation "org.scalatest:scalatest_2.11:$scalaTestVersion"
}
tasks.withType(JavaCompile) {
options.encoding = 'UTF-8'
}
Contents of gradle.properties :
# Description
# Versions
version = 4.0
scalaVersion=2.11.12
scalaMajorVersion=2.11
scalaTestVersion=3.0.4
sparkVersion=2.4.6
sourceCompatibility = '1.8'
I have tried ./gradlew clean assemble and ./gradlew clean build.
Both of them building a regular jar but not dependencies jar.
Also, I'm trying to execute this in IntelliJ since Jar is not building, but with IntelliJ getting the below error.
21:36:59: Executing task 'mainclass1.main()'...
FAILURE: Build failed with an exception.
* Where:
Initialization script '/private/var/folders/sq/npjk1mkn7lgfm57mf9g_3rrh0000gn/T/mainclass1_main__.gradle' line: 4
* What went wrong:
A problem occurred configuring root project 'project-name'.
> Could not create task ':mainclass1.main()'.
> Unnecessarily replacing a task that does not exist is not supported. Use create() or register() directly instead. You attempted to replace a task named 'mainclass1.main()', but there is no existing task with that name.
* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.
* Get more help at https://help.gradle.org
Deprecated Gradle features were used in this build, making it incompatible with Gradle 7.0.
Use '--warning-mode all' to show the individual deprecation warnings.
See https://docs.gradle.org/6.4.1/userguide/command_line_interface.html#sec:command_line_warnings
BUILD FAILED in 567ms
Cause: invalid type code: FA
21:37:00: Task execution finished 'mainclass1.main()'.
While converting from Maven pom.xml to Gradle, I didn't included and build plugins in Gradle. What are the plugins I can use to build a the jar in Gradle.

It looks like you want a fat jar. This will contain all the dependencies that allow you to run the application. ​
Gradle does not have a straightforward out-of-the-box solution because its aim is to keep things simple.
You can do this with by setting the following on your build.gradle file:
jar {
​from {
​configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) }
​}
}
Alternatively, you can use this plugin, by setting the following on the build.gradle:
plugins {
id 'com.github.johnrengelman.shadow' version '5.2.0' // check version compatibiltiy
}
and the running the task gradlew shadowJar.
On another note, did I understand you have 3/4 main classes? I don't know SPARK, so maybe it allows for several main classes, but outside of SPARK, your manifest file must set which is the main class. There can be only one.
This will allows you to run java -jar your-jar.jar. The following SO question might be relevant: Multiple runnable classes inside JAR, how to run them?
To set your main class on the Manifest using gradle:
jar {
​manifest.attributes["Main-Class"] = "<your-main-class-full-path>"
}

Related

Exception Child services have no parent when starting Optaplanner application

I have a test program that uses optaplanner. There is no direct use of KIE API's but it looks like they are being invoked behind the scenes. This may be related to the fact that I am using DROOLS for the score calculation. The program works from the IDE or through maven, but I want to create a standalone jar that will not require maven.
I used the maven assembly plugin to build a fat jar with all dependencies included to be run standalone.
When I run java -jar target/OptaPlannerTest-1.4-SNAPSHOT-jar-with-dependencies.jar I get :
Exception in thread "main" java.lang.ExceptionInInitializerError
at org.kie.api.internal.utils.ServiceRegistry.getInstance(ServiceRegistry.java:27)
at org.kie.api.KieServices$Factory$LazyHolder.<clinit>(KieServices.java:332)
at org.kie.api.KieServices$Factory.get(KieServices.java:339)
at org.optaplanner.core.config.score.director.ScoreDirectorFactoryConfig.buildDroolsScoreDirectorFactory(ScoreDirectorFactoryConfig.java:460)
at org.optaplanner.core.config.score.director.ScoreDirectorFactoryConfig.buildScoreDirectorFactory(ScoreDirectorFactoryConfig.java:331)
at org.optaplanner.core.config.solver.SolverConfig.buildSolver(SolverConfig.java:220)
at org.optaplanner.core.impl.solver.AbstractSolverFactory.buildSolver(AbstractSolverFactory.java:61)
at com.github.wshackle.optaplannertest.Main.main(Main.java:38)
Caused by: java.lang.RuntimeException: Child services [org.kie.api.internal.assembler.KieAssemblers] have no parent
at org.kie.api.internal.utils.ServiceDiscoveryImpl.buildMap(ServiceDiscoveryImpl.java:186)
at org.kie.api.internal.utils.ServiceDiscoveryImpl.getServices(ServiceDiscoveryImpl.java:97)
at org.kie.api.internal.utils.ServiceRegistryImpl.<init>(ServiceRegistryImpl.java:36)
at org.kie.api.internal.utils.ServiceRegistryImpl$LazyHolder.<clinit>(ServiceRegistryImpl.java:32)
Line 38 of Main.java is only two lines into the application, so all it has done is load the config file and try to build the solver.
SolverFactory<Plan> solverFactory = SolverFactory.createFromXmlResource(
"com/github/wshackle/optaplannertest/solverConfig.xml");
Solver<Plan> solver = solverFactory.buildSolver();
solverConfig.xml is:
<solver>
<!-- Domain model configuration -->
<scanAnnotatedClasses>
<packageInclude>com.github.wshackle.optaplannertest.model</packageInclude>
</scanAnnotatedClasses>
<!-- Score configuration -->
<scoreDirectorFactory>
<scoreDrl>com/github/wshackle/optaplannertest/scoreRules.drl</scoreDrl>
</scoreDirectorFactory>
<!-- Optimization algorithms configuration -->
<termination>
<secondsSpentLimit>5</secondsSpentLimit>
</termination>
</solver>
In cast it is relevant my pom is this:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.github.wshackle</groupId>
<artifactId>OptaPlannerTest</artifactId>
<version>1.4-SNAPSHOT</version>
<packaging>jar</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<optiplanner.version>7.3.0.Final</optiplanner.version>
<main.class>com.github.wshackle.optaplannertest.Main</main.class>
</properties>
<dependencies>
<dependency>
<groupId>org.optaplanner</groupId>
<artifactId>optaplanner-core</artifactId>
<version>${optiplanner.version}</version>
</dependency>
<dependency>
<groupId>org.kie</groupId>
<artifactId>kie-api</artifactId>
<version>${optiplanner.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.25</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<scope>runtime</scope>
<version>1.2.3</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.5.5</version>
<configuration>
<archive>
<manifest>
<mainClass>${main.class}</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
<executions>
<execution>
<id>make-assembly</id> <!-- this is used for inheritance merges -->
<phase>package</phase> <!-- bind to the packaging phase -->
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
The complete list of files in the jar is shown at
https://gist.github.com/wshackle/8887aac8a10e8c4b1f862a4bda288e41
I used grep to verify they seem to include the expected classes for each jar dependancy:
> grep -c org/kie/api jarlisting.txt
391
> grep -c org/kie/internal jarlisting.txt
364
> grep -c org/optaplanner/core jarlisting.txt
841
> grep -c org/drools/core jarlisting.txt
2175
> grep -c org/drools/compiler jarlisting.txt
832
The problem is that the following jar files all contain different versions of META-INF/kie.conf:
optaplanner-core-7.3.0.Final.jar
kie-internal/7.3.0.Final/kie-internal-7.3.0.Final.jar
drools-core-7.3.0.Final.jar
drools-compiler-7.3.0.Final.jar
When the maven-assembly-plugin puts them together only one version of the META-INF/kie.conf can be included. When building the solver the Optaplanner library will indirectly call getResources("META-INF/kie.conf") on the current Thread context classloader. If there are multiple jars on the classpath then all of them will be found and the resulting configuration will be the product of parsing all of them. In order to make this work in a single fat uber jar the kie.conf files need to be moved to different file names and a classloader overloaded to direct the library to use them at the new names. (It might also be possible to combine them into a single kie.conf file)
Extract and move the kie.conf files:
jar -xf ~/.m2/repository/org/optaplanner/optaplanner-core/7.3.0.Final/optaplanner-core-7.3.0.Final.jar META-INF/kie.conf
mv META-INF/kie.conf src/main/resources/optaplanner-core-kie.conf
jar -xf ~/.m2/repository/org/kie/kie-internal/7.3.0.Final/kie-internal-7.3.0.Final.jar META-INF/kie.conf
mv META-INF/kie.conf src/main/resources/kie-internal-kie.conf
jar -xf ~/.m2/repository/org/drools/drools-core/7.3.0.Final/drools-core-7.3.0.Final.jar META-INF/kie.conf
mv META-INF/kie.conf src/main/resources/drools-core-kie.conf
jar -xf ~/.m2/repository/org/drools/drools-compiler/7.3.0.Final/drools-compiler-7.3.0.Final.jar META-INF/kie.conf
mv META-INF/kie.conf src/main/resources/drools-compiler-kie.conf
Then overload and set the thread context loader.
ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader();
URL[] localKieConfUrls = new URL[]{
ClassLoader.getSystemResource("optaplanner-core-kie.conf"),
ClassLoader.getSystemResource("kie-internal-kie.conf"),
ClassLoader.getSystemResource("drools-core-kie.conf"),
ClassLoader.getSystemResource("drools-compiler-kie.conf")
};
ClassLoader newClassLoader = new ClassLoader(oldClassLoader) {
private final URL[] kieConfUrls = localKieConfUrls;
#Override
public Enumeration<URL> getResources(String name) throws IOException {
if ("META-INF/kie.conf".equals(name)) {
return new Enumeration<URL>() {
int index;
#Override
public boolean hasMoreElements() {
return index < kieConfUrls.length;
}
#Override
public URL nextElement() {
return kieConfUrls[index++];
}
};
}
return super.getResources(name);
}
};
Thread.currentThread().setContextClassLoader(newClassLoader);
I agree that the problem is as #WillSchackleford describes:
The problem is that the following jar files all contain different versions of META-INF/kie.conf:
optaplanner-core-7.3.0.Final.jar
kie-internal/7.3.0.Final/kie-internal-7.3.0.Final.jar
drools-core-7.3.0.Final.jar
drools-compiler-7.3.0.Final.jar
When the maven-assembly-plugin puts them together only one version of the META-INF/kie.conf can be included.
The best trick to combine all of these kie.conf files is to use a transformer in your maven config, like so:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<!-- get all project dependencies -->
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<!-- MainClass in mainfest make a executable jar -->
<archive>
<manifest>
<mainClass>com.paconsulting.powerpeers.PowerPeersDemo</mainClass>
</manifest>
</archive>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
<resource>META-INF/kie.conf</resource>
</transformer>
</transformers>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<!-- bind to the packaging phase -->
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
This creates one META-INF/kie.conf file with the content of any of the kie.conf files it finds.
Run "mvn dependency:tree" and you'll see that optaplanner-core depends on kie-api, kie-internal-api, drools-core and drools-compiler. One of those will be missing in your fat jar.
I was having the same problem with the following pom
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
..
<dependencies>
<dependency>
<groupId>org.optaplanner</groupId>
<artifactId>optaplanner-core</artifactId>
<version>${optaPlanner.version}</version>
</dependency>
...
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>${jar.plugin.version}</version>
<configuration>
<archive>
<addMavenDescriptor>false</addMavenDescriptor>
<compress>false</compress>
<manifest>
<addClasspath>true</addClasspath>
<classpathPrefix>libs/</classpathPrefix>
<mainClass>${mainClass}</mainClass>
</manifest>
<index>true</index>
<manifestEntries>
<impl-version>${project.version}</impl-version>
</manifestEntries>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>${dependency.plugin.version}</version>
<executions>
<execution>
<id>copy-dependencies</id>
<phase>package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/libs</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>${assembly.plugin.version}</version>
<configuration>
<descriptors>
<descriptor>assembly/release.xml</descriptor>
</descriptors>
<finalName>${distribution.file.name}</finalName>
<outputDirectory>${project.build.directory}/dist</outputDirectory>
<workDirectory>${project.build.directory}/assembly/work</workDirectory>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
Removing
<index>true</index>
solved my problem. Hope this helps others as well.
For people using maven-shade-plugin, here is a proposed fix that is going to merge the META-INF/kie.conf that are duplicated into a single file using the AppendingTransformer https://stackoverflow.com/a/53273253/5903731
I have also met this error but i found a solution with different way. Instead of generating a jar file with all dependencies, generating jar file with library folder of dependencies is easier way for getting runnable jar file. To produce jar file with lib folder modify your pom.xml file as indicated below.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>copy-dependencies</id>
<phase>prepare-package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/lib</outputDirectory>
<overWriteReleases>false</overWriteReleases>
<overWriteSnapshots>false</overWriteSnapshots>
<overWriteIfNewer>true</overWriteIfNewer>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<classpathPrefix>lib/</classpathPrefix>
<mainClassMain-Class</mainClass>
</manifest>
</archive>
</configuration>
</plugin>

Maven modules will not find dependencies with scalatest

While working with scalatest I ran into a weird problem. I have a maven project with multiple modules. If I execute mvn test directly in the module. It works without problems, but if I do it in the root folder it complains about missing packages (dependencies) while compiling.
My configuration looks like following:
<dependency>
<groupId>org.scalatest</groupId>
<artifactId>scalatest_${scala.shortversion}</artifactId>
<version>3.0.0-SNAP2</version>
</dependency>
<dependency>
<groupId>org.scalatest</groupId>
<artifactId>scalatest-maven-plugin</artifactId>
<version>1.0</version>
</dependency>
plugin configuration:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.7</version>
<configuration>
<skipTests>true</skipTests>
</configuration>
</plugin>
<plugin>
<groupId>org.scalatest</groupId>
<artifactId>scalatest-maven-plugin</artifactId>
<version>1.0</version>
<configuration>
<reportsDirectory>${project.build.directory}/surefire-reports</reportsDirectory>
<junitxml>.</junitxml>
<filereports>WDF TestSuite.txt</filereports>
</configuration>
<executions>
<execution>
<id>scala-test</id>
<goals>
<goal>test</goal>
</goals>
</execution>
</executions>
</plugin>
If I remove from maven-scala-plugin the goals it'll compile but scalatest will not find the test sources and exit with No tests were executed.:
<plugin>
<version>2.15.2</version>
<groupId>org.scala-tools</groupId>
<artifactId>maven-scala-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>testCompile</goal>
</goals>
</execution>
</executions>
<configuration>
<scalaVersion>${scala.version}</scalaVersion>
</configuration>
</plugin>
Any ideas on what I am doing wrong?!
Cheers
Hard to say without seeing all your poms, but generally speaking:
Define in root Pom all your dependencies in dependencyManagement section, your plugins in pluginManagement section with their configuration. In child poms define only those plugins and dependencies you need.
Keep in mind that xxxManagement sections only build shared definition, kind of root configuration. You still have to define in plugins and dependencies sections what you need but you can omit version and configuration elements.
This will allow all your child poms to run tests in all modules.

Maven Javadoc - Unable to generate Javadoc

I have the following dependency and build in my pom file. I'm able to manually create the javadoc with a Maven command. I can also succesfully perform a build. The output doesn't mention javadoc at all. I've also tried leaving out the output directory paths. POM File
Dependency section:
<dependency>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.8</version>
</dependency>
and then the build section:
<build>
<finalName>D</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.8</version>
<configuration>
<outputDirectory>${project.build.directory}/javadoc</outputDirectory>
<reportOutputDirectory>${project.reporting.outputDirectory}/javadoc</reportOutputDirectory>
<version>2.8</version>
</configuration>
<executions>
<execution>
<id>attach-javadocs</id>
<goals>
<goal>aggregate</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
The Maven Javadoc plugin doesn't run by default and needs to be bound to one of the default Maven lifecycle phases.
Here's how I would write the plugin's configuration:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.8</version>
<configuration>
<outputDirectory>${project.build.directory}/javadoc</outputDirectory>
<reportOutputDirectory>${project.reporting.outputDirectory}/javadoc</reportOutputDirectory>
</configuration>
<executions>
<execution>
<id>attach-javadocs</id>
<phase>site</phase>
<goals>
<goal>aggregate</goal>
</goals>
</execution>
</executions>
</plugin>
Notice how I added an extra phase element to the execution. This will bind it to the "site" goal so that javadocs are generated when you run mvn site. Check Introduction to the Build Lifecycle if you want one of the default Java build phases.
Also note that I ditched the version parameter; by default, it should use your POM's version anyway.

How to check and access javadoc/source for Maven Artifacts

I am writing a Maven plugin which needs to check if a certain project
dependency has javadocs and sources available... and if so, would like
to download them and archive them on a server.
I cannot find out how to check if the javadocs and source are available
or how to access them if they are.
Any help would be appreciated.
You can reference additional artifacts by adding the classifier tag to a dependency. The classifier is the additional part of the artifact's name in the repository, e.g junit-4.5-sources.jar
So to directly declare a dependency on the junit sources jar you can specify it as follows:
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.5</version>
<classifier>sources</classifier>
<scope>test</scope>
</dependency>
If you want to download all the dependency sources, use the maven-dependency-plugin's copy-dependencies goal specifying the classifier sources. The following example defines two executions, one for sources and one for javadocs.
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>sources</id>
<phase>package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<classifier>sources</classifier>
<failOnMissingClassifierArtifact>false</failOnMissingClassifierArtifact>
<outputDirectory>${project.build.directory}/sources</outputDirectory>
</configuration>
</execution>
<execution>
<id>javadocs</id>
<phase>package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<classifier>javadoc</classifier>
<failOnMissingClassifierArtifact>false</failOnMissingClassifierArtifact>
<outputDirectory>${project.build.directory}/javadocs</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
If you want to package all the downloaded artifacts into a zip, you can use the maven-assembly-plugin to create an archive of the project. The example below are the contents of an assembly descriptor file to include the sources and javadocs directories:
<assembly>
<id>project</id>
<formats>
<format>zip</format>
</formats>
<fileSets>
<fileSet>
<directory>${project.basedir}</directory>
<useDefaultExcludes>true</useDefaultExcludes>
<includes>
<include>${project.build.directory}/sources</include>
<include>${project.build.directory}/javadocs</include>
</includes>
</fileSet>
</fileSets>
</assembly>
To reference the assembly, add a plugin configuration to your pom. This assumes the above contents have been put in src/main/assembly/sources.xml (make sure it is defined after the dependency configuration above):
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.2-beta-4</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<descriptors>
<descriptor>src/main/assembly/sources.xml</descriptor>
</descriptors>
</configuration>
</execution>
</executions>
</plugin>

Execute Maven plugin goal on parent module, but not on children

We have a multi-module maven project that uses a profile that defines a buildnumber-maven-plugin to increment a build number and then check it into source control.
If I define the plugin in the parent pom.xml it executes for all the child builds as well.
Here's my parent pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.webwars</groupId>
<artifactId>parent</artifactId>
<packaging>pom</packaging>
<properties>
<buildNumber.properties>${basedir}/../parent/buildNumber.properties</buildNumber.properties>
</properties>
<version>1.0-SNAPSHOT</version>
<name>Parent Project</name>
<profiles>
<profile>
<id>release</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<debug>false</debug>
<optimize>true</optimize>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>buildnumber-maven-plugin</artifactId>
<version>1.0-beta-3</version>
<executions>
<execution>
<phase>validate</phase>
<goals>
<goal>create</goal>
</goals>
</execution>
</executions>
<configuration>
<buildNumberPropertiesFileLocation>${buildNumber.properties}</buildNumberPropertiesFileLocation>
<getRevisionOnlyOnce>true</getRevisionOnlyOnce>
<doCheck>false</doCheck>
<doUpdate>false</doUpdate>
<format>{0, number}</format>
<items>
<item>buildNumber</item>
</items>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-scm-plugin</artifactId>
<executions>
<execution>
<phase>install</phase>
<goals>
<goal>checkin</goal>
</goals>
</execution>
</executions>
<configuration>
<basedir>${basedir}</basedir>
<includes>buildNumber.properties</includes>
<message>[Automated checkin] of ${basedir} Build version: ${major.version}.${minor.version}.${buildNumber}</message>
<developerConnectionUrl>...</developerConnectionUrl>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
<modules>
<module>../common</module>
<module>../data</module>
<module>../client</module>
<module>../webplatform</module>
</modules>
...
</project>
As documented in the Plugins section of the pom reference:
Beyond the standard coordinate of groupId:artifactId:version, there are elements which configure the plugin or this builds interaction with it.
inherited: true or false, whether or not this plugin configuration should apply to POMs which inherit from this one.
So just add <inherited>false</inherited> to the buildnumber-maven-plugin configuration to avoid inheritance in children POMs:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>buildnumber-maven-plugin</artifactId>
<version>1.0-beta-3</version>
<inherited>false</inherited>
...
</plugin>
You can add <inherited>false</inherited> to the plugin configuration to avoid inheritance in children POMs:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>buildnumber-maven-plugin</artifactId>
<version>1.0-beta-3</version>
<inherited>false</inherited>
...
</plugin>
Or, if your plugin has multiple executions, you can control which executions are inherited and which are not by adding the inherited tag to the execution body:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
<id>parent-only</id>
<phase>initialize</phase>
<inherited>false</inherited>
<configuration>
<target>
<echo message="Echoed only by this module."/>
</target>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
<execution>
<id>all-modules</id>
<phase>initialize</phase>
<inherited>true</inherited> <!-- Defaults to true, so you could leave this line out -->
<configuration>
<target>
<echo message="Echoed in this module and each child module."/>
</target>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
There is a built-in maven option:
mvn --help
...
-N,--non-recursive Do not recurse into sub-projects
If the plugin is custom one and you have access to plugin MOJO code, you can mark the plugin as aggregator; if the expected behavior is applicable for all projects where plugin is to be used.
As mentioned in Mojo API Specification ,
Flags this Mojo to run it in a multi module way, i.e. aggregate the
build with the set of projects listed as modules.
Example,
#Mojo(name = "createHF", inheritByDefault = false, aggregator = true)
public class CreateHFMojo extends AbstractMojo {
..
public void execute() throws MojoExecutionException, MojoFailureException {
....
}
..
}
Detailed example on github.
Just an addition to the great answers here: note that per-execution inheritance is broken in Maven 2: http://jira.codehaus.org/browse/MNG-3959