Variable dependency of submodule with property from settings.xml - java

I have a sample maven project with the following structure:
parent
frontend
backend
Frontend depends on Backend.
Backend has a database driver dependency for testing. However, this dependency should be dependent on the developers settings.xml
<dependency>
<groupId>${database.driver.groupId}</groupId>
<artifactId>${database.driver.artifactId}</artifactId>
<version>${database.driver.version}</version>
<scope>test</scope>
</dependency>
In my settings.xml I have this:
<profile>
<id>database</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<database.driver.groupId>mysql</database.driver.groupId>
<database.driver.artifactId>mysql-connector-java</database.driver.artifactId>
<database.driver.version>5.1.9</database.driver.version>
</properties>
</profile>
When I run only the backend the properties are correctly substituted.
However, if I run frontend (or parent) transitive dependencies are not available for frontend because it can't substitute the properties anymore:
[WARNING] The POM for de.phil.mvntest:business:jar:0.0.1-SNAPSHOT is invalid, transitive dependencies (if any) will not be available: 2 problems were encountered while building the effective model for de.phil.mvntest:business:0.0.1-SNAPSHOT
[ERROR] 'dependencies.dependency.artifactId' for ${database.driver.groupId}:${database.driver.artifactId}:jar with value '${database.driver.artifactId}' does not match a valid id pattern. #
[ERROR] 'dependencies.dependency.groupId' for ${database.driver.groupId}:${database.driver.artifactId}:jar with value '${database.driver.groupId}' does not match a valid id pattern. #
The funny part is, that if I move the profile declaration into the parent's pom.xml it works fine!
So my question is, why are the properties of a submodule not substituted when they come from the settings.xml.
Note:
"help:active-profiles -N" shows that the profile from the settings.xml is active.
Note2: The Maven version came with STS and is Embedded 3.0.4
Following the settins.xml and poms
backend
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>de.phil.mvntest</groupId>
<artifactId>parent</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<artifactId>backend</artifactId>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>${database.driver.groupId}</groupId>
<artifactId>${database.driver.artifactId}</artifactId>
<version>${database.driver.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
fontend
<?xml version="1.0"?>
<project
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>de.phil.mvntest</groupId>
<artifactId>parent</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<artifactId>frontend</artifactId>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>de.phil.mvntest</groupId>
<artifactId>backend</artifactId>
<version>0.0.1-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
</dependencies>
</project>
parent
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>de.phil.mvntest</groupId>
<artifactId>parent</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>pom</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<modules>
<module>backend</module>
<module>frontend</module>
</modules>
</project>
settings.xml
<?xml version="1.0" encoding="UTF-8"?>
<settings xmlns="http://maven.apache.org/SETTINGS/1.1.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.1.0 http://maven.apache.org/xsd/settings-1.1.0.xsd">
<profiles>
<profile>
<id>database</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<database.driver.groupId>mysql</database.driver.groupId>
<database.driver.artifactId>mysql-connector-java</database.driver.artifactId>
<database.driver.version>5.1.9</database.driver.version>
</properties>
</profile>
</profiles>
</settings>

Manipulating dependencies in profiles isn't very safe. The only case in which it works fairly well is to run tests against different dependencies, and even that is safer with the maven-invoker-plugin instead. The pom that gets deployed can only have one dependency set.

Related

Maven property substitution for repository url not happening if parent pom is defined

I'm having an issue where maven is not properly substituting properties into my repository URLs if and only if there is a parent pom defined. This is particularly a problem because the parent pom is IN the remote repository, so I need to have the parent pom defined.
minimum reproducible example:
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.group</groupId>
<artifactId>parent-artifact</artifactId>
<version>1.0.0</version>
<relativePath/>
</parent>
<groupId>com.group</groupId>
<artifactId>project-artifact</artifactId>
<version>1.0.0-SNAPSHOT</version>
<name>project</name>
<description>test project</description>
<properties>
<nexus.url>https://nexus.myorganization.net</nexus.url>
</properties>
<repositories>
<repository>
<id>nexus-server</id>
<url>${nexus.url}/repository/maven-releases/</url>
</repository>
</repositories>
</project>
Using this pom, I get the error message Cannot access ${nexus.url}/repository/maven-snapshots/... so clearly it is not replacing the property with the actual value.
If I remove the <parent> section of the POM, then suddenly property substitution begins working just fine:
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.group</groupId>
<artifactId>project-artifact</artifactId>
<version>1.0.0-SNAPSHOT</version>
<name>project</name>
<description>test project</description>
<properties>
<nexus.url>https://nexus.myorganization.net</nexus.url>
</properties>
<repositories>
<repository>
<id>nexus-server</id>
<url>${nexus.url}/repository/maven-releases/</url>
</repository>
</repositories>
<!-- adding this dependency so that Maven is forced to download from the repository -->
<dependencies>
<!-- some dependency here -->
</dependencies>
</project>
I know its working properly because I can see in maven's output the line Downloading from nexus-server: https://nexus.myorganization.net/repository/maven-releases/...
Any ideas?
Thanks to the commenters, the reason is because the property resolution does not occur until after the parent pom has been resolved, so that there are no property conflicts between current pom and parent pom.
More details provided at tickets MNG-2569 and MNG-624 (source).
I think you have a wrong tag in the definition of the parent.
Why is there a relativePath tag?
just remove the tag:
and try it again

Update war name based on activated maven profile

In my pom, I have two profiles.
test1
test2
Now I want my war name to change based on the activated profile.
Expected Result
When test1 profile is activated, war name should be prefix-test1.war.
When test1 and test2 are activated, war name should be prefix-test1-test2.war.
When no profile is activated, war name should be prefix.war.
My POM file ....
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.sbill</groupId>
<artifactId>sbill-wrapper</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<packaging>war</packaging>
<artifactId>executable</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
<profiles>
<profile>
<id>test1</id>
<properties>
<rp.build.warname>test1</rp.build.warname>
</properties>
</profile>
<profile>
<id>test2</id>
<properties>
<rp.build.warname>test2</rp.build.warname>
</properties>
</profile>
</profiles>
<build>
<finalName>prefix-${rp.build.warname}</finalName>
</build>
</project>
Right now if I run command mvn clean install the war name is prefix-null.war
. If I run command mvn clean install -P test1,test2 the war name is prefix-test2.war.
The result is different to what expected.
Firstly, to avoid showing null when no profiles, we can provide a default value for the property rp.build.warname, as mentioned in Setting default values for custom Maven 2 properties.
For the case running mvn clean install -P test1,test2, the war name is prefix-test2.war as the value of rp.build.warname is overridden, you may read How are conflicting properties resolved if multiple profiles are activated for more details.
In Order to have multiple values, we can use two properties(rp.build.warname1, rp.build.warname2) instead.
The following pom.xml includes the above changes
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.sbill</groupId>
<artifactId>sbill-wrapper</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<packaging>war</packaging>
<artifactId>executable</artifactId>
<!-- Provide default value here to avoid null in file name -->
<properties>
<rp.build.warname1/>
<rp.build.warname2/>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
<profiles>
<profile>
<id>test1</id>
<properties>
<rp.build.warname1>-test1</rp.build.warname1>
</properties>
</profile>
<profile>
<id>test2</id>
<properties>
<rp.build.warname2>-test2</rp.build.warname2>
</properties>
</profile>
</profiles>
<build>
<finalName>prefix${rp.build.warname1}${rp.build.warname2}</finalName>
</build>
</project>

How to update the dependency version in the parent pom when building in Jenkins

I have a project with the following pom :
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>...</groupId>
<artifactId>...</artifactId>
<version>2.5.1-RELEASE</version>
</parent>
<groupId>com.bb.cc.dd</groupId>
<artifactId>Proj1</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>pom</packaging>
<name>bla bla bla</name>
<description>abcfgd</description>
<!-- Configuration of repositories for dependency resolution -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>aa.bb.cc.dd</groupId>
<artifactId>dependencyProj</artifactId>
<version>2.0.0</version>
<type>war</type>
</dependency>
</dependencies>
</dependencyManagement>
</project>
What I am trying to achieve :
When I start a build in Jenkins for Proj1,I should have an option to start a build for dependencyProj and if that succeeds insert the new version(2.0.1) in the pom of the Proj1 and complete the build for Proj 1.So the updated pom (release version) should look like this (before the maven plugin updates it for the development iteration) :
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>...</groupId>
<artifactId>...</artifactId>
<version>2.5.1-RELEASE</version>
</parent>
<groupId>com.bb.cc.dd</groupId>
<artifactId>Proj1</artifactId>
<version>0.0.1</version>
<packaging>pom</packaging>
<name>bla bla bla</name>
<description>abcfgd</description>
<!-- Configuration of repositories for dependency resolution -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>aa.bb.cc.dd</groupId>
<artifactId>dependencyProj</artifactId>
<version>2.0.1</version>
<type>war</type>
</dependency>
</dependencies>
</dependencyManagement>
</project>
Note : I tried the "Trigger build" option from the main project and the Post Build Step "Build other projects" from dependency project but none of them update the versions when cheking in to git.Just to add i used the maven release plugin here.
Is it possible to configure jenkins to update the version of the dependent projects in the pom?

How to develop a Maven Multi-module application using the Spring Boot framework

I have a maven multi-module Java project that runs perfectly, until I try to include the Spring Boot framework. The main module, called core, gets called OK, but all the rest are unable to implement the interface I declared in Core.java.
This error gets thrown:
[ERROR] /F:/mvnmodularapp/module1/src/main/java/service/impl/ModuleServiceImpl.java:[12,30] cannot find symbol
[ERROR] symbol: class Service
[ERROR] /F:/mvnmodularapp/module1/src/main/java/service/impl/ModuleServiceImpl.java:[13,5] method does not override or implement a method from a supertype
The project structure:
mvnmodularapp/
/pom
mvnmodularapp/core/
/src
/target/core-1.0-SNAPSHOT.jar
mvnmodularapp/module1
/src
/target/module1-1.0-SNAPSHOT.jar
THe file/directory structure:
core/src/java/service/
Service.java
core/src/java/service/impl
CoreServiceImpl.java
module1/src/java/service/impl
ModuleServiceImpl.java
Service.java
public interface Service {
String getName();
}
CoreServiceImpl.java in core
#Service
public class ServiceImpl implements Service {
#Override
public String getName() {
return "Hi. You called me from ServiceImpl in Core";
}
}
ModuleServiceImpl.java in module1
#Service
public class ModuleServiceImpl implements Service {
#Override
public String getName() {
return "Hi. You called me from ModuleServiceImpl in module1, but I can\'t pick up right now. Sorry";
}
}
THE POMS
mvnmodularapp pom
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.mvnmodularapp</groupId>
<artifactId>mvnmodularapp</artifactId>
<packaging>pom</packaging>
<version>1.0-SNAPSHOT</version>
<modules>
<module>core</module>
<module>module1</module>
</modules>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.4.3.RELEASE</version>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
</project>
core pom
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>mvnmodularapp</artifactId>
<groupId>com.mvnmodularapp</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>core</artifactId>
<version>1.0-SNAPSHOT</version>
<name>Core</name>
<description>SudenGut application</description>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<start-class>main</start-class>
<java.version>1.8</java.version>
<tomcat.version>8.0.24</tomcat.version>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--- this will not be enough to provide a cool app :) -->
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
module1 pom
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>mvnmodularapp</artifactId>
<groupId>com.mvnmodularapp</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>module1</artifactId>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<start-class>baseview.impl.BaseViewImpl.ModuleServiceImpl</start-class>
<java.version>1.8</java.version>
<tomcat.version>8.0.24</tomcat.version>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--- this will not be enough to provide a cool app :) -->
<dependency>
<groupId>com.mvnmodularapp</groupId>
<artifactId>core</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Dependencies between modules are correctly declared but you have one thing that is not configured as required.
I am not sure it will solve your problem but it could.
You declare in each module :
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
It should be required only for the module which bootstraps the Spring Boot application.
If you want have multiple web applications in the same Spring Boot container, you could read this question.
As you say that it works before adding Spring Boot I think that the problem should be solved with previous recommandation.
But if it is not enough, below are other guessworks which could be the cause of the compilation error. I rely on this error message :
[ERROR]
/F:/mvnmodularapp/module1/src/main/java/service/impl/ModuleServiceImpl.java:[12,30]
cannot find symbol [ERROR] symbol: class Service
The Service class is not imported in ModuleServiceImpl.
If I rely on what you write in your question, you should add :
import service.Service in the imports of ModuleServiceImpl.
The core module doesn't create a JAR with the service.Service class.
So, importing it doesn't solve the problem of the module1 module.
You should perform a mvn clean install from the core module and check that the jar contains the compiled class : service.Service in the good package.

maven version dependency injection to sub modules

I purchased the 'Apache Maven 3 Cookbook' and I'm trying to learn on adding dependencies to my maven projects.
my main project pom.xml:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven- 4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>net.srirangan.packt.maven</groupId>
<artifactId>TestModularApp</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>pom</packaging>
<name>TestModularApp</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.2</version>
</dependency>
</dependencies>
<modules>
<module>ChildProject</module>
<module>MyWebApp</module>
</modules>
</project>
as you can see here the packaging in this project is set to "pom" because this is the parent project.. ( that's all i know :) )
and then I created a subproject with the following pom.xml:
<?xml version="1.0"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>net.srirangan.packt.maven</groupId>
<artifactId>TestModularApp</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<groupId>com.xpogames.childproject</groupId>
<artifactId>ChildProject</artifactId>
<version>1.0-SNAPSHOT</version>
<name>ChildProject</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
</dependencies>
</project>
as you can see here i did not add a version property to the mysql-connect-java dependency because it supposed to inherit the version from the parent project. but for some reason, it doesn't.
when I run mvn compile on that project i get an error that the dependencies.dependency.version property is missing.
any ideas what i'm doing wrong? how can I resolve the issue that i won't need to specify versions in sub-projects too ?
thanks!
update
after watching Peter Lawrey's answer and watching the example on the url he provided
I noticed that my main XML is missing the property <dependencyManagement> around the <dependencies>. once I added that property then I didn't need to provide a version number in the sub-project.
Peter answer shows another method to achieve this goal.
thanks for everything!
Kfir
You inherit versions from the dependencies in the dependencyManagement section of your parent pom(s) and selectively include these in child poms.
In your case you don't need to mention the dependency again as it already included from the parent. (As it is for JUnit)
BTW: I use JUnit 4.10 which I haven't found any backward compatibility problems with.

Categories