I want to change maven project's active profile from within the maven project.
The java project has 3 classes having main methods and they are executed one by one, All of these require different set of dependencies.
I would like to run these classes with different maven profiles.
For example my project project1 is a maven project and is getting invoked by mvn clean package spring-boot:run command.
When the control comes to the project1 it executes the java classes one by one.
My requirement is that when ClassA is run it should change the current maven profile to profile1 (recompiling the same project is ok, performance is not priority). Similarly when ClassB gets invoked it should change the current maven profile to Profile2.
(Note these classes are dynamically picked from directory using reflection and only the class will know what profile it supports)
Is there any way maven allows this at runtime.
If not what is the best way to achieve this.
maven profiles are not designed for such tasks, what you are actually need to do is to setup different executions for each class:
...
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<id>run-clsa</id>
<goals>
<goal>run</goal>
</goals>
<phase>none</phase>
<configuration>
<mainClass>ClassA</mainClass>
</configuration>
</execution>
<execution>
<id>run-clsb</id>
<goals>
<goal>run</goal>
</goals>
<phase>none</phase>
<configuration>
<mainClass>ClassB</mainClass>
</configuration>
</execution>
</executions>
...
and run that in following way:
mvn clean package spring-boot:run#run-clsa
mvn clean package spring-boot:run#run-clsb
Related
Is there a way to include a test folder for Maven to compile from the command line?
I have a set of tests that are in a folder that are not part of the standard set of unit and integration tests. These tests are still useful to run individually until the needed integration tests are built. In Eclipse, I can run these tests individually by right clicking on them and running them as a JUnit test. I am finding that I often want to run more than one test, so I am trying to run them from Maven on the command line. In Maven I can do something like this:
mvn -Dtest=OldTest,OlderTest test
The problem I think I have is that the folder that these tests sit in is not listed as part of the set of test files that need to compile in the POM. I would like to temporarily add the folder, run the tests, and remove the folder without modifying the POM.
I use the Build Helper plugin to add in integration test sources when a certain profile has been activated, for example:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>1.4</version>
<executions>
<execution>
<id>add-test-source</id>
<phase>generate-test-sources</phase>
<goals>
<goal>add-test-source</goal>
</goals>
<configuration>
<sources>
<source>src/it/java</source>
</sources>
</configuration>
</execution>
</executions>
</plugin>
Perhaps you can do something similar?
Sonatype has a repository that I want to deploy a jar file to, and they ask for separate files for application, sources, and javadocs:
Example:
example-application-1.4.7.pom
example-application-1.4.7.jar
example-application-1.4.7-sources.jar
example-application-1.4.7-javadoc.jar
In Scala SBT, I have a command called "package" that generates the jar file for the project, but that only generates "example-application-1.4.7.jar".
Question: What should I do to generate the other two jar files?
In Maven, in order to get the additional -sources and -javadoc artifacts, add to your POM file the following:
<build>
<plugins>
<!-- additional plugin configurations, if any.. -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.0.0</version>
<executions>
<execution>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.10.3</version>
<executions>
<execution>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
Note the snippet above:
We are invoking the Maven Source Plugin to create an additional jar files for sources
We are invoking the Maven Javadoc Plugin to create an additional jar files for javadoc
Executing
mvn clean package
You will find these two additional jars in the target folder.
The .pom file instead is generated during the install phase, but it is not placed under the target folder. Basically, it is a copy of your pom.xml file, with a different extension and used by Maven during the dependency mediation process to check which transitive dependencies are required by the concerned artifact.
Executing
mvn clean install
Maven will install the artifact in your local cache (in your machine), under path_to_cache/.m2/repository/your_groupId/your_artifactId/your_version/. In this folder, you will also find the .pom file, which normally you don't need to distribute (it is created automatically by Maven).
Further note: you probably don't want to generate these additional jar files at each and every build, so to speed up normal builds and have them only on demand, you could wrap the snippet above in a Maven profile.
You can achieve this by removing the snippet above from your build section and add a further section at the end of your pom:
<profiles>
<profile>
<id>prepare-distribution</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.0.0</version>
<executions>
<execution>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.10.3</version>
<executions>
<execution>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
So that normal builds would not create these jars anymore, but when executing the following:
mvn clean install -Pprepare-distribution
You would instead get them back. the -P option is actually activating on demand the profile defined with the id prepare-distribution.
With Maven 3 a default profile already comes as part of the super pom which perform exactly the same actions (sources and javadoc artifact), hence no need to add anything to your existing project. Simply run:
mvn clean install -Prelease-profile
Or, to activate it via a property
mvn clean install -DperformRelease=true
However, as also specified in the super pom, this profile may be removed in future releases (although there since first Maven 3 version till version 3.3.9 so far)
NOTE: The release profile will be removed from future versions of the super POM
The main reason behind this warning is most probably to push for the usage of the Maven Release Plugin, which indirectly makes use of this profile via the useReleaseProfile option of the release:perform goal.
As highlighted by comments, if you are not familiar with maven (especially via console) I would definitely recommend to
Go through the official Maven in 5 minutes documentation for a quick but worthy look.
Play with Maven from the command line, is there where Maven gives you its best. IDE integrations are great, but command line is the real turning point.
Then play with the POM customization above, to get familiar with some concepts and behaviors, first directly as part of your default build, then moved to a profile.
Then, and only then, move to the Maven Release Plugin usage. I recommend it as last step because you would already have acquired more confidence and understanding and see it as less magic and more reasonable approach.
I have a (Maven) project B dependent on project A. Project A packages its tests into a jar, as described here. Suppose I have a test class com.forelight.a.FooTest in projecet A. The class is visible on the test-scoped class path in project B, but is not automatically execute by mvn test. I can extend FooTest in project B's test/main/java directory like so:
package com.forelight.b;
public class FooBarTest extends com.forelight.a.FooTest {}
This does the job (mvn test runs this both command line and under eclipse) but feels kludgy.
Here is a working automated solution:
project A should also provide its test-sources jar
project B should import project A in test scope and also import project A test sources in test scope
project B would use the unpack-dependencies of the Maven Dependencies Plugin to automatically unpack the test-sources jar to a subfolder of the target folder (say project-a-test-sources)
project B would use the add-test-source goal of the Build Helper Maven Plugin to add automatically the unpacked sources as test sources in project A
Maven will then compile and run the added sources as part of project B tests
To achieve it, in project A add the following to the build section:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>test-jar</goal>
</goals>
</execution>
</executions>
</plugin>
This will actually create a new jar as part of the build providing test sources. Remember to install it via mvn install.
In project B, add the following to the dependencies:
<dependency>
<groupId>com.sample</groupId>
<artifactId>project-a</artifactId>
<version>1.0-SNAPSHOT</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.sample</groupId>
<artifactId>project-a</artifactId>
<version>1.0-SNAPSHOT</version>
<scope>test</scope>
<classifier>test-sources</classifier>
</dependency>
So that the classpath will be populated with project A, the second dependency is harmless, it will be used by the plugin execution below.
In project B, also add the following to the build section:
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.2</version>
<executions>
<execution>
<id>unpack-test-sources</id>
<phase>generate-test-sources</phase>
<goals>
<goal>unpack-dependencies</goal>
</goals>
<configuration>
<includeGroupIds>com.sample</includeGroupIds>
<includeArtifactIds>project-a</includeArtifactIds>
<includeScope>test</includeScope>
<includeClassifiers>test-sources</includeClassifiers>
<outputDirectory>
${project.build.directory}/project-a-test-sources
</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>1.10</version>
<executions>
<execution>
<id>add-test-source</id>
<phase>generate-test-sources</phase>
<goals>
<goal>add-test-source</goal>
</goals>
<configuration>
<sources>
<source>${project.build.directory}/project-a-test-sources</source>
</sources>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
Here we are unpacking sources and adding them as test sources.
Maven will then automatically execute the added tests.
Few considerations on this approach:
It might look as kludgy as the approach you mentioned in your question, even though it would be automated and would not require to create new extension tests
It's definitely not something standard, but the original requirement also doesn't sound like a standard practice neither
You may have conflicts on test names or resources names (again, because it's not a standard approach)
You may not want to run these external tests as part of your default build, in this case you could move the configuration above to a Maven profile, say run-project-a-tests and execute them only upon desire via -Prun-project-a-tests. This will also make your default build faster (and more standard).
I have a multi-module Maven project with a master pom and numerous sub-directories each containing projects (and pom.xml files) which refer to the master pom.
In projectA contains an invocation of exec-maven-plugin, which executes the java goal and successfully invokes a test class that resides somewhere in projectA (in projectA/test/com/mycompany/Testclass.java). The plugin is declared as follows:
org.codehaus.mojo
exec-maven-plugin
1.2.1
<execution>
<id>execute-test</id>
<phase>pre-integration-test</phase>
<goals>
<goal>java</goal>
</goals>
<configuration>
<mainClass>com.mycompany.Testclass</mainClass>
<classpathScope>test</classpathScope>
</configuration>
</execution>
</executions>
</plugin>
I execute maven with the following command, and it works fine:
mvn verify -P <profile name> -pl projectA -am
I have a second project, projectB, which depends on projectA. I have configured an exec-maven-plugin section in projectB's pom.xml file that is identical to the one above. When I run maven with the same command as above (except with projectB in the -pl parameter), I get the exception java.lang.ClassNotFoundException: com.mycompany.Testclass.
Clearly this is happening because the classpath when I run maven for projectB does not include the directories in projectA, even though the pom.xml has a dependency on projectA (actually it depends on projectA.1, which in turn depends on projectA).
I have tried switching to use the exec goal rather than the java goal, in projectB, and then providing a classpath in the arguments, like this:
<execution>
<id>execute-test</id>
<phase>pre-integration-test</phase>
<goals>
<goal>exec</goal>
</goals>
<configuration>
<executable>java</executable>
<arguments>
<argument>-classpath</argument>
<argument>"../projectA/target/projectA-6.6.1-bSOURCE-tests.jar;../projectA/target/projectA-6.6.1-bSOURCE.jar"</argument>
<argument>com.mycompany.Testclass</argument>
</arguments>
<classpathScope>test</classpathScope>
</configuration>
</execution>
When I've done that I successfully load the class, but get a ClassNotFoundException on com.google.gson.JsonSyntaxException
That happens to be the same error I get if I run the class from the command line, as follows
java -classpath "projectA/target/projectA-6.6.1-bSOURCE-tests.jar;projectA/target/projectA-6.6.1-bSOURCE.jar" com.mycompany.Testclass
In projectB I think I want to use the java goal of the exec-maven-plugin rather than the exec goal, but one way or the other I have to be able to specify the classpath.
Any ideas how I can do that?
Thanks.
I figured this out myself, and am posting my answer in case anybody else needs it, or in case anybody wants to dispute it (or suggest something better).
What I did was add a dependency in the subordinate project, projectB, as follows:
<dependency>
<groupId>com.mycompany</groupId>
<artifactId>projectA</artifactId>
<version>6.6-SNAPSHOT</version>
<scope>test</scope>
<classifier>tests</classifier>
</dependency>
I believe the clincher was the element, which directed maven to get the dependent classes from the jar file containing the test classes in projectA.
whats the preferred way to upload an artifact via scp to a predefined destination?
i tried using the wagon:upload mojo, but it wont execute atomatically when i defined a "executions" section in my pom like that:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>wagon-maven-plugin</artifactId>
<version>1.0-beta-3</version>
<executions>
<execution>
<phase>release</phase>
<goals>
<goal>upload</goal>
</goals>
</execution>
</executions>
<configuration>
<fromDir>target/checkout/target</fromDir>
<includes>*.jar</includes>
<url>scpexe://host/dir</url>
<toDir />
<serverId>my id</serverId>
</configuration>
</plugin>
i added the necessary extension wagon-ssh and wagon-ssh-external and it all works fine when i execute wagon:upload but it wont upload the artifact automatically in the release phase.
Is this even the right way to upload artifacts to a website, or should the deploy plugin take care of that?
thanks!
That's because no release phase exists (see Maven Lifecycle Reference)
You probably want phase deploy. And yes, wagon is usually used by the maven deploy plugin (automatically when you execute mvn deploy).