How to run method with Maven? - java

I have written a console app (.java class with main function), and I'd like to call this main (or, for example some static method before execution of my big project) how to do this with Maven (script?)?

go and look at the exec maven plugin. you can use it to execute either a native executable, a script, or a java main() at any point in the build. like so:
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.3.2</version>
<executions>
<execution>
<goals>
<goal>java</goal>
</goals>
</execution>
</executions>
<configuration>
<mainClass>com.example.Main</mainClass>
</configuration>
</plugin>
</plugins>
</build>
you cannot run just any java method you want, but writing a small class with a main() method that invokes whatever you want is pretty easy.
another gotcha is that the class you want to run has to be compiled before you run it. this means that either this execution has to happen after the compile phase or you need to split your project into 2 modules - one containing the main class and the other containing the rest of you code (that will depend on the 1st module to get proper build order)
if you still insist on arbitrary code, there's always the groovy maven plugin, which allows you to write groovy code inline to be executed during the build.

As an alternative to the exec-maven-plugin you can also use the Apache Maven Scripting Plugin. It can execute scripts in any JSR223 compatible scripting language.
For references on the scripting library options you have, see the following questions:
Java ScriptEngine supported languages
Where can I find a list of available JSR-223 scripting languages?
I have written a more detailed answer on how this plugin works in the following answer:
https://stackoverflow.com/a/73067375/18699445
For your needs on executing any piece of Java code from the current project, you can use the following plugin setup:
<!-- Scripting Plugin: run ScriptEngine compatible scripts -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-scripting-plugin</artifactId>
<version>3.0.0</version>
<executions>
<execution>
<id>run-script</id>
<phase>compile</phase>
<goals>
<goal>eval</goal>
</goals>
</execution>
</executions>
<configuration>
<engineName>beanshell</engineName>
<!-- <scriptFile>use this when possible; no code in the POM is preferred</scriptFile> -->
<script>
log.info("Hello from " + project.getArtifact());
// run code from the current project
// new my.package.MyClass().myMethodToExecute();
</script>
</configuration>
<dependencies>
<!-- Script Engine: Beanshell -->
<dependency>
<groupId>org.apache-extras.beanshell</groupId>
<artifactId>bsh</artifactId>
<version>2.0b6</version>
</dependency>
<!-- Dependency to current project (self) for executing code -->
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>${project.artifactId}</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
</plugin>
You can use any id you like in the execution element.
The phase needs to be compile or later, otherwise you can't use the code from your current project. If you need to execute it earlier, you could put this code in a different artifact or module and depend on that.
By changing the dependency and engineName you can use any other compatible scripting language. You'll need to pick a Java-like language that is capable of calling & executing Java code.
This gives the following example output in the maven build log:
[INFO] --- maven-scripting-plugin:3.0.0:eval (run-script) # tests ---
[INFO] Hello from local:tests:jar:1.0
You can of course remove the "Hello world" and just execute the code you want.

Related

How do I fail a Maven build from inside Java logic?

I am developing a project in which I would like to use Maven to execute a Java Main class as part of the build process. The Main class's job is to validate that some given (currently hardcoded) files are valid RAML files. In a perfect world, I would like the build to be able to fail the build from within this class's logic, if they are invalid, and have that failure report back to the terminal with the "[BUILD FAILURE]" message just like maven does natively.
I added tho org.codehaus.mojo.exec-maven-plugin plugin to my POM, which is allowing me to execute the Java Main class I mentioned earlier. That section of the POM looks like this:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.4.0</version>
<executions>
<execution>
<phase>test</phase>
<goals>
<goal>java</goal>
</goals>
<configuration>
<mainClass>com.example.ubunfu.MainClass</mainClass>
<arguments>
<argument></argument>
</arguments>
<cleanupDaemonThreads>false</cleanupDaemonThreads> <!-- Prevents thread hanging -->
</configuration>
</execution>
</executions>
</plugin>
However, I'm not sure how to signal from the logic inside of MainClass that the build should fail - if that's necessary. I read about the org.apache.maven.plugins.MojoFailureException in the Maven - Guide to Developing Java Plugins. There it seems to say that I can throw one of these and it will fail the build like I'm hoping for.
I'm not sure what I need to do in order to have the MojoFailureException class available to me inside MainClass. I haven't been able to find a JAR or anything, but if I understand how Maven works, this should be fixed with some kind of addition to the POM, not a JAR.
If you have any insight for me on this, I'd really appreciate it.
-Ryan
It appears that throwing any exception will cause the build to fail. See this answer.
To get access to MojoFailureException, add the following dependency:
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-plugin-api</artifactId>
<version>3.3.3</version>
</dependency>
Hint: According to Exec Maven Plugin, Usage <configuration> resides outside of <executions>.
"I would like the build to be able to fail the build from within this class's logic" → Simply throw new RuntimeException().

Getting a version number in Eclipse context root via Maven

I've got a web project where I'd like to have the major version number in the final build name. So for example, it should be myproject-v2.
Using the build-helper-maven-plugin I've managed to get this working in my normal Maven build process by adding the following to my pom:
<build>
<finalName>${project.artifactId}-v${parsedVersion.majorVersion}</finalName>
<plugins>
<!-- Used to build the parsedVersion property for use above -->
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>1.9.1</version>
<executions>
<execution>
<id>parse-version</id>
<goals>
<goal>parse-version</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
That works great via Maven & I get a myproject-v0.war at the end that I can deploy.
But within Eclipse, it always gets deployed as myproject-v${parsedVersion.majorVersion}. So it's not found the new variable - fair enough. But no matter what I try, I can't seem to get Eclipse to pick up the result from the build helper plugin
Does anyone have any suggestions on what I could try? Here's what I have tried already:
* Setting the final build name, the warName property on the maven-war-plugin and the m2eclipse.wtp.contextRoot property to my build name pattern.
* Binding the parse-version to a number of different goals (e.g. clean, package)
But I'm running low on ideas. If I can't do it automatically, I'll just hard code the value but it would be nice to have it done automatically.

Serial execution of plugins in Maven using <phase>

I have the following structure in pom.xml:
<profile>
<id> x </id>
<build>
<finalName> y </finalName>
<plugins>
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<!-- DELETE SOME FOLDERS AND SOME FILES -->
</plugin>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<!-- MOVE A FILE -->
</plugin>
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<version> 1.6 </version>
<executions>
<execution>
<phase> <!-- WHAT COMES HERE ? --> </phase>
<configuration>
<!-- I EXECUTE CMD FILE HERE -->
</configuration>
<goals>
<goal> run </goal>
</goals>
<execution>
<executions>
</plugin>
</plugins>
</build>
</profile>
I want to achieve a serial execution for plugins:
Delete some folders and some files (1st plugin)
Move a file (2nd plugin)
Run cmd file (3rd plugin)
What should I use for <phase> to have the order above (sequential execution)? Is it relevant ? Is it ok to use pre-integration-test for example ?
P.S.: Here are the phases: http://maven.apache.org/ref/3.2.2/maven-core/lifecycles.html
Maven doesn't support adding steps to the life cycle (without writing a new plugin).
If you have complex build steps and you absolutely need a certain order and this order violates the standard life cycle, then Maven might not be the right tool for you. Consider Gradle instead.
If you have to use Maven, then stop using plugins for this. Instead, replicate all the build steps using the antrun plugin so everything is done with a single Ant script. Afterwards, find a place in the life cycle where you want all the steps to be executed at once.
generate-sources is a good place if you need something to be done before anything is compiled. If you want to run code after compilation and tests, use prepare-package.
See here for the complete life cycle: http://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html#Lifecycle_Reference
If you like to add the execution of different plugins to the same life cycle phase the execution order is defined by the order of the definition in the pom file.
So if you choose to bind all the above three plugins to the package phase than they will be executed in the given order.
You can of course use the antrun plugin which will work also and will implicit execute the steps in the defined order without thinking about the default behaviour of Maven.
You can also use the exec-maven-plugin to execute a script in a particular life cycle phase but which might be not a good solution cause the script is OS dependent. Or you can use the groovy plugin to execute some steps in groovy code.

Mechanics of Goal execution in Maven

I have the wsimport plugin in my project.
I would like to execute the wsimport. According to the website, the string to execute is "mvn jaxws:wsimport".
Firstly, is this string deductable from the XML ?
The artifact ID is :
<artifactId>jaxws-maven-plugin</artifactId>
and goal :
<goal>wsimport</goal>
so is the artifact-part just the substring of the artifactid leading up to "-maven-plugin" ?
..And when I execute my plugin goal "mvn jaxws:wsimport" does this completely ignore which phase I am in? Ie. is this running outside of the phase? And if no, is there a way to run this standalone?
ie. is there a way I can set the phase to none? (eg [phase]none[/phase]).
Pom code :
<build>
<plugins>
<plugin>
<groupId>org.jvnet.jax-ws-commons</groupId>
<artifactId>jaxws-maven-plugin</artifactId>
<version>2.3</version>
<executions>
<execution>
<id>wsimport-from-jdk</id>
<goals>
<goal>wsimport</goal>
</goals>
<configuration>
<executable>${tool.wsimport}</executable>
<wsdlUrls>
<wsdlUrl>http://WorkPC:8080/server-web/AirlineWS?wsdl</wsdlUrl>
</wsdlUrls>
<packageName>com.bluewalrus</packageName>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
When you issue a command like mvn [plugin]:[goal], it launches Maven out of any lifecycle, so if you do not intend to perform that goal inside a lifecycle, but only via such commands, you shouldn't have any <execution> defined, just place <configuration> right after <version>.
About how Maven can shorten the plugin call (i.e. mvn dependency:tree instead of mvn org.apache.maven.plugins:maven-dependency-plugin:2.1:tree), it is based on several conventions:
When no version defined, it tries to take the latest from available repositories
When the groupId is omitted, it looks among the predefined or user-defined pluginGroups to find a suitable one. See here for more information (Configuring Maven to Search for Plugins)
On the same page, you can see how plugins prefixes are used to shorten the plugin prefix, by using a prefix instead of the artifactId of the plugin. Thirdparty plugins should use [prefix]-maven-plugin construction, and it looks OK here.
And to disable the default execution of a plugin (although it might not be useful in this case), you can use this answer

Running caliper from eclipse in maven's test scope

I have a Java project in Eclipse, with JUnit tests in my src/test directory. I've also added a class to my tests with Caliper microbenchmarks, and I'd like to be able to run these tests from within Eclipse.
As the Caliper code is test code, I've added Caliper as a dependency in Maven in test scope. That makes it show up in the classpath when I run JUnit tests, but I can't see a way to run an arbitrary class with test dependencies in the classpath. What I tried doing was adding a new Run Configuration for a Java Application, thinking I could launch CaliperMain with the right class as a parameter, but the Caliper jar is not on the classpath and I can't see how to add it.
I don't want to move my benchmark code and dependency into the main scope, as it's test code! It seems seriously overkill to move it into a completely separate project.
You should be able to do this with the Maven Exec Plugin. For my project, I opted to make a benchmark profile that can be run with the maven command mvn compile -P benchmarks.
To configure something like this, you can add something along the lines of the following to your pom.xml, specifying scope of the classpath as test using the <classpathScope> tag:
<profiles>
<profile>
<id>benchmarks</id>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.2.1</version>
<executions>
<execution>
<id>caliper</id>
<phase>compile</phase>
<goals>
<goal>java</goal>
</goals>
<configuration>
<classpathScope>test</classpathScope>
<mainClass>com.google.caliper.runner.CaliperMain</mainClass>
<commandlineArgs>com.stackoverflow.BencharkClass,com.stackoverflow.AnotherBenchmark</commandlineArgs>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
Alternatively, if you'd like to specify a lot of options for caliper, it is probably easier to use the <arguments> tags:
<executions>
<execution>
<id>caliper</id>
<phase>compile</phase>
<goals>
<goal>java</goal>
</goals>
<configuration>
<classpathScope>test</classpathScope>
<mainClass>com.google.caliper.runner.CaliperMain</mainClass>
<arguments>
<argument>com.stackoverflow.BencharkClass</argument>
<argument>--instrument</argument>
<argument>runtime</argument>
<argument>-Cinstrument.allocation.options.trackAllocations=false</argument>
</arguments>
</configuration>
</execution>
</executions>
More configuration options (like -Cinstrument.allocation.options.trackAllocations above) can be found here and more runtime options (like --instrument above) can be found here.
Then, if you are using the Eclipse m2 Maven plugin, you can right-click on your project folder and select Run as... -> Maven Build... and enter something like clean install in the Goals input box and benchmarks in the Profiles input box and click Run and you should see the output in your Eclipse console.
It's important to note that I used a local snapshot build of Caliper by checking out the source using git clone https://code.google.com/p/caliper/, which is recommended at the time of this post in order to take advantage of the latest API.

Categories

Resources