Maven profiles behaviour with plugins - maven

Let's say I have a multi-module maven project. One of the project's POM file is the following:
<?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>some.group</groupId>
<artifactId>parent-artifact</artifactId>
<version>0.14.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<artifactId>artifact-x</artifactId>
<packaging>jar</packaging>
<name>Artifact X</name>
<dependencies>
<dependency>
<groupId>some.group</groupId>
<artifactId>artifact-a</artifactId>
<version>${project.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>some.group</groupId>
<artifactId>artifact-b</artifactId>
<version>${project.version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>some.group</groupId>
<artifactId>artifact-c</artifactId>
<version>${project.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>some.group</groupId>
<artifactId>artifact-d</artifactId>
<version>${project.version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>some.group</groupId>
<artifactId>artifact-e</artifactId>
<version>${project.version}</version>
<scope>runtime</scope>
</dependency>
</dependencies>
</project>
Let's say for some reason, I want to move some of the dependencies in this POM file to a profile. So, I move artifact-c, artifact-d, artifact-e to only be dependencies when using profile-1. profile-1 is also used in other POMs in the project. My new POM now becomes:
<?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>some.group</groupId>
<artifactId>parent-artifact</artifactId>
<version>0.14.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<artifactId>artifact-x</artifactId>
<packaging>jar</packaging>
<name>Artifact X</name>
<dependencies>
<dependency>
<groupId>some.group</groupId>
<artifactId>artifact-a</artifactId>
<version>${project.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>some.group</groupId>
<artifactId>artifact-b</artifactId>
<version>${project.version}</version>
<scope>runtime</scope>
</dependency>
</dependencies>
<profiles>
<profile>
<id>profile-1</id>
<dependencies>
<dependency>
<groupId>some.group</groupId>
<artifactId>artifact-c</artifactId>
<version>${project.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>some.group</groupId>
<artifactId>artifact-d</artifactId>
<version>${project.version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>some.group</groupId>
<artifactId>artifact-e</artifactId>
<version>${project.version}</version>
<scope>runtime</scope>
</dependency>
</dependencies>
</profile>
</profiles>
</project>
When building, I run mvn -Pprofile-1 clean package at the top-level POM in both cases. My expectation was that moving dependencies to a profile shouldn't change anything when -Pprofile-1 was specified. But that didn't happen - some of the plugins started behaving erroneously - for ex. the maven-shade-plugin didn't put artifact-c, artifact-d and artifact-e in the shaded jar etc.
Am I doing something wrong? Are profiles not supposed to work like this?
Are these two POM files not equivalent even when used with -Pprofile-1?

Even though the pom.xml allows you to define it like this, you shouldn't (call it a design flaw). Most of the times it doesn't make sense to just add dependencies in a profile. Valid constructions are dependencies based on OS or on JDK version.
Also remember that the pom.xml also acts as "consumer-pom", so other projects using this artifact will read this pom file to get the transitive dependencies. In such case you can't active a profile anymore.
In conclusion: don't try to solve this with profiles. There must be a better solution.

Related

Intellij / Spring Security - unable to expand - spring-security-oauth2-core dependency?

When I am analyzing dependencies in intelij using Analyze Dependencies.. feature, i am seeing that at one hierarchy i am able to expand spring-security-oauth2-core and I am not able to expand the same at different hierarchy. Why is this so.
Able to expand below -
Unable to expand below -
Seems quite trivial, but if I am looking at a new dependency I would not be able to determine for sure if it's an end-node (i.e has no further deps) until I can find an answer for this Q.
Edit - Below is the pom.xml if some one want to try at there end.
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.3</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>spring-security-only</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>spring-security-only</name>
<description>spring-security-only</description>
<properties>
<java.version>11</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
It does not show the nested dependencies for the omitted dependencies.

Not able to access maven dependency from a common folder in same directory

I am using a multi-module approach in Spring boot application. My directory structure is like
package name
|_bom
|__common-test
|__service
|_src/test/java/TestFile.java
I have put test related dependencies in pom.xml of common-test and accessing them in test folder of service. I am able to access most of the dependencies in TestFile.java but not the dependency mentioned below. This is the last dependency in pom.xml of common-test. Following the same structure I am able to use mockito dependency but not this one.
I have defined related properties in bom/pom.xml which are to be used in common-test/pom.xml. Using this approach for first time and not sure how to achieve this. Basically, I need to maintain test related dependencies in common-test pom.xml and not include it in service.
import org.junit.jupiter.migrationsupport.rules.EnableRuleMigrationSupport;
pom.xml of common-test have this dependency
<?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>projeectname</artifactId>
<groupId>in.packagename.mint</groupId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>projeectname-common-test</artifactId>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>in.packagename.mint</groupId>
<artifactId>projeectname-bom</artifactId>
<version>${project.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<!-- project dependencies -->
<dependencies>
<!-- https://mvnrepository.com/artifact/org.mockito/mockito-junit-jupiter -->
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-junit-jupiter</artifactId>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-migrationsupport</artifactId>
</dependency>
</dependencies>
</project>
pom.xml of bom
<?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 coordinates -->
<parent>
<groupId>in.packagename.mint</groupId>
<artifactId>projectname</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<artifactId>projectname-bom</artifactId>
<properties>
<junit.jupiter.migration-support.version>5.7.0</junit.jupiter.migration-support.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-junit-jupiter</artifactId>
<version>3.5.13</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-migrationsupport</artifactId>
<version>${junit.jupiter.migration-support.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>
I have tried deleting .m2 folder and building all these bom, common-test, etc. separately and runnning mvn install but this dependency issue is not resolved and not able to import it in service test folders.

How to use controller service api from a dependency

I have a custom controller service that I want to use together with the ConnectWebSocket processor. The controller service depends on nifi-websocket-services-api and does not need a custom api (the my-customer-controller-service-api folder is empty). I have written a test for the controller service and it is passing.
However I cannot select the controller service, because ConnectWebSocket only accepts a controller service api from nifi-websocket-service-api-nar.
I want to avoid to recode the entire ConnectWebSocket processor. So my question is:
Is it possible to configure the dependencies such that my custom controller service uses the api that comes from nifi-websocket-service-api-nar?
pom.xml of controller-service:
<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.mydomain</groupId>
<artifactId>nifi-controllerservice-bundle</artifactId>
<version>1.9.2</version>
</parent>
<artifactId>nifi-controllerservice</artifactId>
<packaging>jar</packaging>
<dependencies>
<!-- normal dependencies -->
<dependency>
<groupId>org.apache.nifi</groupId>
<artifactId>nifi-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.nifi</groupId>
<artifactId>nifi-processor-utils</artifactId>
<version>1.9.2</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.apache.nifi</groupId>
<artifactId>nifi-websocket-services-api</artifactId>
<version>1.9.2</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.nifi</groupId>
<artifactId>nifi-websocket-services-jetty</artifactId>
<version>1.9.2</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.nifi</groupId>
<artifactId>nifi-ssl-context-service-api</artifactId>
<scope>provided</scope>
</dependency>
<!-- Test dependencies -->
</dependencies>
pom.xml of controller-service-nar
<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.mydomain</groupId>
<artifactId>nifi-controllerservice-bundle</artifactId>
<version>1.9.2</version>
</parent>
<artifactId>nifi-controllerservice-nar</artifactId>
<version>1.9.2</version>
<packaging>nar</packaging>
<properties>
<maven.javadoc.skip>true</maven.javadoc.skip>
<source.skip>true</source.skip>
</properties>
<dependencies>
<dependency>
<groupId>com.mydomain</groupId>
<artifactId>nifi-controllerservice</artifactId>
<version>1.9.2</version>
</dependency>
<dependency>
<groupId>org.apache.nifi</groupId>
<artifactId>nifi-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.nifi</groupId>
<artifactId>nifi-websocket-services-jetty</artifactId>
<version>1.9.2</version>
<scope>nar</scope>
</dependency>
</dependencies>
</project>
root pom.xml
<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>org.apache.nifi</groupId>
<artifactId>nifi-nar-bundles</artifactId>
<version>1.9.2</version>
</parent>
<groupId>com.mydomain</groupId>
<artifactId>nifi-controllerservice-bundle</artifactId>
<version>1.9.2</version>
<packaging>pom</packaging>
<modules>
<module>nifi-comtom</module>
<module>nifi-comtom-nar</module>
</modules>
</project>
This should be the standard way processors and controller services work...
Processors depend on an interface which comes from the service API NAR, and controller service implementations implement that interface. The framework then knows all the implementations of that interface which allows is to provide the possible services that can be used.
Without seeing your project and poms it is hard to say what the problem is, but most likely it is a dependency issue. Your project structure should have two Maven modules, one that produces a jar for your service impl, lets call this one custom-service, and then one that packages the NAR, lets call this custom-service-nar.
The custom-service module should have a provided dependency on nifi-websocket-services-api, this allows it to compile, but we don't want to bundle that API since at runtime it will come from another NAR.
The custom-service-nar module should have a dependency of type NAR on the nifi-websocket-services-api-nar.
https://cwiki.apache.org/confluence/display/NIFI/Maven+Projects+for+Extensions#MavenProjectsforExtensions-LinkingProcessorsandControllerServices

Spring Boot Application cannot be resolved to a type but I imported it in pom.xm

I have added the spring boot in pom.xml but still it is giving an error.
Can anyone help me.
It is giving error The import org.springframework.boot.autoconfigure.SpringBootApplication cannot be resolved
and
SpringBootApplication cannot be resolved to a type
My pom. xml is
<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>
<groupId>com.webapp</groupId>
<artifactId>proj1</artifactId>
<packaging>war</packaging>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.3.5.RELEASE</version>
</parent>
<version>0.0.1-SNAPSHOT</version>
<name>proj1 Maven Webapp</name>
<url>http://maven.apache.org</url>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<finalName>proj1</finalName>
</build>
</project>
Your pom looks almost correct, but few things to note
No need to add dependency 'javax.servlet-api', it is available from 'spring-boot-starter-web'
And you probably you may be missing the 'spring-boot-maven-plugin', it is not compulsory but you may want that in your project. Where it provides some easy maven goals for you to run.
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
if your running eclipse you can generate your .classpath files just as usual
mvn eclipse:eclipse, once done your ide should look fine
then mvn spring-boot:run should set your application running

Spring Boot multi module Maven project deployment

We have multi module Maven project with following modules:
Commons
Model
Repository
Service
Web
We've googled around and we didn't found a solution how to make one executable jar when project has this kind of structure.
Here is the parent pom.xml:
<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>...</groupId>
<artifactId>...</artifactId>
<version>1.0-SNAPSHOT</version>
<modules>
<module>Model</module>
<module>Web</module>
<module>Service</module>
<module>Repository</module>
<module>Common</module>
</modules>
<packaging>pom</packaging>
<name>Api</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.8</java.version>
<mssql.jdbc.driver.version>4.2</mssql.jdbc.driver.version>
<apache.commons.lang.version>3.3.2</apache.commons.lang.version>
<apache.commons.collection.utils.version>4.1</apache.commons.collection.utils.version>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.4.1.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-envers</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
</dependencies>
</project>
So, very basic parent pom.xml. We know that we can't use Spring Boot Maven plugin when packaging is pom, so we've defined it in pom.xml from Web module:
<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>...</artifactId>
<groupId>...</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>...</groupId>
<artifactId>...</artifactId>
<packaging>jar</packaging>
<name>...</name>
<dependencies>
<dependency>
<groupId>...</groupId>
<artifactId>Service</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>1.4.1.RELEASE</version>
<configuration>
<mainClass>...App</mainClass>
</configuration>
<!--<executions>-->
<!--<execution>-->
<!--<goals>-->
<!--<goal>repackage</goal>-->
<!--</goals>-->
<!--</execution>-->
<!--</executions>-->
</plugin>
</plugins>
</build>
</project>
The rest of pom.xmls from other modules are pretty much the same: Service's pom.xml includes Repository.jar, Repository includes Model and Common.
Problem 1: when we run mvn install, plugin creates fat jar in target folder of web module. But when we try to run it with java -jar name-of-jar it gives java.lang.NoClassDefFoundError about some class from Service module - and you can see from Web's pom.xml that Service module is included (there is also a Service.jar packed as library in Web.jar)
Problem 2: what's interesting is that Service.jar inside of Web.jar also contains pretty much all the dependencies that are already present in Web.jar - basically they are duplicated.
Did anyone managed to create executable fat jar using Spring Boot Maven plugin and Maven Module project structure?
Problem 1 & 2
You should not have devtools as dependency in your parent pom.
Move the following to the web/spring-boot module:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
If you look at devtools's pom, it includes the following:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
</dependency>
So your service jar ends up with some spring boot dependencies.

Resources