Is there a variable in Maven that holds the current goal? - variables

In order to invoke the Maven invoker plugin with the same goal that is currently running in my uber-pom, I need a way to pass the current goal into the invoker-plugin's config.
Somethig like
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-invoker-plugin</artifactId>
...
<configuration>
<goals>
<goal>${maven.goal}</goal>
</goals>
...

The Maven Help plugin might help you get where you want to go. The ${reactorProjects} variable holds what you are looking for, but perhaps not in precisely the format you are looking to reuse it.
You can view all the expressions available to you via:
mvn help:expressions
and then you can test one of them without the tedium of a pom via evaluation:
mvn help:evaluate
which takes you to a prompt you can use to try expressions.
If I use the help:evaluate and type ${reactorProjects}, I'll get a lot of output, but part of which includes the data you are after:
<plugins>
<plugin>
<inheritanceApplied>true</inheritanceApplied>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-help-plugin</artifactId>
<version>2.1</version>
<extensions>false</extensions>
<dependencies/>
</plugin>
</plugins>
<pluginMap class="linked-hash-map">
<entry>
<string>org.apache.maven.plugins:maven-help-plugin</string>
<plugin reference="../../../plugins/plugin"/>
</entry>
</pluginMap>

I added the following dependency:
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-core</artifactId>
<version>3.0.3</version>
</dependency>
And then in my MOJO:
import org.apache.maven.execution.MavenExecutionRequest;
import org.apache.maven.execution.MavenSession;
...
#Parameter(defaultValue = "${session}", readonly = true)
private MavenSession session;
Finally, I was able to get the current goals:
MavenExecutionRequest executionRequest = session.getRequest();
List<String> goals = executionRequest.getGoals();

Related

Kotlin: Possible to modify functions during compile time through metaprogramming?

In dynamic languages like JavaScript/Python, it's possible to overwrite or "modify" functions during run-time. For example, in order to modify the alert function in JS, one could do:
const _prev_alert = window.alert;
window.alert = function() {
_prev_alert.apply(this, arguments);
console.log("Alert function was called!");
}
This would output "Alert function was called!" to the console every time the alert function is called.
Now, obviously something like this would be impossible during runtime in Kotlin-JVM or Kotlin-Native due to their static nature. However, in regards to those same languages, is it possible to perhaps modify a non-compiled function during compile time? I don't mean pre-compiled functions from libraries, but instead functions I have written in the same project I'm developing on.
For example, let's say I have a function I wrote called get_number. Could I modify get_number to return a different number without changing how its called in main and without modifying its code directly? (Or is there a way I COULD write the original get_number so modification IS possible down the line?)
fun main(args: Array<String>) {
println(get_number())
}
fun get_number(): Int {
return 3
}
// Without modifying the code above, can I get main to print something besides 3?
I've been reading into Kotlin's metaprogramming with Annotations and Reflections, so perhaps those could control the compiler's behavior and overwrite get_number's code? Or is this complete lunacy and the only way something of this nature would be possible is through developing my own, separate, metaprogramming wrapper over Kotlin?
Also, just to double-clarify, this question is not about Kotlin-JS and the answer (if it exists) should be applicable to Kotlin-JVM or Native.
As stated in my comment: in almost all cases, it's more desirable to use an appropriate design pattern than to start relying on things like dynamic proxies, reflection, or AOP to address this kind of problem.
That being said, the question asks whether it's possible to modify Kotlin functions at compile time through meta-programming, and the answer is "Yes". To demonstrate, below is a complete example that uses AspectJ.
Project structure
I set up a small Maven-based project with the following structure:
.
├── pom.xml
└── src
└── main
└── kotlin
├── Aop.kt
└── Main.kt
I'll reproduce the contents of all files in the sections below.
Application code
The actual application code is in the file named Main.kt, and—except for the fact that I renamed your function to be in line with Kotlin naming rules—it's identical to the code provided in your question. The getNumber() method is designed to return 3.
fun main(args: Array<String>) {
println(getNumber())
}
fun getNumber(): Int {
return 3
}
AOP code
The AOP-related code is in Aop.kt, and is very simple. It has an #Around advice with a point cut that matches the execution of the getNumber() function. The advice will intercept the call to the getNumber() method and return 42 (instead of 3).
import org.aspectj.lang.ProceedingJoinPoint
import org.aspectj.lang.annotation.Around
import org.aspectj.lang.annotation.Aspect
#Aspect
class Aop {
#Around("execution(* MainKt.getNumber(..))")
fun getRealNumber(joinPoint: ProceedingJoinPoint): Any {
return 42
}
}
(Note how the name of the generated class for the Main.kt file is MainKt.)
POM file
The POM file puts everything together. I'm using 4 plugins:
The kotlin-maven-plugin takes care of compiling the Kotline files. The configuration includes the execution of the kapt plugin to process the AspectJ annotations.
The jcabi-maven-plugin executes the AspectJ compiler/weaver to weave the aspects into the binary classes.
The maven-jar-plugin builds the JAR file with a manifest that references the main class.
The maven-shade-plugin builds a fat JAR that includes all library dependencies.
This is the complete POM file:
<?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>x.y.z</groupId>
<artifactId>kotlin-aop</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.8</java.version>
<kotlin.version>1.2.61</kotlin.version>
<aspectj.version>1.9.1</aspectj.version>
</properties>
<dependencies>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-stdlib</artifactId>
<version>${kotlin.version}</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>${aspectj.version}</version>
</dependency>
</dependencies>
<build>
<sourceDirectory>${project.basedir}/src/main/kotlin</sourceDirectory>
<plugins>
<plugin>
<artifactId>kotlin-maven-plugin</artifactId>
<groupId>org.jetbrains.kotlin</groupId>
<version>${kotlin.version}</version>
<executions>
<execution>
<id>kapt</id>
<goals>
<goal>kapt</goal>
</goals>
</execution>
<execution>
<id>compile</id>
<goals>
<goal>compile</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>com.jcabi</groupId>
<artifactId>jcabi-maven-plugin</artifactId>
<version>0.14.1</version>
<executions>
<execution>
<goals>
<goal>ajc</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.1.0</version>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<mainClass>MainKt</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.1.1</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
Building and executing
To build, as with any Maven project, you just need to run:
mvn clean package
This will build a fat JAR at the target/kotlin-aop-1.0-SNAPSHOT.jar location. This JAR can then be executed using the java command:
java -jar target/kotlin-aop-1.0-SNAPSHOT.jar
Execution then gives us the following result, demonstrating that everything worked as expected:
42
(Application was built and executed using the most recent Oracle Java 8 JDK at the time of writing—1.8.0_181)
Conclusion
As the example above demonstrates, it's certainly possible to redefine Kotlin functions, but—to reiterate my original point—in almost all cases, there are more elegant solutions available to achieve what you need.

Maven: Different configuration for different goals

I'd like to have different configuration options for different goals of the Maven's release plugin. The story goes like this:
I'm using Git for an SCM. I want the release:prepare plugin to do everything locally and the release:perform to push all the changes at once to the remote repository.
I've tried doing something like this:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-release-plugin</artifactId>
<version>2.2.2</version>
<executions>
<execution>
<id>release-prepare</id>
<configuration>
<pushChanges>false</pushChanges>
</configuration>
<goals>
<goal>prepare</goal>
</goals>
</execution>
<execution>
<id>release-perform</id>
<configuration>
<localCheckout>true</localCheckout>
<pushChanges>true</pushChanges>
</configuration>
<goals>
<goal>perform</goal>
</goals>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-scm-plugin</artifactId>
<version>1.7-SNAPSHOT</version>
</dependency>
</dependencies>
</plugin>
The 1.7-SNAPSHOT version is required for localCheckout=true to work at all (http://jira.codehaus.org/browse/SCM-662) if anyone is wondering about that.
With the settings mentioned above all the configuration options are ignored completely but when I simply specify the settings like this:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-release-plugin</artifactId>
<version>2.2.2</version>
<configuration>
<localCheckout>true</localCheckout>
<pushChanges>false</pushChanges>
</configuration>
<dependencies>
<dependency>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-scm-plugin</artifactId>
<version>1.7-SNAPSHOT</version>
</dependency>
</dependencies>
</plugin>
they apply to both release:prepare as well as release:perform which is not the desired outcome.
Edit:
To make things clear: while we're using Git for SCM we'd like to have all the operations leading to the preparation of a release local which is not without reason if you take into account that the local Git repository is a full-fledged repo anyways. However when we do the actual release we'd like all the changes to be pushed to upstream repository so that everything is properly set.
Could anyone help me out with it?
In the case you need to change that you have to change the release plugin cause during the release:perform (goal!) the release plugin will checkout the tagged state of the project and call the deploy lifecycle on it. So this will not work.
EDIT:
I have checkt that with a Git project and did a release on it and it is as i explained. During the release:prepare goal the changes will be pushed to the remote repository. During the release:perform goal nothing will be pushed to the remote repository only a clone will be done to checkout the tagged version.
First i have to say that during the release:prepare goal all changes will be done in the SCM and not in the release:perform goal. So the question is why would like to do it in a such complicated (non maven) way ?

Maven cobertura plugin - one report for multimodule project

I'm using maven cobertura plugin to report code coverage in my multimodule project.
The problem is that I don't know how to generate one report for all modules in project.
So far I have generated separate reports for every module, but it would be nice to have one report for whole project.
My parent pom configuration:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>cobertura-maven-plugin</artifactId>
<version>2.4</version>
<inherited>true</inherited>
<executions>
<execution>
<phase>test-compile</phase>
<goals>
<goal>clean</goal>
<goal>cobertura</goal>
</goals>
</execution>
</executions>
</plugin>
The plugin has been updated since this question was asked (and last answered) to now enable aggregated reporting, via the aggregate configuration property in the parent POM.
This produces the aggregated coverage report at target/site/cobertura/index.html which will include all modules.
(Each module will also have it's own report produced, if that is of any use.)
Parent pom.xml
<modules>
<module>moduleA</module>
<module>moduleB</module>
<module>moduleC</module>
<modules>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>cobertura-maven-plugin</artifactId>
<version>2.6</version>
<configuration>
<check/>
<formats>
<format>html</format>
<format>xml</format>
</formats>
<aggregate>true</aggregate>
</configuration>
</plugin>
...
</pluginManagement>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>cobertura-maven-plugin</artifactId>
</plugin>
</plugins>
...
</build>
To my knowledge, this is currently not supported, see MCOBERTURA-65. But the issue has a patch attached, maybe try it. But my suggestion would be to use something like Sonar to aggregate metrics.
I have been using Hudson as a Continuous Integration tool.
The Cobertura plugin allows me to see code coverage of all of the child modules when checking on the parent.
The Jenkins Cobertura plugin aggregates the report automatically but if you are interested in the coverage file itself for some other reasons you can do by following below procedure:
Download Cobertura from here
Go to your project workspace -> find all the .ser files and rename them
(i=0; find . | grep cobertura.ser$ | while read line;do echo $line; cp -i $line cobertura$i.ser;i=$(($i+1));done;)
use cobertura-merge.sh to generate global .ser file
~/cobertura-2.0.3/cobertura-merge.sh --datafile cobertura.ser cobertura*.ser
use cobertura-report.sh to generate report on global .ser file
~/cobertura-2.0.3/cobertura-report.sh ./cobertura.ser --destination ./ --format xml
You will have the global coverage.xml generated in the current directory.
You can use it for any kind of processing further.

Copy dependencies maven war

When I try to use the plugin "maven-war-plugin", it copies all libraries to / WEB-INF/lib, how to copy to another directory? Example: "/ libtest"
I'm not sure to understand why you need to do this but I see two points here:
Avoiding dependencies to get copied into WEB-INF/lib (if not, then just skip the part related to 1.)
Getting them copied to another directory.
For 1. I'm assuming you need the dependencies (because you want to compile against them) but if you don't want the Maven War Plugin to copy them in WEB-INF/lib, you'll have to play with their scope, for example by declaring them as provided.
For 2. the Maven Dependency Plugin will be helpful here and I think you could use dependency:copy-dependencies, for example during the pre-package phase. Use it like this:
<project>
[...]
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>copy-dependencies</id>
<phase>pre-package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<!-- configure the plugin here -->
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
[...]
</project>
And configure the outputDirectory (and other parameters you could need).
Use the maven-dependency-plugin.

Checkstyle not working

I am new to maven and chekstyle, so need to ask some question... I want to use checkstyle in my maven based project, so in my pom.xml I have add the dependency
<dependency>
<groupId>checkstyle</groupId>
<artifactId>checkstyle</artifactId>
<version>2.4</version>
</dependency>
and also I have added the entry in plugin tag:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
<version>2.4</version>
<configuration>
<enableRulesSummary>true</enableRulesSummary>
<configLocation>checkstyle.xml</configLocation>
</configuration>
</plugin>
But when I run my maven build with command mvn clean install, checkstyle doesn't do anything. And as I dont have any checkstyle.xml in my system yet, shouldn't it complains me about the error?
What else configuration am I missing?
I want to use checkstyle in my maven based project, so in my pom.xml I've add the dependency (...)
You don't need to add this dependency, you just need to declare the plugin (a plugin declares its own dependencies).
(...) But when I run my maven build with command mvn clean install, checkstyle doesn't do anything.
Yes because you only declared the plugin, you did not bind the check goal to a lifecycle phase, so a normal build doesn't trigger the checkstyle plugin. If you want checkstyle:check to be triggered as part of your build, you need to declare the check goal inside an execution (it binds itself by default to the verify phase). Something like this:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
<!-- Lock down plugin version for build reproducibility -->
<version>2.5</version>
<configuration>
<consoleOutput>true</consoleOutput>
<configLocation>checkstyle.xml</configLocation>
...
</configuration>
<executions>
<execution>
<goals>
<goal>check</goal>
</goals>
</execution>
</executions>
</plugin>
Now, calling any phase including verify will invoke checkstyle.
And as I don't have any checkstyle.xml in my system yet, shouldn't it complains me about the error?
It will... when called (either explicitly by mvn checkstyle:check or as part of the build if you modify your setup as suggested).