How to execute a specific plugin/Mojo from a pom.xml programmatically? - java

I'm the author of one of the Maven plugins (not Apache/Codehaus, completely indie). Sometimes I get support requests or test cases where I'd really need to debug the execution of my plugin with an existing pom.xml. Basically the test cases I get are sample/test project (pom.xml with src/main/resoures, src/main/java and so on).
What I need is a way to:
Load an existing pom.xml.
Find a specific execution of my plugin there (usually it's the only one).
Get an instance of MyMojo - fully initialized/condigured, with all the components and parameters corectly injected.
Execute MyMojo.
What's important is that test projects are separate projects, I don't want to copy them into the Maven module of my plugin.
I'd like to be able to do this without remote debugging.
By debugging I mean to be able to set and halt on breakpoints (also conditional), step in/out/over on the source code.
Ideally I'd like to be able to executeMyMojoFrom(new File("pom.xml")) - for instance in a JUnit test or a main method of some class. (I can supply groupId, artifactId etc. All other definitions should just be loaded from that pom.xml.)
How can I achieve this?
What I've tried so far:
Debug As... on pom.xml in Eclipse - does not work well enough (source code not found, breakpoint don't work as its not a Java project context)
Maven Embedder/Invoker solutions - spawn things in separate processes via CLI. Forget breakpoints, no debugging.
Remote debugging with mvnDebug and then remote debugging from Eclipse as suggested by Pascal Thivent here. This is so far the best option. However, remote debugging means starting mvnDebug separately, and there's also not guarantee that the JARs I have in Eclipse are exactly the same that mvnDebug is using. So there's a certain distance here.
maven-plugin-testing-harness - I actually thought this this will do the task. But first I was jumping through hoops for a few hours just to make it start. All of the important dependencies are "provided" so I first had to figure out the right combination of versions of these artifacts. And then - only to discover that AbstractMojoTestCase only works within the plugin module you want to test. Probably I was mistaken when I thought that maven-plugin-testing-harness was a testing harness for Maven plugins. It seems that it's a testing harness for the plugin from that plugin's module. Which is not illogical but does not help my case. I'd like to test my plugin in other modules.
So right now I've got the best results with the remote debugging solution. But what I'm looking for is really something like maven-plugin-testing-harness but not hardwired to the plugin module. Does anyone happen to have a hint, if such a method exists somewhere in Maven artifacts?
To be even more specific, I'd like to write something like:
public void testSomething()
throws Exception
{
File pom = getTestFile( "pom.xml" );
assertNotNull( pom );
assertTrue( pom.exists() );
MyMojo myMojo = (MyMojo) lookupMojo( "myGroupId", "myArtifactid", ...,
"myGoal", pom );
assertNotNull( myMojo );
myMojo.execute();
...
}
Compare it to the MyMojoTest here - it's almost there. Should just not be hardwired into the mymojo Maven module (as it is in maven-plugin-testing-harness).
Update
Few answers to the questions in comments:
You mean you don't want such a test class, i.e MyMojoTest to reside inside the same project as the MyMojo, i.e your plugin project? Why is that?
Exactly. I want to debug the plugin execution in an existing Maven project, I don't want to move that project to my plugin project first to be able to run a test. I want to be able to test/debug an existing project. Ideally, I'd just need to add my-maven-plugin-testing dependency and subclass MyMojoTest in the project's src/test/jaca. This would be a good instrument to debug executions. Dragging the target project into my Mojo project ist just too much overhead - and mostly these aren't really the test cases I want to keep long-term. I hope, this answers, why.
Anyway, it's merely a convention to keep the project-to-test/pom.xml inside the src/test/resources of your plugin module, not a rule...
My problem is not the location of the pom.xml of the project-to-test, that is easily configurable. My difficulty is that maven-plugin-testing-harness is is somehow hardcoded to be in the Mojo's project. It uses the pom.xml of the Mojo, looks for other special files/descriptors in the containing project. So I somehow can't use it in a non-Mojo project, or can I? This is my question.
And I'm not sure why Debug as... didn't help you...
Not sure either, but (1) breakpoints did not work and (2) the source code was not "attached" for some reason.

If the Debug as didn't work for you as well as it should, you can try to use the mojo-executor with a bit of work.
https://github.com/TimMoore/mojo-executor
This is how you would execute the copy-dependencies goal of the Maven Dependency Plugin programmatically:
executeMojo(
plugin(
groupId("org.apache.maven.plugins"),
artifactId("maven-dependency-plugin"),
version("2.0")
),
goal("copy-dependencies"),
configuration(
element(name("outputDirectory"), "${project.build.directory}/foo")
),
executionEnvironment(
mavenProject,
mavenSession,
pluginManager
)
);
The project, session, and pluginManager variables should be injected via the normal Mojo injection. Yes, that means this should be executed from the context of another maven plugin. Now that I think about it, whether this would help you in any way is still a question because this still relies on injection of such components by the underlying plexus container.
My original idea was though to have you build a maven plugin that would invoke your jaxb2 plugin thru the mojo-executor like above, then serialize the mavenProject, mavenSession, pluginManager, i.e, all the plexus injected components and then use those objects to invoke your jaxb2 plugin in future from a standalone class without the plugin that you built.

Related

Pitest: How to set paths correct in different modules

I have a huge project for which I am testing mutation testing with Pitest. The project is in an OSGi form and having all modules separated. I have this structure:
|-1.myProgramm-parent
 |-pom.xml
 |-2.myProgramm.module1
  |-pom.xml
 |-2.myProgramm.module1.Test
  |-pom.xml
 |-3.myProgramm.module2
  |-pom.xml
 |-3.myProgramm.module2.Test
   |-pom.xml
... and so on.
Now I put into the pom.xml from my 1.myProgramm-parent all the Pitest configurations I need (taken from the official site of pitest.org). The targetClasses and targetTests are in the pom.xml of 2.myProgramm.module1.Test, which I need to use.
Pitest finds all 7 test classes to minion. And sends them. Then gathering for test description is also fine. Coverage generator Minion excited ok.
Then: created 0 mutation test units.
And a build failure is shown. No mutations found.
I tried already all the possible annotatons shown on pitest.org, like: targetClasses, targetTests and additionalClasspathElements.
How can I say that the testClasses are in this folder 2.myProgramm.module1.Test, where I am setting the targetClasses, targetTests in the pom.xml. BUT the normal javaClasses to be minioned are in this package: 2.myProgramm.module1
How I can tell, go out of your test-folder and get into the folder up?
I also gave the pure path to the folder with the normal javaClasses, but NO reaction.
Do you have an idea?
Ps. It is not my program. I didn't wrote it. I am just working on it, to test. I have already 11 other programs with Maven and Gradle. I get all to minion. But this is such a pain in the butt! ARG!
If you are working with multi-module projects, you will need to use the pitmp plugin (https://github.com/STAMP-project/pitmp-maven-plugin).
This is because PIT itself only mutates classes that are defined in the same module as the tests. In contrast, pitmp will execute the tests for all classes of the modules. More details are provided in the link above.

How to make sure that every ejb-client has an ejb-impl (in an ear)?

We have a lot of ejb-artifacts that are split into client and impl artifacts like
a-client, a-impl, b-client, b-impl, c-client,...
If a needs to call b, we need to add a compile dependency a-impl -> b-client. When we run the ear, classes from b-impl are injected to actually do the work.
The problem:
To run an ear, we need to make sure that for every client, the corresponding impl artifact is present. When we build the artifact with Maven, this is not guaranteed. If I add a-impl to my pom, Maven adds b-client to the ear (it is a compile dependency), but it does not add b-impl (because there is no static connection). b-impl has to be added to the pom as dependency.
The frequently leads to problems because of "forgotten" impl artifacts. Furthermore, there may be abandoned impl artifacts that will never be deleted from the pom. Possible solutions:
Add a runtime dependency from client to impl. Solves the problem for Maven, but ties the client to the impl. In ejb with client artifact - runtime dependency?, people advised against it.
Use scripts to update and check the pom to make sure that every client has an impl.
Manually check the dependency:list before every build to make sure that every client has an impl.
I do not really like any of the possibilities, but the first seems to produce the least hassle. Is there a better way?
I would create unittests they run the client - then you see on the test phase on the build if everything is working

ClassNotFoundExceptions in Maven Surefire tests

While executing tests in Maven Surefire I see ClassNotFoundExceptions from time to time.
This really gives me a headache, since:
the missing classes vary. Only around 5 classes are affected, but which one it is varys from build to build. However, I see no unique similarities between these classes, which they wouldn't share with 20 other classes of the same kind.
These missing classes come from 2 different dependencies. These are managed by Maven, of course.
When a CNFE is raised I had a look at the class path (during runtime!) and it looks fine!
How I analysed the class path
I took the code of the "class path scanner" from Arno Haase:
public List<URL> getRootUrls () {
List<URL> result = new ArrayList<> ();
ClassLoader cl = Thread.currentThread().getContextClassLoader();
while (cl != null) {
if (cl instanceof URLClassLoader) {
URL[] urls = ((URLClassLoader) cl).getURLs();
result.addAll (Arrays.asList (urls));
}
cl = cl.getParent();
}
return result;
}
The list of URLs is quite short:
a few JRE libs
a "surefire booter jar"
The latter jar bundles all my Maven dependencies in its Manifest file, as described in the Surefire docs.
So I dug further and analysed the "Class-Path" attribute of the manifest. There I found the dependent jar listed, where the missing class should have come from.
When browsing through the jar's entries, I also found the missing class there. The fully qualified path also matches.
So in principle everything seems to be correct and in place.
Where should I continue to investigate now?
There are several things to check for problems like these.
Does this happen from command line or via CI build only? If using Jenkins or Hudson, is this a Maven project or a FreeStyle project with a Maven build step? If this is a Maven project, switch it to a FreeStyle project with a Maven build step, and that just may solve the issue. Stephen Connolly of the Maven team considers the Jenkins Maven build type evil.
Ensure there is only one version of each dependency and that related dependencies (Spring, ASM, Hibernate, etc.) have the same/compatible versions. Pay particular attention to artifacts where the group ID or artifact ID has changed, for example spring.jar vs. spring-core.jar. The old Tattletale plugin might be useful to get started.
Replace any dependencies ending in -all with their component parts. -all jars may contain every class needed to run the library - repackaged into the jar file where Maven's dependency resolution process can't get at them - instead of referencing them as dependencies. mockito-all, hamcrest-all, powermock-all, cglib are examples.
If using coverage tools (Jacoco, Clover) does the build work if you turn off the coverage? If yes, the tool may be introducing classpath jars that conflict with your app's. (Different version of CGLIB for example.) Run in debug mode and compare dependencies with/without coverage to identify the differences.
If using JUnit, make sure Maven surefire is using the right JUnit provider for your version of JUnit. Run the build in debug mode with -X (redirect output to a file if using command line). Grep the output for surefire-junit. You should find something like this:
[DEBUG] org.apache.maven.surefire:surefire-junit4:jar:2.16:test (selected for test)
Now, make sure the version of the provider matches the version of JUnit used. Check out the Maven docs for information on which provider to use and how to configure.

IntelliJ won't accept FileTypeFactory

I am attempting to follow the Language and File Type tutorial for JetBrains IntelliJ
It worked, once. Now (whatever I do) I receive an assertion failure stating that it was expecting an instance of FileTypeFactory and got my SimpleFileTypeFactory
My public class SimpleFileTypeFactory extends com.intellij.openapi.fileTypes.FileTypeFactory so I'm not sure how to react to this ...
Caused by: java.lang.AssertionError: Expected: class com.intellij.openapi.fileTypes.FileTypeFactory; Actual: class bengie.idea.SimpleFileTypeFactory
at com.intellij.openapi.extensions.impl.ExtensionPointImpl.assertClass(ExtensionPointImpl.java:408)
at com.intellij.openapi.extensions.impl.ExtensionPointImpl.processAdapters(ExtensionPointImpl.java:242)
at com.intellij.openapi.extensions.impl.ExtensionPointImpl.getExtensions(ExtensionPointImpl.java:185)
... especially when Google has no matches for "Expected: class com.intellij.openapi.fileTypes.FileTypeFactory; Actual"
Has anyone resolved this sort of thing?
I was depending on a Maven module (actually, two of them) The rest of my project is built with Maven so it seemed logical and looked like it would work. I didn't remember the build seizing up when I added them, so I had forgotten about it. Removing the dependency, starting a debug session, uninstalling the plugin, rinse, repeat and I eventually stopped seeing error messages.
I've since stuffed the maven modules into a jar-with-dependencies and told the IntelliJ plugin module to load the resulting .jar No problems so far - Yay!

Anyone heard about a standard property deployment.name?

I've just fought for a whole day with a strange maven problem:
I had a custom property called "deployment.name" that was never to resolved to what I configured for it, but rather the maven filtering mechanism always replaced it by the project's name.
I tried the goal "help:expressions" to find out whether this is a preconfigured property, but that goal only throws exceptions in m2eclipse. Google does not seem to know a pre-configured
property by that name.
The strangest bit: deployment.somethingelse works perfectly fine, so I ended up replacing ".name" with ".depname", then it works ;.)
The Maven Super POM defines the common configuration for all Maven projects. The values in that are accessible as properties (and , so that is where most of the properties you generally use come from (e.g. ${project.build.directory}), these are the pretty much the same as the output of help:expressions.
There is no deployment section in the super POM. The only thing I can think of is that the property is being set somewhere else, e.g. in a profile, or overridden by a plugin (though that seems unlikely). You could try running mvn help:effective-pom to see if the property is being set by a profile.
Are you able to post your POM? that might help diagnose it.
... I just ran help:effective-pom, and there is no trace of "deployment.name" in the output.
I can see all the other properties that I defined though (e.g. "deployment.depname").
Maybe "name" is a reserved attribute of some sort? Maybe debugging into m2eclipse will shed light on this riddle.

Categories

Resources