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().
Related
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.
I am creating a generic utils maven project. I have added this utils project as a dependency into my main maven project. It looks like I can use plugins in my utils pom to generate an executable jar. If the jar is executable, could I run it in my main project by adding it as a dependency? If I can, how do I add the path of the dependency to the exec-maven-plugin?
main_pom.xml
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.2.1</version>
<executions>
<execution>
<id>default-cli</id>
<goals>
<goal>exec</goal>
</goals>
<configuration>
<executable>java</executable>
<arguments>
<argument>-jar</argument>
<!-- How can I get the dependency path here? -->
<argument>path/to/executable-dependency-jar/name.jar</argument>
</arguments>
</configuration>
</execution>
</executions>
</plugin>
I want it as a dependency for convenience. But I don't know if a dependency can be executable. And I don't know how to get the dependency path as shown above in the xml. My idea was to:
Add an executable dependency.
Add maven exec plugin to run the
executable dependency as shown above.
When I want my utils ran I
would just have to execute mvn exec:exec.
Not sure what you're trying to do, but you can have an executable jar, and use it in another project.
But in this case, you don't need to call it as an executable. This is way simpler to just call some java code.
An executable jar is basically a jar with at least one class containing a valid main method (plus a manifest to know which class is the main class).
You can use this class from your Java code, without going "out" of the jvm, and use your jar as an executable.
And yet, you keep the ability to call your executable jar from outside (i.e from command line).
Typically, you have a business method doStuff(some signature), that you can call from any java code (this might be a static method) and main methods that just parses the command line arguments and calls the doStuff method.
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.
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.
So, I've been wanting to use Lombok for a while - and I'm finally starting a project where I will be able to use it. The important thing to note is that this will be a large, enterprise-grade application and thus the integration patterns used have to be meaningful, with as few hacks as possible.
So I've taken a look at the lombok-maven-plugin, and the whole delombok fudge. I understand this is going to duplicate all my code, and expand the lombok annotations where present. This gives me a second set of generated .java files that need to be used by maven during compilation.
However, by generating these new source files - eclipse picks them up and attempts to pull them into my project. Thus it fires off a million (OK, slight exaggeration) errors about duplicate classes.
Some solution suggest I change the <sourceDirectory> in my POM. This makes things no better, as a mvn eclipse:eclipse will now completely omit my src/main/java java directory from the project - only showing me the output from the delombok process.
Then come the suggestions that I need to use one profile to compile / package the project, and another to mvn eclipse:eclipse. This is not an acceptable solution, as I’m having to spend enough time maintaining / explaining my already complex maven setup – without having to introduce an entire new profile (in addition to my existing profiles).
I’m hoping for some inspiration to save me from writing off Lombok for my project. It’s a great tool to reduce boilerplate code, but it simply doesn’t seem ready for prime-time enterprise usage – which I find very disappointing :-(
The following is my current POM:
<build>
<sourceDirectory>target/generated-sources/delombok</sourceDirectory>
<testSourceDirectory>target/generated-test-sources/delombok</testSourceDirectory>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
<plugin>
<groupId>org.projectlombok</groupId>
<artifactId>lombok-maven-plugin</artifactId>
<version>1.12.2.0</version>
<dependencies>
<dependency>
<groupId>sun.jdk</groupId>
<artifactId>tools</artifactId>
<version>1.7</version>
<scope>system</scope>
<systemPath>${java.home}/../lib/tools.jar</systemPath>
</dependency>
</dependencies>
<executions>
<execution>
<id>delombok</id>
<phase>generate-sources</phase>
<goals>
<goal>delombok</goal>
</goals>
<configuration>
<encoding>UTF-8</encoding>
<addOutputDirectory>false</addOutputDirectory>
<sourceDirectory>src/main/java</sourceDirectory>
</configuration>
</execution>
<execution>
<id>test-delombok</id>
<phase>generate-test-sources</phase>
<goals>
<goal>testDelombok</goal>
</goals>
<configuration>
<encoding>UTF-8</encoding>
<addOutputDirectory>false</addOutputDirectory>
<sourceDirectory>src/test/java</sourceDirectory>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
Which is currently only putting the delomboked code in my eclipse project.
Final note - I'm also quite frustrated that I have to manually install lombok on all the eclipse instasnces we're going to use. Mostly because it's me who will get the phonecall from all the developers that can't get it working. I get why it's not as simple as mvn eclipse:eclipse but I still wanted to note my dissapointment. If we had to manually set up every library for use on each developer's machine, we'd be back in the pre-maven days.
We are successfully using lombok in our project for 1.5 years now. We're not using any delombokification, but instead have lombok as a provided dependency like so
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>0.11.0</version>
<scope>provided</scope>
</dependency>
That's all it needs. We can use the lombok annotations and they are recognized by both eclipse and maven builds. This is even compatible with EclEmma in eclipse, which marks the annotations as (un)covered, when the respective generated code is(n't).
You have to install it on every Eclipse instance manually, since most of the JDT isn't open for eclipse plugins to modify. That's a technical restriction the lombok developers cannot lift. Anyways, the installer is quite simple and never failed me so far.
You don't necessarily need to use lombok-maven-plugin to take advantage of Lombok. As I understand, the delombofication that the plugin does is meant to allow things like code coverage and javadoc to have a full version of the code. Even then, the process would only occur at, say, Javadoc building time.
The question is if your project can live without that. If yes, then just adding lombok as Maven dependency is all you need.
In Eclipse you'll indeed need to install it. Note that the fact the Lombok is still kind of experimental, is perhaps of the reasons it's not included in Eclipse by default.