Is there a way to add a custom line in .classpath using mvn eclipse:eclipse? - maven

I am using mvn eclipse:eclipse command to generate my .project and .classpath.
However, for some reasons, I want to add one line in the .classpath file. Is there a configuration in my pom.xml that I can use to achieve that?
Note that <additionalConfig> cannot be used, as this will erase the content of the .classpath.
I am using maven 3.0.2 and maven-eclipse-plugin 2.8.

It depends on what that line is.
If it's a source folder, use the
buildhelper-maven-plugin to
add a source folder in a
lifecycle phase before
generate-sources, this will
automatically be picked up by the
eclipse plugin.
If it's a classpath container, you
can use the classpathContainers
parameter
If you want to change the output folders (from target/classes and target/test-classes to something else), change them in the maven build configuration:
<build>
<!-- replace "target" -->
<directory>somedir</directory>
<!-- replace "target/classes" -->
<outputDirectory>anotherdir</outputDirectory>
<!-- replace "target/test-classes" -->
<testOutputDirectory>yetanotherdir</testOutputDirectory>
</build>
You can configure each of those three independently, and the changes will be picked up by the eclipse plugin, but it's considered good practice to put outputDirectory and testOutputDirectory inside directory (usually by referencing ${project.build.directory}), otherwise you break standard functionality like mvn clean (it cleans ${project.build.directory}):
<build>
<directory>bin</directory>
<outputDirectory>${project.build.directory}/main-classes
</outputDirectory>
<!-- this config will replace "target" with "bin",
compile src/main/java to "bin/main-classes"
and compile src/test/java to "bin/test-classes"
(because the default config for <testOutputDirectory> is
${project.build.directory}/test-classes )
-->
</build>
Reference:
POM Reference > Build > The BaseBuild Element Set
POM Reference > Build > Directories
Introduction to the POM > Available Variables
Update: in your case I guess the only possible solution is to programmatically edit the .classpath file. What I would probably do is something like this:
Define a <profile> named eclipse (or whatever)
Define an execution of the gmaven plugin (use this version)
Write a short groovy script (inline in the pom or external) that checks the .classpath file for your classpath container and adds it if missing (bind execution to a lifecycle phase, e.g. generate-resources)
set the profile activation to <file><exists>${project.basedir}/.classpath</exists></file> (because you only want it to be active in an eclipse project)
The problem with this solution: eclipse:eclipse is a goal, not a phase, so it's not possible to execute this automatically, so you'll have to do something like this:
mvn eclipse:eclipse # two separate executions
mvn generate-resources # here, profile will be active
or perhaps this will also work:
mvn -Peclipse eclipse:eclipse generate-resources

Related

Maven: Define SuperPOM property project.build.directory over command line

I am building my maven project with GitLab CI on a docker file.
I would like to configure my pipeline with a "compile" stage and a "test" stage. To be able to do that, I need to set the property project.build.directory, which is defined in the maven super POM, to the docker cache so the compiled artefact does not get lost between the jobs.
project.build.directory is a predefined maven property. Therefore I would think that I am able define it with the CL parameter -Dproject.build.directory=anotherDir. This somehow does not work and my project still gets built to the default directory target.
If I modify my POM with
<properties>
<buildDir>target</buildDir>
</properties>
<build>
<directory>${buildDir}</directory>
</build>
and call mvn clean install -DbuildDir=customTargetDir, my project gets built to the customTargetDir as expected.
Why is that? I really don't see a difference. I both cases, I define the value of an existing property.

Maven install goal does not generate pom for modules

I'm running a multi-module maven project and have an unexpected behavior. First time I'm seeing this...
My parent module configures the install plugin, defining its classifier.
<plugin>
<artifactId>maven-install-plugin</artifactId>
<configuration>
<generatePom>true</generatePom>
<classifier>${env}</classifier>
</configuration>
</plugin>
<!-- ... -->
<modules>
<module>webapp-formation</module>
<module>db-formation</module>
</modules>
But when I'm running mvn install the .pom files are not generate for my modules. Only my parent is associated with a .pom file in my repositories. Thus trying to browse to my module's artifact on Archiva (after running mvn depoy of course!) it simply fails. I can browse to the parent but not its children.
So... I need to add the undocumented attribute generatePom to my plugin configuration to have the .pom files generated --copied would be a better word actually-- for all my modules. --I said undocumented attribute because this attribute is documented only for the install-file goal which is not the one ran by default. The install goal is not expecting that attribute...
Of course, if I do not configure my install plugin --so not configuring the classifier-- I have no problem and all .pom files are generated properly.
For you guys, is that a normal behavior? Something that you have already seen? Or should I just file a bug?
Thanks,
Olivier.
What you describe as an undocumented attribute is simply wrong, cause the attributes are specific on a goal base which means the given configuration will not change anything, cause the generatePom attribute is only valid for install-file goal. So you can remove it.
In general such configuration does not make sense, cause if you have different environments you should go a different way. Just removed hte configuration with <classifier>${env}</classifier> as well and try to deploy via:
mvn clean deploy

Version in jar name

When I import mvn project into Intellij the jar file it generates doesn't include version. But mvn generated jar has name-version.jar format. So I end up with two jar files one with version and another without one. I can of course, change module name in Intellij settings to include version. But that will be reset whenever I change pom file.
Maybe somebody else had a better idea?
The jar name that Maven generates on disk is controlled by /project/build/finalName so if you edit your pom.xml to look like
<project>
...
<build>
...
<finalName>${artifactId}</finalName>
...
</build>
...
</project>
and then Maven will be generating the jar file without the version.
Note
finalName only controls the name of the file on disk. Once that file is transferred into the local repository cache or a remote repository it will be renamed to match the repository layout (i.e. ${artifactId}-${version}.${type} or ${artifactId}-${version}-${classifier}.${type} for artifacts with a classifier). You cannot change the format used by the repository.
I add the above note because the first thing everyone seems to want to do upon learning about the finalName parameter is try and change the name in the repository.
use version tag of the maven
<version>0.0.1-SNAPSHOT</version>
do not let intellij to create jar files without version tag.

Reading Properties file from POM file in Maven

Why is this NOT working ? How to pick the version numbers from the properties file.
Reading properties in pom.xml
<project>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>properties-maven-plugin</artifactId>
<version>1.0</version>
<executions>
<execution>
<phase>initialize</phase>
<goals>
<goal>read-project-properties</goal>
</goals>
</execution>
<configuration>
<files>
<file>dev.properties</file>
</files>
</configuration>
</executions>
</plugin>
</plugins>
</build>
</project>
In dev.properties
org.aspectj.aspectjrt.version=1.6.11
Dependency in pom.xml
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>${org.aspectj.aspectjrt.version}</version>
</dependency>
Error : dependency must be a valid version
When you start up Maven from the command line, it goes through a number of stages. Here is a pseudo description of these stages, I am intentionally simplifying the exact sequencing (with the risk of saying things that are slightly incorrect/out-of-order) so that you can see why what you are trying to do cannot work.
First it parses your command line, any properties defined on the command line using the -Dname=value are injected into the MavenSession
The reactor defining command line options are checked to decide what the list of projects to build (also known as the reactor) should be. -N means build only the root pom.xml, -pl allows specifying a list of modules to build, -am and -amd allows adding upstream or downstream, respectively, modules from those specified by -pl. Maven has not parsed any pom.xml files at this point in time.
The -P profile activation rules are parsed to see what profiles to activate.
Now Maven has enough knowledge to start parsing the pom.xml files. It starts by loading and parsing the root pom.xml, i.e. the one in the current directory (or if you specified an alternative pom.xml with -f then that one). This initial parse is just concentrating on figuring out the list of projects to build. Profile activation is only considered in so much as it may affect the list of <modules> that are available. The Group Id, Artifact Id, Version and Packaging coordinates in the pom.xml cannot contain properties because the parsing of the properties in the pom.xml has not taken place at this point in time. (The observant reader will also see that this also explains why you cannot activate profiles based on properties within the pom.xml, as only system properties have been parsed at this stage)
Once the set of projects has been validated, Maven now does some more parsing of those pom.xml files to construct the list of build extensions (if any) and the list of plugins. At this stage the parsing requires evaluation of the <properties> in each project, so this is when these get evaluated and "injected" into the effective model. Thus you can use system properties and pom properties to define the coordinates and additional dependencies within (xpath) /project/build/extensions, /project/build/pluginManagement/plugins/plugin, /project/build/pluginManagement/plugins/plugin/dependencies, /project/build/plugins/plugin and /project/build/plugins/plugin/dependencies.
Now Maven starts parsing the list of goals and phases specified on the command line. Partially specified goals are evaluated for a match against the list of plugins. The match must be unique for all the projects that the plugin goal will be executed against (i.e. if it is an aggregator goal, the match is only required at the root, but for all other "normal" goals, the plugin short name must be the same plugin for all projects). Lifecycle phases must be from one of the default lifecycles, or from a lifecycle defined in a build extension.
From the parsed list of goals and phases, Maven constructs the build plan, i.e. what it is going to do on which projects and in what order. In order to do this Maven must parse the list of project dependencies defined in the reactor projects pom.xml files. This is because a dependency may be produced by another project within the reactor, thereby forcing a sequencing of project execution. Thus you can use system properties and pom properties to define the coordinates and additional dependencies within (xpath) /project/dependencyManagement/dependencies/dependency and /project/dependencies/dependency but note that at this point in time, no plugins have been executed.
Now that Maven has the build plan, it starts following that plan in the order that it constructed. If the first goal/phase on the CLI was a goal, then that goal will be invoked. If the first goal/phase was a phase from the default build lifecycle, then Maven will start with the initialize phase and execute all the plugins bound to that phase... continuing in a similar manner along the list of phases and then the list of projects. Note also that the initialize phase is only executed as part of the default build lifecycle. It is not executed on the default clean or default site lifecycles, and it is not executed on any custom lifecycles. (The observant reader will conclude that this highlights another problem with the technique that the question is attempting). Note: keep in mind that aggregator goals form a "break" in the reactor, so if you ask Maven to run clean package foo:bar site where foo:bar is an aggregator mojo goal, then clean package will be run against all the projects in the reactor, then foo:bar will be run against the root, then site will be run against all the projects in the reactor. In other words, the build plan will take the longest continuous run of non-aggregator goals & phases, split by longest continuous runs of aggregator goals.
Before it calls each mojo (i.e. goal bound to a phase or directly specified from the command line) Maven evaluates the pom.xml for the effective <configuration> of that mojo. At this point Maven has available the system properties, the properties specified in the pom and any properties injected into the MavenSession by previously executed mojos. Thus the <configuration> can reference any of those properties...
Aside
Now there is a caveat... if you say set (xpath) /project/build/directory to ${some-property-i-will-set-via-a-mojo} and then reference that from your <configuration>, well the sad news is that (xpath) /project/build/directory will have been evaluated into the effective pom.xml before any plugin execution, so ${project.build.directory} will have been given the literal value ${some-property-i-will-set-via-a-mojo} and that is of type java.io.File in the MavenProject so what you will actually have had happen is new File(project.getBaseDir(),"${some-property-i-will-set-via-a-mojo}"). If the <configuration> field you are injecting into is of type File, there will be no type conversion required, and hence the value will be injected straight in, and no property substitution will have taken place.
There are other edge cases, like the one outlined above, but in general property substitution will work with "mojo injected" properties (such as those provided by Mojo's Properties Maven Plugin) within the <configuration> sections. It will not work outside of those sections.
So here is Stephen's quick rule of thumb for the different property types:
System Properties
These work everywhere... but are extremely dangerous in /project/(parent/)?/(groupId|artifactId|version|packaging) as you have no control what so ever on what system properties will be defined when the project is pulled in as a transitive dependency. Use of ${...} expansion within /project/(parent/)?/(groupId|artifactId|version|packaging) should be considered as equivalent to driving a car at 200kph with a 30cm (12 inch) metal spike protruding from the steering wheel in place of an airbag... oh and no seat belt... and you've just had 10 units of Alcohol and two lines of cocaine.
pom.xml properties (and settings.xml properties)
These work in most places, but are never available within /project/(parent/)?/(groupId|artifactId|version|packaging) (as they have not been parsed when those fields are being evaluated) and are not available for consideration of the active profiles (again as they have not been parsed when profile activation is being evaluated)
Mojo injected properties
These work within <configuration> sections and may (due to the recursive interpolation of injected Mojo String parameters) work when used indirectly, but given the uncertainty involved, the recommendation is to restrict their use to the <configuration> section of plugins and reports only.
One final thing
Think about what happens when your project is listed as a dependency. If you had specified its dependencies by using a mojo to pull those from a .properties file on disk, Maven has no way to replicate that when your dependency has been pulled from the Maven repository. So Maven would be unable to determine the dependencies. Thus it could never work.
What you could do, is use an external system (e.g. ANT) to generate the pom.xml from a template with the versions replaced into that file. And then use the instantiated template to build.
This properties(dev.properties) file for build job.
<files>
<file>dev.properties</file>
</files>
For dependency you need add like below in your pom.xml file.
<properties>
<org.aspectj.aspectjrt.version>1.6.11</org.aspectj.aspectjrt.version>
</properties>

Changing the name of the generated war file from command line with maven

According to the maven war plugin documentation I should be able to set the name of the generated war file with the parameter warName. Is it not possible to do this from the command line with mvn -DwarName=mySpecificName package? When I run maven like this the war file still gets the default name.
My webapp project is part of a multi module project and I only want to change the final name of the war file, not any other projects generated artifact.
I am using maven 3.0.4 and version 2.3 of the war plugin.
You can achieve the same effect by maven property.
1) Define a property via
<properties>
<my.warName>xxx</my.warName>
</properties>
You can overwrite the default value by "-Dmy.warName=commandlineWarName"
2) Redefine the war name
<build>
<finalName>${my.warName}</finalName>
<!-- ... -->
</build>
After looking at the code of the war plugin I realize that it is not possible to set the warName parameter from command line. I assumed that all parameters were possible to set from the command line. This assumption was incorrect.

Resources