Add dependency from custom plugin - java

I'm developing custom Maven plugin. I want my plugin to add a new dependency to a project.
I have the following code:
#Mojo(name = "generate-model", defaultPhase = LifecyclePhase.GENERATE_SOURCES)
public class ModelGeneratorMojo extends AbstractMojo {
#Parameter(defaultValue = "${project}", required = true, readonly = true)
MavenProject project;
#Override
public void execute() throws MojoExecutionException {
Dependency connectivity = new Dependency();
connectivity.setGroupId("groupid");
connectivity.setArtifactId("artifactid");
connectivity.setVersion("1.0");
//noinspection unchecked
project.getDependencies().add(connectivity);
}
}
It seems to have no effect, because when I compile a project containing this plugin, I get unresolved symbol error.
I'm sure that plugin is executed because I see code generated by it (code generation is omitted in my example) in target folder.

I think you should bind the goal in your plugin to the Initialize phase of Maven build process to include the dependency very early in the build process.
Something along these lines:
#Mojo(name = "generate-model", defaultPhase = LifecyclePhase.INITIALIZE)
public class ModelGeneratorMojo extends AbstractMojo {
#Parameter(defaultValue = "${project}", required = true, readonly = true)
MavenProject project;
#Parameter(defaultValue = "${session}", required = true)
MavenSession session;
#Override
public void execute() throws MojoExecutionException {
Dependency connectivity = new Dependency();
connectivity.setGroupId("groupid");
connectivity.setArtifactId("artifactid");
connectivity.setVersion("1.0");
project.getDependencies().add(connectivity);
session.setCurrentProject(project);
}
}
<plugin>
<groupId>com.maventest</groupId>
<artifactId>maven-generate-model</artifactId>
<version>1.0-SNAPSHOT</version>
<executions>
<execution>
<goals>
<goal>generate-model</goal>
</goals>
</execution>
</executions>
</plugin>
I tried multiple paths to accomplish this, but it seems not possible to do using maven plugins, probably maven extension is a better choice here.
The reason is that Depedency Resolution is the first step into Maven lifecycle and you need that extra dependency to compile the application.
With maven extensions, you can extend the maven lifecycle.
https://maven.apache.org/examples/maven-3-lifecycle-extensions.html

Related

Initialize full dependency tree in Maven aggregator plugin

I have an aggregator plugin in Maven with an injected DependencyGraphBuilder. My goal is to resolve the DependencyNode of the current project with all child nodes initialized as well.
#Mojo(name = "mojo", defaultPhase = LifecyclePhase.SITE,
requiresDependencyResolution = ResolutionScope.COMPILE, aggregator = true)
public class MyMojo extends AbstractMojo {
#Component(hint = "default")
private DependencyGraphBuilder dependencyGraphBuilder;
#Parameter(defaultValue = "${reactorProjects}", readonly = true, required = true)
private List<MavenProject> reactorProjects;
}
Currently, if i try to resolve to root node, i am only able to get the dependencies of the current project. I assume that Maven did not resolve that dependencies (only for the current project).
dependencyGraphBuilder.buildDependencyGraph(project, null, reactorProjects);
Summing up:
How can i resolve the child nodes to build to full dependency tree
using DependencyGraphBuilder in a Maven reactor project or is this not possible for aggregator projects?
Additional Info:
I have looked at similar questions, but all of those did not assume an aggregator project.
Since you are trying to implement mvn dependency:tree why not to copy the solution from the Maven Dependency Plugin. Take a look at TreeMojo which also uses DependencyGraphBuilder with DependencyNodeVisitor.

Apache Maven Assembly Plugin not working with OSGi bundles

I have a Maven OSGi multi-module project. The project runs perfectly well when the OSGi picks the module jars from the individual project modules. (view 1.1.B below).
However, using a second approach, bundle.getRegisteredServices() (view 1.1.A below) returns null whenever I try using bundles deposited into a central folder (D:/parent/provider/target/modules) using the maven-assembly-plugin version : 2.6:
framework.getBundleContext().installBundle("file:D:/parent/provider/target/modules/OSGiDmHelloWorldProvider-1.0.jar");
framework.getBundleContext().installBundle("file:D:/parent/provider/target/modules/OSGiDmHelloWorldConsumer-1.0.jar");
View 1.1.C below for console output using the second approach.
1.1.A
if (bundle.getRegisteredServices() != null) {
for (ServiceReference<?> serviceReference : bundle.getRegisteredServices())
System.out.println("\tRegistered service: " + serviceReference);
}
Why can't I access the bundles with the second approach?
GitHub
I have a SSCCE on GitHub HERE. Running the main class will show my predicament.
Thank you all in advance.
1.1.B
package main;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.ServiceLoader;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleException;
import org.osgi.framework.Constants;
import org.osgi.framework.ServiceReference;
import org.osgi.framework.launch.Framework;
import org.osgi.framework.launch.FrameworkFactory;
public class App {
public static void main(String[] args) throws BundleException, URISyntaxException {
App app = new App();
app.initialize();
}
private void initialize() throws BundleException, URISyntaxException {
Map<String, String> map = new HashMap<String, String>();
// make sure the cache is cleaned
map.put(Constants.FRAMEWORK_STORAGE_CLEAN, Constants.FRAMEWORK_STORAGE_CLEAN_ONFIRSTINIT);
map.put("ds.showtrace", "true");
map.put("ds.showerrors", "true");
FrameworkFactory frameworkFactory = ServiceLoader.load(FrameworkFactory.class).iterator().next();
Framework framework = frameworkFactory.newFramework(map);
System.out.println("Starting OSGi Framework");
framework.init();
loadScrBundle(framework);
framework.getBundleContext().installBundle("file:D:/parent/provider/target/OSGiDmHelloWorldProvider-1.0.jar");
framework.getBundleContext().installBundle("file:D:/parent/consumer/target/OSGiDmHelloWorldConsumer-1.0.jar");
for (Bundle bundle : framework.getBundleContext().getBundles()) {
bundle.start();
System.out.println("Bundle: " + bundle.getSymbolicName());
if (bundle.getRegisteredServices() != null) {
for (ServiceReference<?> serviceReference : bundle.getRegisteredServices())
System.out.println("\tRegistered service: " + serviceReference);
}
}
}
private void loadScrBundle(Framework framework) throws URISyntaxException, BundleException {
URL url = getClass().getClassLoader().getResource("org/apache/felix/scr/ScrService.class");
if (url == null)
throw new RuntimeException("Could not find the class org.apache.felix.scr.ScrService");
String jarPath = url.toURI().getSchemeSpecificPart().replaceAll("!.*", "");
System.out.println("Found declarative services implementation: " + jarPath);
framework.getBundleContext().installBundle(jarPath).start();
}
}
1.1.C
Starting OSGi Framework
Found declarative services implementation: file:/C:/Users/Revilo/.m2/repository/org/apache/felix/org.apache.felix.scr/1.6.2/org.apache.felix.scr-1.6.2.jar
INFO : org.apache.felix.scr (1): Version = 1.6.2
DEBUG: Starting ComponentActorThread
Bundle: org.apache.felix.framework
Registered service: [org.osgi.service.resolver.Resolver]
Registered service: [org.osgi.service.packageadmin.PackageAdmin]
Registered service: [org.osgi.service.startlevel.StartLevel]
Bundle: org.apache.felix.scr
Registered service: [org.apache.felix.scr.ScrService]
Registered service: [org.osgi.service.cm.ManagedService]
Registered service: [org.apache.felix.scr.impl.ScrGogoCommand]
Bundle: null
Bundle: null
I had to do a lot to get your sample to duplicate the question.
First off your reactor order is wrong in the parent. That is why you have to do mvn install all the time.
<modules>
<module>OSGiDmHelloWorldProvider</module>
<module>OSGiDmHelloWorldConsumer</module>
<module>main</module>
<module>dist</module>
</modules>
Next, if you define a dependency (e.g. JUnit) in the parent you don't need to redfine it in the children.
Next, it is conventional to put the parent tag at the top of the pom.
I don't see a reason to have your child modules have a different version to the parent so I removed the tag so they all have 1.0-SNAPSHOT from the parent.
Next, you have the wrong group id in the OSGiDmHelloWorldProvider dependency (it should be rev).
<dependency>
<groupId>rev</groupId>
<artifactId>OSGiDmHelloWorldProvider</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
In the main module you have a dependency that isn't in the reactor. I am guessing this is just an oversight of the sample.
<dependency>
<groupId>rev</groupId>
<artifactId>core</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
After all that, mvn clean package -DskipTests=true works.
You have a hard-coded string in your Main class that obviously doesn't work for me. (You also might want to look at the free IDEA Community instead of Eclipse!)
String baseDir = "D:/standAloneDev/java/workingDir/Sample Projects/Eclipse/Gen/OSGiDmHelloWorld/dist/target/dist-1.0-SNAPSHOT-bin/plugins/";
You should make this relative. e.g.
File baseDir = new File("dist/target/dist-1.0-SNAPSHOT-bin/plugins/");
String baseDirPath = baseDir.getAbsolutePath();
loadScrBundle(framework);
File provider = new File(baseDirPath, "OSGiDmHelloWorldProvider-1.0-SNAPSHOT.jar");
File consumer = new File(baseDirPath, "OSGiDmHelloWorldConsumer-1.0-SNAPSHOT.jar");
framework.getBundleContext().installBundle(provider.toURI().toString());
framework.getBundleContext().installBundle(consumer.toURI().toString());
Anyway, after getting it going I noticed the following javadoc on bundle.getSymbolicName().
Returns the symbolic name of this bundle as specified by its Bundle-SymbolicName manifest header. The bundle symbolic name should be based on the reverse domain name naming convention like that used for java packages.
So in the MANIFEST.MF of org.apache.felix.scr-1.6.2.jar you have
Bundle-Name: Apache Felix Declarative Services
Bundle-SymbolicName: org.apache.felix.scr
You don't have this in yours as you are not creating a manifest and adding it to a jar.
You need to add an execution phase and tell the jar plugin to use the manifest:
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<executions>
<execution>
<id>bundle-manifest</id>
<phase>process-classes</phase>
<goals>
<goal>manifest</goal>
</goals>
</execution>
</executions>
<extensions>true</extensions>
<configuration>
<instructions>
<Bundle-SymbolicName>OSGiDmHelloWorldProvider</Bundle-SymbolicName>
<Export-Package>com.bw.osgi.provider.able</Export-Package>
<Bundle-Activator>com.bw.osgi.provider.ProviderActivator</Bundle-Activator>
<Bundle-Vendor>Baptiste Wicht</Bundle-Vendor>
</instructions>
</configuration>
</plugin>

Maven MOJO: Get execution configuration in runtime

I am developing a maven plugin.
When maven instantiates the mojo class, fields annotated as #Parameter will be "dependency injected" by maven, as childenodes are defined inside the project/build/plugins/plugin/executions/execution tag.
Like this:
#Parameter(defaultValue = "${basedir}/src", alias = "src")
private String sourcePath;
will be filled by
<configuration>
<src>${basedir}/whatever</src>
</configuration>
.
Is there a way to get the configuration via some java calls?
I know that I can use
public Xpp3Dom org.apache.maven.plugin.MojoExecution.getConfiguration()
to retrieve that configuration, the problem is that properties are not resolved in this case, so I get "${basedir}/whatever" for sourcePath, ${} of properties are not resolved. I need them resolved, whatever property they are.
Is there a way to get the resolved values runtime?
Thanks
Annotate your mojo with:
#Mojo(name = "mymojoid", defaultPhase = LifecyclePhase.PACKAGE, requiresDependencyResolution = ResolutionScope.COMPILE_PLUS_RUNTIME)
public class MyMojo extends AbstractMojo{}
Then the values will automatically be resolved

Maven Codehaus findbugs plugin "onlyAnalyze" option not working as expected

Update for the impatient: it's simple, use package.- for sub-package scanning instead of package.*, as-per martoe's answer below!
I cannot seem to get onlyAnalyze working for my multi-module project: regardless of what package (or pattern) I set, maven-findbugs-plugin doesn't evaluate sub-packages as I'd expect from passing it packagename.*.
To prove either myself or the plugin at fault (though I always assume it's the former!), I setup a small Maven project with the following structure:
pom.xml
src/
main/java/acme/App.java
main/java/acme/moo/App.java
main/java/no_detect/App.java
which is very simple!
The POM has the following findbugs configuration:
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>findbugs-maven-plugin</artifactId>
<version>2.4.0</version>
<executions>
<execution>
<phase>verify</phase>
<goals><goal>findbugs</goal><goal>check</goal></goals>
</execution>
</executions>
<configuration>
<debug>true</debug>
<effort>Max</effort>
<threshold>Low</threshold>
<onlyAnalyze>acme.*</onlyAnalyze>
</configuration>
</plugin>
</plugins>
</build>
and every App.java has the following code with two obvious violations:
package acme;
import java.io.Serializable;
public class App implements Serializable
{
private static final class NotSer {
private String meh = "meh";
}
private static final NotSer ns = new NotSer();// Violation: not serializable field
public static void main( String[] args )
{
ns.meh = "hehehe";// Vilation: unused
System.out.println( "Hello World!" );
}
}
Note that no_detect.App has the same content as above, but my expectation is that it wouldn't be evaluated by findbugs because I have the "onlyAnalyze" option set to acme.* which I assume would evaluate acme.App and acme.moo.App and nothing else.
I now execute a mvn clean install to clean, build, test, run findbugs, package, install, which produces the following findbugs report (snipped for brevity) and results in a build failure which is expected because acme.App and acme.moo.App:
<BugInstance category='BAD_PRACTICE' type='SE_NO_SERIALVERSIONID' instanceOccurrenceMax='0'>
<ShortMessage>Class is Serializable, but doesn't define serialVersionUID</ShortMessage>
<LongMessage>acme.App is Serializable; consider declaring a serialVersionUID</LongMessage>
<Details>
<p> This field is never read.&nbsp; Consider removing it from the class.</p>
</Details>
<BugPattern category='BAD_PRACTICE' abbrev='SnVI' type='SE_NO_SERIALVERSIONID'><ShortDescription>Class is Serializable, but doesn't define serialVersionUID</ShortDescription><Details>
<BugCode abbrev='UrF'><Description>Unread field</Description></BugCode><BugCode abbrev='SnVI'><Description>Serializable class with no Version ID</Description></BugCode>
To summarise: only acme.App is analysed, acme.moo.App isn't (bad) and neither is no_detect.App (good).
I tried with two wildcards in the onlyAnalyze option but that produces a successful build but with a findbugs error (Dangling meta character '*' etc).
I tried with onlyAnalyze set to acme.*,acme.moo.* which analyzes all the expected classes (acme.App and acme.moo.App) which means it "works" but not as I expect; i.e. I have to explicitly declare all parent-packages for the classes I want to analyze: that could get large and difficult to maintain on a multi-module project!
Do I have to define every package I want analyzed, or can I declare a wildcard/regex pattern that will do what I want?
I'd rather not use the inclusion/exclusion XML because that requires far more setup and reasoning that I don't currently have time for...
To cite the Findbugs manual: "Replace .* with .- to also analyze all subpackages"

Maven doesn't run TestNG tests generated by groovy compiler

I have a java project with tests written in groovy.
I use TestNG as unit testing framework.
I also have several tests written in java.
After maven test-compile phase all tests (both groovy and java) are compiled and placed in the similar folder inside target/test-classes/.
When I want to run tests with maven, only java tests are run.
When I tried to run groovy test from the IDE (IntelliJ IDEA), it runs perfectly.
I decompiled groovy test and here is what I have:
package mypackage.core;
import groovy.lang.GroovyObject;
import groovy.lang.MetaClass;
import org.codehaus.groovy.runtime.ScriptBytecodeAdapter;
import org.codehaus.groovy.runtime.callsite.CallSite;
import org.testng.annotations.Test;
#Test
public class Sample
implements GroovyObject
{
public Sample()
{
Sample this;
CallSite[] arrayOfCallSite = $getCallSiteArray();
this.metaClass = $getStaticMetaClass();
MetaClass tmp20_17 = this.metaClass;
this.metaClass = ((MetaClass)ScriptBytecodeAdapter.castToType(tmp20_17, $get$$class$groovy$lang$MetaClass()));
tmp20_17;
while (true)
return;
}
#Test
public void testSomething()
{
CallSite[] arrayOfCallSite = $getCallSiteArray(); Registry registry = arrayOfCallSite[0].callConstructor($get$$class$mypackage$core$internal$Registry());
arrayOfCallSite[1].call(registry, null); for (return; ; return);
}
static
{
tmp10_7 = new Long(0L);
__timeStamp__239_neverHappen1314379332415 = (Long)tmp10_7;
tmp10_7;
tmp28_25 = new Long(1314379332415L);
__timeStamp = (Long)tmp28_25;
tmp28_25;
Class tmp48_45 = ((Class)ScriptBytecodeAdapter.castToType($get$$class$mypackage$core$Sample(), $get$$class$java$lang$Class()));
$ownClass = (Class)tmp48_45;
tmp48_45;
return;
while (true)
return;
}
}
Has anyone met similar issue? What can be wrong here?
Can it be connected with the fact that class Sample implements GroovyObject? Can it be connected with bad surefire version?
Thanks!
UPD:
Groovy-related settings in pom.xml:
<dependency>
<groupId>org.codehaus.groovy.maven.runtime</groupId>
<artifactId>gmaven-runtime-1.6</artifactId>
<version>1.0</version>
<scope>test</scope>
</dependency>
...
<plugin>
<groupId>org.codehaus.groovy.maven</groupId>
<artifactId>gmaven-plugin</artifactId>
<version>1.0</version>
<executions>
<execution>
<goals>
<goal>generateTestStubs</goal>
<goal>testCompile</goal>
</goals>
</execution>
</executions>
</plugin>
Groovy tests are placed in mymodule/src/test/groovy/.., java tests are placed in mymodule/src/test/java/...
After test-compile phase they both are in mymodule/target/test-classes/...
I don't have special section for surefire in my pom.xml, but from looking at local repository .m2 I can say that surefire plugin of version 2.4.3 is being used.
Test classes must end with "Test" in order to be selected by maven test phase. Just rename the class to SampleTest.

Categories