How does a Maven plugin know when to re-run? - maven

How does a Maven plugin know when to re-run when a clean isn't part of execution?
That is, when I do mvn install as opposed to mvn clean install, how does it know which files have changed and which plugins it should/shouldn't run?
I ask because I seem to have a troublesome plugin that seems to be missing some changes and I don't want to "recompile the world" every single time and I also don't want to have to actively think when to do a clean or not.

After some investigation I have found there is no universal way this is done. The general idea is that timestamps of sources and targets are compared, but some plugins aren't "smart" enough to know what the sources are.
The specific problem I was running into was the cxf-codegen-plugin not considering that the .wsdl files may depend on .xsd files. So if the .xsd file was modified, meaning the compiled code would change if it ran again, but it did not run the plugin.

Related

Gradle failing on build, but Maven works

So, I have always used Maven.... thought I would try Gradle.
I went through the instruction to just convert my existing maven setup to gradle, this supposedly sets up the gradle environment from the existing Maven environment.
After conversion, I was able to get simple projects to build with "gradle build".
However, more complicated ones are failing. The problem seems to be the absence of ".jar" files. Maven seems happy with only needing the ".pom" file for dependencies.. yet Gradle seems to require the ".jar" file.
I am not really sure why Maven does not care about the ".jar". Maybe it is lazy and assumes it only needs it during runtime, and as long as it finds the ".pom" it can finish the build. Gradle, then, is not as lazy and requires the actual ".jar".
I don't really know, but am looking for some confirmation on how this works.
Can someone help out?
Thanks!!!!
Maven also needs all the jar files, except for cases where you only need pom information, like parent poms and boms.
If a dependency does not have a jar file, there is probably something missing in your repository.

Can I use maven to add sources as part of my project?

I am using a dependency and I have some issues with it.
I could download the sources and include it as part of my project and then start modifying the source to help me debug my issue.
However, is there an easier way to do this, using maven ? I have the source-jars downloaded but I am not sure if I can then use these source jars and modify the code as well ?
I could in theory unbar the sources and add them to my source build path, but is there an easier way to accomplish this ?
I am using maven and IntelliJ.
Are you able to get a successful build of the dependency you're having issues with (in it's own project?).
If so, change the version, e.g. 1.2.3-CUSTOM-1, make the improvements, rebuild, and use it as a proper maven depdendency with <version>1.2.3-CUSTOM-1</version>.
This might seem a lot of work, but it's not really - you end up with a properly versioned jar.... having a "hacked" version of 1.2.3 jar is asking for all sorts of problems later.
On the plus side, you can share and deploy the -CUSTOM-1 jar if you need to, and you can keep versioning -CUSTOM-2, etc.
This is the "proper way" I would say.
As Thorbjørn Ravn Andersen wrote, source jars are read-only. You can setup debugger breakpoints in them, but you can't "write" in them
Either unjar the sourced jar or if you know it came from a git release tag, clone the original repository and checkout the correct tag
Make sure its sources compile
Bump up the version in case you know you are going to hack the source
On the right pane, use Maven projects / Plus icon to add sources and use the "m" Execute goal icon to build the sources in IDEA :

Maven module dependency source instead of repository jars

I have a multi-module project, i.e.
parent
module1
module2
In one dev cycle, I added a class mod1.A to module1. Class mod2.B in module2 depends on it.
I do not have the artifacts in my local .m2/repository. Running this:
$ cd prj/module2
$ mvn -o exec:java -Dexec.mainClass=mod2.B
results in an error along the lines of:
The following artifacts could not be resolved: com.example:module1:jar:1.0-SNAPSHOT
After I install the artifacts via mvn install while in the prj folder, it all works as expected.
However, this presents an issue in at least two ways:
I have to go through the slower install phase instead of the faster compile phase
I have two versions of the same project and conflicting modifications in these. I cannot run the same Java class with their respective modifications, only the currently installed modifications, considering they are both the same SNAPSHOT version
There are workaround for both (skip parts of the build for the first, different snapshot versions for the second), but they are far from usable in practice.
Is there a way to make maven use the local modules, instead of using artifacts from local maven repository?
If I understand your question correctly, it seems like you are living a bit outside the norm here: you have two local "copies" of the project with different modifications, that you want to work with alternately when running "exec:java". And Maven is getting in your way: it expects your local .m2 repository area to be in play, but the version strings in each copy are the same, so you end up with the changes interfering among the copies.
To me, it sounds like what you are trying to do is to test your changes. I suggest you just write an actual JUnit or TestNG test in module2 that tests what you want (it can just call mod2.B Main if you want). Then, from your chosen project directory, you can run mvn test -Dtest=MyTestName. It won't "install" anything and it will find the dependencies the way you want it to.
Otherwise, I can see three options.
Change the version string locally in one of the copies (mvn versions:set -DnewVersion=B-SNAPSHOT can do this for you). That way any "installed" jars from your work on that copy will not be considered by the other copy, and vice-versa. You refer to this as being "far from usable" ... I think it should be fine? These are different versions of the project! They should have different version strings! I strongly recommend this option out of the three. (You can do mvn versions:revert when done if you used :set, or you can rely on version control to undo the change.)
Select a different local repository used by Maven when working on one of the projects, with a command-line flag as per https://stackoverflow.com/a/7071791/58549. I don't really think this is a good solution, since you would have to be very careful about using the right flags every time with both projects. Also you'd end up having to re-download Maven plugins and any other dependencies into your new local repository anyway, which is kind of a waste of time.
Try to avoid using any local repository at all. You seem to be trying to make this option work. I don't think this is a great approach either; you're fighting against Maven's expectations, and it limits your flexibility a lot. Maven will indeed find dependencies from the "reactor" (i.e., the executing mvn process) first, but this means all of the required modules must be available in the reactor to be found, which means you can only run mvn at the top level. So if instead you want to just do "mvn exec:java" inside a single module, mvn needs to find that module's dependencies somewhere ... and that's what the local repo is generally used for.
If you're dead set on going with option 3 (instead of option 1), then I suggest you follow the comments on your question and create a profile that runs your exec selectively against module2 and binds it to a lifecycle phase. But this is in practice very close to just wrapping it with a test.
For IntelliJ users:
I solved this problem using IntelliJ's Run configuration. It has the options Resolve workspace artifacts and Add before launch task -> Build. See this picture for clarification:
Run configuration example
The whole point of modules in Maven is to create decoupling between them. You either build each module independently, so that you can work on one module without touching the other, or include both modules as sub-modules in the parent pom and build the parent, which will resolve dependencies between its sub-modules and trigger their builds.
It looks like you have two options here:
Review the structure of your project. Do you really need to split it into two separate modules, if you change code in both of them simultaneously?
Import the project into a Maven-aware IDE (IntelliJ IDEA is very good at working with Maven), and let the IDE handle the compilation. Once finished and stabilized the code-base, build normally with Maven.

Maven deleted class still in jar if mvn clean not run

In an effort to speed up my maven build time, I want to run mvn install and not mvn clean install.
If I do this, and a source file was removed (in VCS and I got this change after updating my copy), maven will still pack the old file (since it's still under the target folder).
I'm aware of this thread and others similar, but I'm not satisfied with the end result.
I assumed that maven is "smart" enough to pick up only changes and do a real incremental build, but this behavior breaks this assumption...
Does anyone have an idea on how to enjoy a true incremental build with maven without using the clean life-cycle?
Maven runs through it's lifecycle, running external tools through plugins at various points in the process. You can choose where this process begins, and the recommended starting point is clean. We recommend this because maven knows nothing about your source-code -- it doesn't even know whether it's java or C++ -- and it doesn't have to. It just knows that it should invoke the configured compiler (javac for example) on the configured source directory as soon as it reaches the compile step of the lifecycle.
Your compiler knows about source, so if something is to blame here, blame the compiler. However, most compilers will not delete a compiled artifact just because a source file has been removed, because it doesn't know that this artifact isn't going to be linked (referenced) later -- as far as the compiler is concerned, it's only interested in artifacts relating to source files. This is probably the only tool that looks at your source (except maybe some static code analysis tools and perhaps some documentation tools such as site and javadoc).
Maven will proceed after compilation to run your tests, and if they pass it'll enter into the packaging step. Packaging is again an external tool (jar for example), configured through a plugin. In the case of jars or wars, this takes the contents of the target directory and zips them up into a jar or war according to the configured instructions. Again, there is no part of this that needs to know if a file was removed from the source or not -- in fact, it doesn't even look at the source at this point, so how would it know that a file was removed.
My point is, you're assuming too much of your development environment. It has no way of knowing that a file in a target directory is unneeded, unless you go to great lengths to tell it that this is so. That's why there is a clean step in the first place.
As an aside, clean shouldn't be taking a lot of time. If it is, perhaps you should refactor your project into more modules.

how to get over these maven/m2eclipse issues

(first, I admit, I have no love for maven/m2eclipse, but it wouldn't be that bad if I could figure out how to overcome these issues)
I am using maven/m2eclipse. m2eclipse is the only good way I know of to suck in the maven jars. Some of these may not have solutions(but I am hoping to be surprised). Maybe solving #9 solves them all?
ISSUES
When I run "mvn clean package", I am dead in the water as far as running a unit test in eclipse while maven is building as I LOVE to multitask but maven prevents me here. How to get around this?
I move eclipse to point to eclipsegen/classes but then the unit tests are still using the classes in target/classes so it's not using my latest code that I just edited in eclipse and debugging is not lining up and it's stepping on blank lines that don't have code.
If I just slightly touch the pom.xml, bam, it builds when I don't really want it to and turning of automatic builds did not seem to help.
On top of #3, I get random pom builds downloading jars which just freezes eclipse from doing anything why the jars are being downloaded(I am a bit multitasker so this frustrates me to no end)
If I want to modify or do something really custom I need, the answer is usually create a java plugin but this then would require me to create another source control project with another automated build making sure the build tags all versions so we can reproduce issues with certain versions. (in ant, I just modify the xml to do custom stuff).
(I hear there is a bug open for 5 years on this one). global exclusions because people on our project keep breaking stuff when they include new things that depend on log4j and sucking that library in breaks us so we want to globally exclude it so people stop breaking the project when adding new things (IVY has global exclusions, why doesn't maven!!!!)
The xml code for generation from an xsd in maven is about 2-3 times the code of doing it in ant. Why is this? That really shouldn't be the case I think.
Running my unit test says xxxx-12.0.8-SNAPSHOT is missing but in my pom.xml it clearly says 12.0.9-SNAPSHOT not .8. ie. m2eclipse gets into some weird state and I get screwed wasting yet more time because someone selected maven
(I don't like IvyDE for the same reasons I don't like m2eclipse). In maven, is there any way like in Ivy to say on a build MOVE ALL jars into target/lib so that I can uninstall m2eclipse(if maven had this one feature, I think all my problems might go away)....That IS AN Ivy feature that rocks by the way!!!!
NOTE: I just realized that uninstalling m2eclipse and running "mvn eclipse:clean eclipse:eclipse" is not really an option since on this project I had to import 30 projects. I think on single projects, that is a great solution.
Is there no way like ant to log the command that was run for debugging purposes? ( in maven how to log the command that was run? )
I should really look into gradle(I hear it's best of maven and ant) as the theory of maven sounded great but you can tell there was a lot of controversy over it(which usually indicates a bad tool). Good tools that really help typically do have some controversy, but not as much as maven has had so it makes me think twice as I don't want to screw the guy who takes over my project(and I know ant will work). Many people I think don't even consider that. They think "I am fine, so why won't the next guy be fine".
Any ideas on how to fix the above issues?
About #9, if you have 2 alternatives :
Execute
mvn dependency:copy-dependencies
See http://maven.apache.org/plugins/maven-dependency-plugin/copy-dependencies-mojo.html for customization options. You'll have to set your Eclipse classpath manually to point to the newly copied jars.
Use JBoss Tools JDT Extensions to get the "Materialize Library" feature (see http://docs.jboss.org/tools/whatsnew/core/core-news-3.3.0.M4.html). You'll basically just have to right-click on the Maven Classpath library, select a destination folder, select (and rename) the jars you want, and you'll get a m2e-free project in Eclipse (still a valid Maven project in command line though).
You can install JBoss Tools JDT Extensions from http://download.jboss.org/jbosstools/updates/development/indigo/
Disclaimer: I like Maven and M2Eclipse, and I have not experienced any of the issues that you mention. In general, M2Eclipse does not get in the way much for the way I'm working.
One thing that might help is disabling the Maven Builder for the projects (right-click the project, select "Properties", then "Builders"). This will get rid of many of the issues you're complaining about.
One other thing that might help you (and comes close to #9 on your list: Uninstall M2Eclipse and use mvn eclipse:eclipse, which will generate Eclipse .project and .classpath files, which include all dependencies as Eclipse project dependencies. Whenever you add or change dependencies, you will have to run mvn eclipse:eclipse again. Give this a try...
Although it does sound like a faster PC would solve some of your issues I do agree that the m2eclipse plugin sucks (although it sucks a little less since eclipse indigo). Because of this I switched to using Intellij for a while but I switched back to eclipse after a month (for me, eclipse is still the best in spite of m2eclipse).
I use m2eclipse to be able to work in eclipse but nothing more. All my maven builds (package, install, whatever) I run with maven itself (command line) simply because there have been too many occasions where the result was different (working in one, not in the other and and maven was always correct).
So, sorry, no direct answers to your questions, just some tips:
1) do it outside eclipse
2) stick to maven standards (target/classes); that will make your life a lot easier
6) using dependency management in a parent pom might help a bit
8) if you get the same issue when running from command line then there is a problem in your pom (resolve using mvn dependency:tree), if not, see 1
9) maybe assembly is an option here but I would not recommend your approach

Resources