how to know the value variable defined in pom.xml? - maven

I have some multi-module Maven project, I am looking through whole pom.xml. I am beginner for Maven project, so not have enough knowledge to understand it comprehensively. There is some variable defined in pom.xml,
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>xxx</artifactId>
<version>${project.version}</version>
</dependency>
I searched whole properties defined in pom.xml cause those are that I know of which variable can be defined for pom.xml.
Does anybody know about how I can figure I what the 'project.groupId' is? Is there any files or environments I can search for?

I searched whole properties defined in pom.xml cause those are that I know of which variable can be defined for pom.xml. Does anybody know about how I can figure I what the 'project.groupId' is? Is there any files or environments I can search for?
If you would like to explore the various properties, you may find the output of mvn help:expressions instructive; it lists the various starting points of such property expressions, e.g., ${project} (the current project’s POM) or ${settings} (the user’s settings).
You can then use mvn help:evaluate to explore the values of these properties. For example, if you enter ${project} on evaluate’s prompt, you will see an XML rendition of the ${project} object. Within this XML element, you can select child elements by a dot-separated path. A property like ${project.build.finalName} will evaluate to to the value of the <project> > <build> > <finalName> element.

you can refer those links for multi-module Maven POM.xml configuration.
http://www.codetab.org/apache-maven-tutorial/maven-multi-module-project/
http://www.avajava.com/tutorials/lessons/how-do-i-create-a-multi-module-project-in-eclipse.html

Related

In maven, can I define a variable used in another pom?

I'm getting an error when running maven build (unable to load a dependency).
[ERROR] Failed to execute goal on . . .
Could not transfer artifact my.group:libme1:${someVariable} from/to . . .
I believe that the developer that published this artifact was supposed to be setting the variable ${someVariable} but didn't. I think this is a bug but I'm trying to work around it by setting the variable.
The POM for the JAR I'm depending on my.group:libme1:1.2.3 looks like this (snippet highlighting the issue):
<groupId>my.group</groupId>
<artifactId>libme1</artifactId>
<parent>
<groupId>my.group</groupId>
<artifactId>libme1-parent</artifactId>
<version>${someVariable}</version>
</parent>
I tried defining it by adding -DsomeVariable=1.2.3 on the command line but it didn't work. For example, this command
mvn -DsomeVariable=1.2.3 clean install
should work based on Baeldung's article but doesn't.
I also ran:
mvn -DsomeVariable=1.2.3 help:effective-pom
and I see the variable being set, so I know he POM I'm using has that defined, but for some reason another POM doesn't pick up that value (or that is how it appears to me).
Is there any way to set the variable so it can be used in another POM? I'm guessing this is not possible.
Searching for an answer I found:
The maven doc
https://maven.apache.org/settings.html#Activation
If you know that this is bug, please let me know. I'm also reaching out to the publish of the artifact to ask them how this is supposed to work.
Basically the dependency's pom is invalid, the reasoning is following:
maven allows developers to do following things:
define dependencies in parent pom
impose restrictions on dependencies via <dependencyManagement> in both current and parent pom
use placeholders ${...} in <version> element, which somehow get resolved via system properties and current/parent pom properties
all those features mentioned above are very convenient from development perspective, however when you publish artifacts those features cause a pain in behind: that became not possible to use external library without it's parent pom, because parent pom may define dependencies and properties.
In your particular case someone have define version of parent pom as ${someVariable}, that in turn means it is not possible to use that library without information about the value of ${someVariable}. However, even if you had known the "correct" value of ${someVariable} and might specify it via system properties, that would cause some weird behaviour: today you may specify one value for ${someVariable}, tomorrow you (or someone else) will specify another value and ultimately you will get different builds, due to that maven denies such configurations (that is much better to fail a build rather than build something unreliable), that would be wiser to initially deny publishing such poms, but we have what we have.
It might be that the variable was stored in some user's settings.xml.
This would allow checking out an older version already in production for writing patches.
<settings>
...
<profiles>
<profile>
<id>work-in-progress</id>
<properties>
<someVariable>1.2.3</someVariable>
</properties>
</profile>
</profiles>
<activeProfiles>
<activeProfile>work-in-progress</activeProfile>
</activeProfiles>
</settings>
So you might do that too. And search in users' directories, .m2 repo directories where usually the settings.xml is stored.

is there a placeholder for src/main/webapp/WEB-INF directory in Maven

Is there a predefined placeholder for src/main/webapp/WEB-INF directory in maven which can be referred by ${XYZ} ?
If not, is there a way to define such a placeholder?
There isn't really a need for predefined variables that are very much tied to a particular type of project module and packaging standard, with $basedir you have access to any module folder you want. So also ${basedir}/src/main/webapp/WEB-INF.
And Maven allows you to define your own properties.
<project>
<properties>
<webinf.basedir>${basedir}/src/main/webapp/WEB-INF</webinf.basedir>
</properties>
...
</project>
Then you simply have access to the path as ${webinf.basedir}. Use whatever property name you like of course.
Refer to the Maven documentation for a nice overview of available path properties.

Can a property be expanded relative to its defining POM and not any child(ren)

I am trying to set several properties in a parent aggregation POM project which are therefore available to all module projects:
<modules>
<module>module1</module>
<module>module2</module>
<module>module3</module>
</modules>
<properties>
<module1.dir>${project.basedir}</module1.dir>
<module1.build.dir>4{project.basedir}/build</module1.build.dir>
</properties>
The properties relate to various directories I intended them to be evaluated relative to the parent POM
I want to refer to the above properties in a second module (module2) like so:
${module1.build.dir}
However when I look at the effective POM of module2, the following expansion results:
<module1.build.dir>_project_root_directory_/module2/build</module1.build.dir>
What I would like is the value of ${module1.dir} etc. to be expanded relative to the parent POM (where it is defined). Is there anyway to do this in Maven or am I going to have to set some environment variables in a script to do this?
The reason for trying to do this is that I am doing an unusual build in that module1 is a pure native library, module2 is a JNI library that depends on module1 and module3 is a pure Java library that depends directly on module2.
no, maven does the inheritance 1st (so constructing a leaf pom's effective-pom by combining all of its parents), and only then evaluates properties.
this means properties are always evaluated in the context of the child pom in your case.
this is a requirement for maven to behave properly. look in the super pom and you will see things like:
<build>
<directory>${project.basedir}/target</directory>
...
</build>
which define where sources are looked for and where target classes are written to. they must be evaluated post-inheritance (in the context of a child).
workaround
you could use a property value like ${project.parent.basedir}, or you could "look sideways" by using ../sibling-module/whatever. neither of these is pretty.
alternative
for maven builds involving native components, have you looked at the maven nar plugin? it was developed for these situations specifically.

what is project.build.directory in ANT

In my project the maven-antrun-plugin is used and in a number of places a property named
project.build.directory
is referenced but i can't understand to what value this property is set. I tried to google and found couple of places where this was mentioned but could not find a formal note on, to what value this property is set.
Also, since I am using the maven-antrun-plugin, it would be nice if you tell me this property is set by Maven or Ant.
project.build.directory is a maven property available as is when your ant script is embedded in your pom.xml
If you call an external ant build file, this property will be available under maven.project.build.directory
By default the value of this property is the target directory.
This default value can be changed by adding a <directory> element in the <build> section of your pom.xml:
<build>
<directory>something</directory>
...
</build>
More about maven properties in maven-antrun-plugin here
Specific quotes from this source:
All of the properties available to maven are also available in the target configuration. However, you may want to call an external Ant build script using the ant task. To avoid name conflicts, only a subset of the properties are passed to the external Ant build. These include all properties defined in the properties section of the POM. It also includes prefixed versions of some of the commonly used Maven properties.

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>

Resources