Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Maven ear plugin - "doubled" artifact when not using clean

When building an ear through the Maven ear plugin, I experienced that applying package without clean can lead to inconsistent results: If I change the version of a dependency, the dependency now appears twice in the ear, in the old and the new version. If I build the ear without version numbers in the jar names, I get just one jar, but old versions are not replaced properly.

I looked at the source code

http://svn.apache.org/viewvc/maven/plugins/tags/maven-ear-plugin-2.10.1/src/main/java/org/apache/maven/plugin/ear/EarMojo.java?view=markup

Especially the lines from 436 are interesting: There checks whether to update files in target, but apparently only checks for the absolute path and the lastmodified date.

Summarized: Am I right that changing the dependencies (or their versions) always requires to call clean before the build? Or is there some intelligence in package which I missed?

like image 803
J Fabian Meier Avatar asked Nov 22 '17 14:11

J Fabian Meier


2 Answers

Yes... most of the time you should call clean when changing your dependencies or any other build configuration, otherwise previous build elements may collide with a new build (as seems to be your case here). Generally speaking, to make sure previous build elements won't collide with a new build you should call clean before-hand - configuration changes or not.

But there are exceptions: if you know for sure that previous build elements won't impact your new build, you can skip clean. However most of the time you cannot know, or skipping clean is simply not possible without causing such collisions. I explain in details below.


When you build your project with Maven, it will generate files and other elements under the ${project.build.directory} folder (target by default). These elements are then used to create your artifact (EAR in your case) during the package phase.

Without calling clean after a build, all the elements under target will still be there during the next build and may impact it. How can Maven plugins tell the difference and know which elements are from old builds or new ones? Files timestamp are obviously not sufficient, and unless using some obscur mechanism to identify which files are from which build, it is hard to do.

If I change the version of a dependency, the dependency now appears twice in the ear, in the old and the new version.

That's probably because your build copy dependencies under target and your packaging plugin will include an entire directory into the generated artifact (in your case, the EAR). For example, if you run your build twice with different version:

  • First build: mydep-1.0.jar is generated in target/classes/mydep and your plugin includes all files from target/classes/mydep into the EAR. Everything's fine.
  • Second build: mydep-2.0.jar is generated but mydep-1.0.jar is still in target/classes/mydep. The entire target/classes/mydep directory is included and both versions end-up in the EAR.

If I build the ear without version numbers in the jar names, I get just one jar, but old versions are not replaced properly.

That's because some plugins - for optimization - won't re-compile or re-do actions if they see the results already exists. In your case, as you pointed out, the EAR plugin probably keeps the "old" version of the file because it already exists, where in fact a more recent version with the same name should replace it. That's probably because you did not specify a version:

  • In the first case, mydep-0.1.jar existed and a new mydep-0.2.jar was created but both were included in your EAR
  • Now, without version, you have mydep.jar which is not overriden by the most recent version because "it already exists", thus the "old" file stay in place and get included in the EAR.

Conclusion: Maven plugins are not able to differentiate with a 100% certainty if an element is from a previous build or a new one. When you are updating your build configuration, you should always call clean to ensure there won't be a collision between old and new build elements. Even without build configuration changes, it may be necessary to call clean - but that's another matter.

I would recommend to always call clean when running a build, unless no collision is possible and it provides a real value such as a time gain because rebuilding the entire project is too long or other reasons justifying it.

EDIT: as per @JF Meier request for sources, the Running Maven guide provides advice as per the clean goal and the related inconsistency risks:

Inconsistent output

Most plugins are optimized to know if they have to execute their task. In some cases the output can be polluted from a previous build and the end result is not what you expected. In such rare situations you can call the clean phase which means: remove the output directory. You can also call it as mvn clean verify which means: first clean up the output directory, next build the project and verify the outcome.

like image 144
Pierre B. Avatar answered Nov 12 '22 01:11

Pierre B.


See if the issue persists by compiling the latest version of maven-ear-plugin (3.0.0, more recent than 2.10.2, itself more recent than the official 2.12.1)

As you can see in the latest code EarMojo.java, the function copyModules() has changed from the 2.10.1 implementation, and might be more robust.

like image 38
VonC Avatar answered Nov 12 '22 01:11

VonC