Custom maven plugin: install and execute the plugin in one build - java

I wrote a custom maven plugin that scaffolds java-code from a custom schema.
The project-structure is like this:
Project
+ plugin
+ web-application
The reactor compiles first the plugin, then the application.
The usual mvn-command is:
mvn
... who is triggering the <defaultGoal>plugin:scaffold package</defaultGoal>
On fresh machines the build fails because the plugin is not yet known at the time the reactor plan the build-phases. So I have to call mvn install first. Then mvn plugin:scaffold package works like a charm.
The problem is: Whenever I modify the scaffolder-plugin and call mvn plugin:scaffold package the modifications of the scaffolder-plugin is not yet used because it is not yet installed into the repository. So I have to call mvn install first again.
Is there a way to:
Install the modification to the plugin
Build the webapplication using the modifications of the plugin
in one step?

First your plugin must be a module of the root project for the resolution to work correctly:
<modules>
<module>plugin</module>
<module>app</module>
</modules>
Then declare the plugin in the build/plugins section your application pom
<build>
<plugins>
<plugin>
<groupId>org.example.plugin</groupId>
<artifactId>plugin</artifactId>
<version>${project.parent.version}</version>
<executions>
<execution>
<id>sayhi</id>
<phase>generate-sources</phase>
<goals>
<goal>sayhi</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
The first time you run the plugin or when the plugin changes you need to run at least the package phase so the plugin jar is created. It must be run from the root project:
mvn package
The plugin will be executed during the generate-sources phase:
[INFO] --- plugin:1.0-SNAPSHOT:sayhi (sayhi) # app ---
[INFO] Hello, world.
[INFO]
When you change the plugin just run (again from root project):
mvn package
and you will see the changes:
[INFO] --- plugin:1.0-SNAPSHOT:sayhi (sayhi) # app ---
[INFO] Hello, worldxxxx.
[INFO]
See a full example on Github

Related

spring-boot:run in a Maven Multi-Module Project without mvn install [duplicate]

I have a multi-module maven project like this:
my-parent
--my-domain
--my-service
--my-app <<< this is a Spring Boot module
I want to run mvn spring-boot:run command directly from the parent module without having to cd into the 'my-app' directory first.
I figure this is related to configuration of the spring-boot-maven-plugin but I can't seem to get it right.
I have tried the following:
Use spring-boot-starter-parent and otherwise default config with spring-boot-maven-plugin included in plugins section of my-app.
Running mvn spring-boot:run from the parent results in:
Failed to execute goal org.springframework.boot:spring-boot-maven-plugin:1.4.2.RELEASE:run (default-cli) on project my-parent: Unable to find a suitable main class, please add a 'mainClass' property -> [Help 1] in the parent module
Do NOT use spring-boot-starter-parent.
Define spring-boot-dependencies in depManagement as described elewhere. Define spring-boot-maven-plugin in pluginManagement section of my-parent and include the plugin in plugins section of my-app module.
Running mvn spring-boot:run from the parent results in same error as #1:
Failed to execute goal org.springframework.boot:spring-boot-maven-plugin:1.4.2.RELEASE:run (default-cli) on project my-parent: Unable to find a suitable main class, please add a 'mainClass' property -> [Help 1]
Do NOT use spring-boot-starter-parent.
Define spring-boot-dependencies in depManagement as described elewhere. Define spring-boot-maven-plugin in plugins section of my-app.
Running mvn spring-boot:run from the parent results in:
No plugin found for prefix 'spring-boot' in the current project and in the plugin groups
In all cases described above, running mvn spring-boot:run from the my-app directory works fine.
I figure there should be a way to make this work. In a traditional non-Boot Spring project it was fairly simple to configure tomcat7 plugin such that i could run mvn tomcat7:run-war from the parent and the webapp sub-module would start as expected
You can do it by adding following In parent pom:
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
</plugins>
</build>
And in your
In my-app (Spring Boot module) pom:
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<fork>true</fork>
<skip>false</skip>
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
Now you can do execute in project root:
mvn -pl my-app -am spring-boot:run
Additional references:
spring-boot:run hot reload with multi module maven project · Issue #3436 · spring-projects/spring-boot · GitHub: in particular, this comment.
spring-boot maven plugin configuration options:
skip: skips the execution of sprint-boot:run [default: false]
fork: Flag to indicate if the run processes should be forked [default: true]
see spring-boot maven plugin parameters
maven options:
-pl, --projects: Comma-delimited list of specified reactor projects to build instead of all projects. A project can be specified by [groupId]:artifactId or by its relative path
-am, --also-make: If project list is specified, also build projects required by the list
see maven CLI options

maven: execute without actually building anything

I have a project with finalised version in pom files , lets say 12.3.45 .
I have built the code for this version some time ago already, all the built jars are in the local maven repo.
Then at some point I have run mvn clean, so all the target folders are being removed.
And now I want to execute some code, as quickly as possible, using mvn exec:java. Preferably without building anything, because why not? all the jars at some point were already built, and I know there were no code changes after that. How can I force maven to execute the code as fast as possible , not recompile anything, and just reuse the jars from the local repo?
Thanks.
If your artifacts are in a local or remote repository you can use them as dependencies.
You can use exec-maven-plugin's options includeProjectDependencies or includePluginDependencies to use them in java execution
https://www.mojohaus.org/exec-maven-plugin/java-mojo.html#includePluginDependencies. includeProjectDependencies option is enabled (true) by default.
You can execute exec-maven-plugin without building anything with mvn exec:java command
Instructions:
To run exec-maven-plugin you would need a main class to run. I assume you have one in your project. If you don't - you need to make a separate project with a main class.
Create a blank maven project.
In the project add exec-maven-plugin configuration. Set the mainClass
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<goals>
<goal>java</goal>
</goals>
<configuration>
<mainClass>pack.App</mainClass>
</configuration>
</plugin>
</plugins>
</build>
Include you artifacts as dependencies to the project
<dependencies>
<dependency>
<groupId>my.group</groupId>
<artifactId>myartifact</artifactId>
<version>12.3.45</version>
</dependency>
</dependencies>
Run mvn exec:java to execute com.my.package.MyMainClass main class from my.group.myartifact artifact
Edits:
includeProjectDependencies option is enabled (true) by default

Maven project packaging is war but also building/installing jar

I have a Maven 3.3 project, and the main output is a war file:
<artifactId>pro</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
I am using the maven plugin to also build a jar file, which goes into target/pro-1.0-SNAPSHOT.jar and this works.
I would like to install this jar to the local maven repo, so I'm using the maven install plugin to do this:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-install-plugin</artifactId>
<version>2.5.2</version>
<configuration>
<classifier>jar</classifier>
<packaging>jar</packaging>
<file>target/pro-1.0-SNAPSHOT.jar</file>
</configuration>
<executions>
<execution>
<id>do-jar-install</id>
<phase>install</phase>
<goals>
<goal>install</goal>
</goals>
</execution>
</executions>
</plugin>
The whole build works fine except the jar install step is installing the war, and not the jar. How do I override this?
I'm looking here to see what I can use: http://maven.apache.org/plugins/maven-install-plugin/examples/installing-secondary-artifacts.html
Here is the log from my build:
**
Building jar: /Users/mike/code/workspace/pro/target/pro-1.0-SNAPSHOT.jar
[INFO] --- maven-install-plugin:2.5.2:install (do-jar-install) # pro
[INFO] Installing /Users/mike/code/workspace/pro/target/pro-1.0-SNAPSHOT.jar to /Users/mike/.m2/repository/net/mikeski/pro/1.0-SNAPSHOT/pro-1.0-SNAPSHOT.war
Note the last line - it's picking up the jar but installing a war
How can I fix that?
As requested, here is the jar plugin config:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.4</version>
<executions>
<execution>
<id>create-jar</id>
<phase>install</phase>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
It creates a jar of the files in the project, and it's the correct jar. If I copy the war that is installed in my repo to a jar (so I just change the extension) my other project can pick it up just fine.
Your current output is the result of multiple considerations, one of them being maven-jar-plugin too permissive in version 2.4.
First of all, you need to remember that inside a Maven repository, all the artifacts share a single naming convention, which is artifactId-version(-classifier).packaging. This means that whatever the local name of the file your build is producing (let it be foo.jar), it will be installed and it will be deployed with this conventional name. All that matters when artifacts are installed are the Maven coordinates, i.e. the groupId, the artifactId, the version, the classifier and the packaging.
What is happening here is:
Your project has a packaging war. Running Maven with mvn install, the default-install phase will be invoked first and the maven-install-plugin:install goal will be run a first time, installing your WAR project. On your logs, you will find:
[INFO] --- maven-install-plugin:2.5.2:install (default-install) # test-war ---
[INFO] Installing ...\test-war\target\test-war-0.0.1-SNAPSHOT.war to ...\test-war\0.0.1-SNAPSHOT\test-war-0.0.1-SNAPSHOT.war
[INFO] Installing ...\test-war\pom.xml to ...\test-war\0.0.1-SNAPSHOT\test-war-0.0.1-SNAPSHOT.pom
Then, you are using the maven-jar-plugin:jar goal to create a JAR. This plugin creates a JAR for the current Maven project - so it will create it alright, but the Maven coordinates of this new artifact will be exactly the same as those of your WAR project (you didn't specify a classifier). Therefore, you effectively replace the file of the main artifact (which is a WAR), by a JAR file: you end up with a local file having an extension of jar (because the maven-jar-plugin created it this way) that is the file of the main artifact of a Maven project of packaging war. Quite confusing.
Remember that I said that the maven-jar-plugin was too permissive? If you update to version 3.0.2 of the plugin, you will get an error right here (MJAR-198):
You have to use a classifier to attach supplemental artifacts to the project instead of replacing them. -> [Help 1]
which summarizes what is said above.
Finally, you declared another execution of the maven-install-plugin called do-jar-install, that is supposed to install this local JAR file. And this is what it does: it installs the local JAR file inside your target folder to your local Maven repository using the coordinates of the artifact. The confusion comes from the fact that the type (packaging) of the artifact is in fact WAR, so what gets installed is a WAR file (being effectively a JAR)...
Now that we've explained the issue, the question is: what do you want to do? It looks like you want to attach to your WAR project an additional artifact composed of the classes of it. There is no need for all this configuration, you can just use the attachClasses parameter of the maven-war-plugin.
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>2.6</version>
<configuration>
<attachClasses>true</attachClasses>
</configuration>
</plugin>
You received this because double invocation of plugin :
execution phase
package - default phase
If there is no strong reason and all you care is to have just one JAR as artifact from the project, use one among them.
something like :
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.6</version>
<configuration>
<outputDirectory>${outputDirectory}</outputDirectory>
</configuration>
</plugin>

Adding Grails command to Maven phases -- what am I doing wrong?

I need to build my Grails project with Maven, and it is necessary to add an additional grails command. I'm using the grails-maven-plugin to create the pom file, and I can build the war file with $ mvn package
While building this application, I will need to execute another grails command, one the does not correspond directly to any of the maven build phases. Referring to the docs, I'm adding a second execution element to the grails-maven plugin, as follows:
<plugin>
<groupId>org.grails</groupId>
<artifactId>grails-maven-plugin</artifactId>
<version>${grails.version}</version>
<extensions>true</extensions>
<executions>
<execution>
<goals>
<goal>init</goal>
<goal>maven-clean</goal>
<goal>validate</goal>
<goal>config-directories</goal>
<goal>maven-compile</goal>
<goal>maven-test</goal>
<goal>maven-war</goal>
<goal>maven-functional-test</goal>
</goals>
</execution>
<execution>
<id>stats</id>
<phase>init</phase>
<goals>
<goal>exec</goal>
</goals>
<configuration>
<command>stats</command>
</configuration>
</execution>
</executions>
</plugin>
For this example I'm trying to execute grails stats in the maven init phase. (Eventually, stats will be replaced by something more useful.) when I run:
$ mvn package
the ouput includes:
[INFO] [grails:validate {execution: default}]
[INFO] [grails:init {execution: default}]
[INFO] [grails:config-directories {execution: default}]
[INFO] [resources:resources {execution: default-resources}]
which evidently doesn't contain the execution of grails stats. I am able to execute the stats command through Maven directly, in the following way:
$ mvn grails:exec -Dcommand=stats
it only fails to execute when added as a goal in the pom.
I'm using Java 1.5.0_22, Grails 1.3.7, and Maven 2.2.1.
Based on the information I could find about this plugin, you should add the grails: prefix to your goals.
I have no experience with this plugin, so I could be wrong =)
References:
http://grails.1312388.n4.nabble.com/grails-maven-plugin-version-td2284532.html
http://www.grails.org/Maven+Integration
so for example: <goal>grails:init</goal>
OK, my problem was confusing goals and Maven phases. Notice I was trying
<phase>init</phase>
and I had tried other items from the list of goals, but these are not Maven phases.
http://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html

Maven android compiling multiple source directories

I have created a maven android project using this archetype. I want to integrate mirah source files inside my project. So I added the plugin mentioned here to my pom.xml. I setup the configuration section for the plugin to point the source directory to src/main/mirah.
But when I run mvn compile it only compiles the sources inside src/main/java. I have tried running it with mvn -X compile to try and debug the issue, but I can't find anything related to mirah or the mirah-maven-plugin there.
Using the archetype it created two projects - project and project-it (tests) , there is a pom.xml in the root directory as well as a pom.xml in project and project-it directories. I have tried the above configurations in both the root directory as well as in project's pom.xml.
I have come across this question related to using the build-helper plugin but I don't know if it will help in my case. Since my mirah plugin isn't getting called at all.
Is this the right way to do what I'm trying to do? Any help on the setup, or pointer to how to troubleshoot this would be much appreciated.
The relevant bit of my pom.xml
<plugin>
<groupId>org.mirah.maven</groupId>
<artifactId>maven-mirah-plugin</artifactId>
<version>1.0</version>
<configuration>
<sourceDirectory>src/main/mirah</sourceDirectory>
<outputDirectory>target/classes</outputDirectory>
<bytecode>true</bytecode>
<verbose>false</verbose>
</configuration>
<executions>
<execution>
<phase>compile</phase>
<goals><goal>compile</goal></goals>
</execution>
</executions>
</plugin>
Edited as per answer below.
I have added the source directory using the build-helper plugin and I'm able to get the mirah sources to compile using mvn org.mirah.maven:maven-mirah-plugin:1.0:compile from the answer below. But mvn compile still only compiles the sources in src/main/java and not src/main/mirah.
For anyone interested in the output of mvn -X compile here is the pastie.
This page https://github.com/calavera/maven-mirah-plugin#readme says that the mirah plugin extends the default compiler plugin. So this would suggest that the build helper plugin would work for multiple source directories, if it works for the default compiler plugin.
Looking at the mirah plugin, you probably don't need to specify sourceDirectory and outputDirectory yourself, as it seems you're using the defaults.
The -X switch won't have any impact on the mirah plugin directly, as it doesn't do any tracing itself (above what the default compiler plugin does).
Can you show your -X output anyway to show that the mirah plugin isn't invoked?
Alternatively, you could build the mirah plugin yourself and add tracing. It doesn't seem a complicated plugin.
What happens when you try and invoke the plugin directly? E.g.
mvn org.mirah.maven:maven-mirah-plugin:1.0:compile
EDIT:
Tried it myself and this works for me (by 'works' I mean the plugin gets invoked - my build actually fails).
<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>temp</groupId>
<artifactId>temp</artifactId>
<version>0.0.1-SNAPSHOT</version>
<build>
<plugins>
<plugin>
<groupId>org.mirah.maven</groupId>
<artifactId>maven-mirah-plugin</artifactId>
<version>1.0</version>
<configuration>
<bytecode>true</bytecode>
<verbose>true</verbose>
</configuration>
<executions>
<execution>
<phase>compile</phase>
<goals>
<goal>compile</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
With this output:
D:\dev\workspaces\3.6\temp>mvn compile
[INFO] Scanning for projects...
[INFO] ------------------------------------------------------------------------
[INFO] Building Unnamed - temp:temp:jar:0.0.1-SNAPSHOT
[INFO] task-segment: [compile]
[INFO] ------------------------------------------------------------------------
[INFO] [resources:resources {execution: default-resources}]
[WARNING] Using platform encoding (Cp1252 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] Copying 0 resource
[INFO] [compiler:compile {execution: default-compile}]
[INFO] Nothing to compile - all classes are up to date
[INFO] [mirah:compile {execution: default}]
[INFO] No sources to compile
Parsing...
D:\dev\workspaces\3.6\temp\src\main\mirah/test.mirah
Inferring types...
* [Mirah::Typer] Learned local type under #<Mirah::AST::StaticScope:0xbc5245> : a = Type(int)
... ETC ...
[ERROR] BUILD ERROR
[INFO] ------------------------------------------------------------------------
[INFO] Unknown error - Unknown Error (20047) - D:\dev\workspaces\3.6\temp\target\classes\D:
I don't know what the error means as I'm not a mirah user.

Categories

Resources