Maven dynamically exclude class with same name from different dependencies - maven

There are two classes com.package.A, one coming from
<dependency>
<groupId>com.package</groupId>
<artifactId>art1</artifactId>
</dependency>
and one coming from
<dependency>
<groupId>com.package</groupId>
<artifactId>art2</artifactId>
</dependency>
Notice that the artifact ids are different.
For different Maven profiles, I want to exclude one version and just keep the other version. I am using the Shade Plugin.

With the maven-shade-plugin, it is possible to exclude certain class for specific dependencies. This is configured with the help of the filters property:
Archive Filters to be used. Allows you to specify an artifact in the form of a composite identifier as used by artifactSet and a set of include/exclude file patterns for filtering which contents of the archive are added to the shaded jar.
In your case, to exclude the class com.package.A from the dependency art2, you can have:
<filters>
<filter>
<artifact>com.package:art2</artifact>
<excludes>
<exclude>com/package/A.class</exclude>
</excludes>
</filter>
</filters>
To make this dynamic, i.e. select at build-time which com.package.A class you want to keep, you don't need to use a profile. You can use a Maven property that will hold the artifact id of the dependency to filter. In your properties, add
<properties>
<shade.exclude.artifactId>art2</shade.exclude.artifactId>
</properties>
The shade.exclude.artifactId property will hold the artifact id of the dependency to filter. By default, this configuration would select art2. Then, in the <filter> configuration of the Shade Plugin, you can use <artifact>com.package:${shade.exclude.artifactId}</artifact>.
Here's a full configuration of this in action:
<build>
<plugins>
<plugin>
<artifactId>maven-shade-plugin</artifactId>
<version>2.4.3</version>
<executions>
<execution>
<id>shade</id>
<goals>
<goal>shade</goal>
</goals>
<phase>package</phase>
<configuration>
<filters>
<filter>
<artifact>com.package:${shade.exclude.artifactId}</artifact>
<excludes>
<exclude>com/package/A.class</exclude>
</excludes>
</filter>
</filters>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<properties>
<shade.exclude.artifactId>art2</shade.exclude.artifactId>
</properties>
Running mvn clean package will create an uber jar with the A.class from art1 since the one from art2 was excluded. And then, running mvn clean package -Dshade.exclude.artifactId=art1 will keep this time A.class from the dependency art2 since the one from art1 was excluded.

Related

Missing "Artifacts" from uber jar using IntelliJ / Maven

I am developing a Flink application, and I'm very new to building Java applications.
I am using IntelliJ 2022.2.3 Community Edition, and Maven for dependency management.
I have the following dependencies in my POM file:
<!-- https://mvnrepository.com/artifact/com.amazonaws/amazon-sqs-java-messaging-lib -->
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>amazon-sqs-java-messaging-lib</artifactId>
<version>2.0.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.postgresql/postgresql -->
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.5.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.amazonaws/aws-kinesisanalytics-runtime -->
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-kinesisanalytics-runtime</artifactId>
<version>1.2.0</version>
</dependency>
When I build the artifact and view its contents, I notice that some of the dependancies are included, and others are missing. I expect to see the postgressql drivers at org/postgressql/... but that folder does not exist.
I have a copy of the project where the artifacts folder does contain the expected folders and when I look at the project settings/artifacts/output layout view, the postgres jars are in the list, but not in my problem project?
I read How can I create an executable/runnable JAR with dependencies using Maven? and i don't have that section in the POM, but in my case as I mentioned the 2 projects I have seem to have different artifacts missing from the jar?
Sorry for my lack of correct terminology.
UPDATE:
I should add this section is in my POM
<!-- We use the maven-shade plugin to create a fat jar that contains all necessary dependencies. -->
<!-- Change the value of <mainClass>...</mainClass> if your program entry point changes. -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.1.1</version>
<executions>
<!-- Run shade goal on package phase -->
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<artifactSet>
<excludes>
<exclude>org.apache.flink:flink-shaded-force-shading</exclude>
<exclude>com.google.code.findbugs:jsr305</exclude>
<exclude>org.slf4j:*</exclude>
<exclude>org.apache.logging.log4j:*</exclude>
</excludes>
</artifactSet>
<filters>
<filter>
<!-- Do not copy the signatures in the META-INF folder.
Otherwise, this might cause SecurityExceptions when using the JAR. -->
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
</filters>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>vendor.flink.StreamProcessingNoJoin</mainClass>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>

Maven shade plugin does not exclude an artifact

I need to exclude the log4j artifact from the shade plug-in to avoid the log4j vulnerability, however, the exclude tag under artifactSet does not seem to work. Any suggestion to fix this?
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.4</version>
~~
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<artifactSet>
<excludes>
<exclude>*:log4j-core:jar</exclude>
</excludes>
</artifactSet>
~~~
I keep getting below error:
Failed to execute goal org.apache.maven.plugins:maven-shade-plugin:3.2.4:shade (default) on project : Execution default of goal org.apache.maven.plugins:maven-shade-plugin:3.2.4:shade failed: Plugin org.apache.maven.plugins:maven-shade-plugin:3.2.4 or one of its dependencies could not be resolved: Could not find artifact org.apache.logging.log4j:log4j-core:jar:2.13.0
I meet the same problem, and finally solved by maven-shade-plugin config. In your case, you want to exclude log4j-core, your filter config must put outside of artifactSet as below.
find log4j-core class path prefix, for example org/slf4j/;
put this class path prefix in filter exclude rule, run cmd mvn package
use vim your-target.jar to check exclude success or not, you will find that org/slf4j has gone.
for more exclude info, pls see https://maven.apache.org/plugins/maven-shade-plugin/examples/includes-excludes.html
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>org/slf4j/**</exclude>
</excludes>
</filter>

Using Spring Boot without the parent POM [duplicate]

Is there a specific recommended approach to the inclusion of the spring-boot parent pom into projects that already have a required parent POM?
What do you recommend for projects that need to extend from an organizational parent (this is extremely common and even something many/most projects published to Maven central depending on the feeder repos they come from). Most of the build stuff is related to creating executable JARs (e.g. running embedded Tomcat/Jetty). There are ways to structure things so that you can get all the dependencies without extending from a parent (similar to composition vs. inheritance). You can't get a build stuff that way though.
So is it preferable to include all of the spring-boot parent pom inside of the required parent POM or to simply have a POM dependency within the project POM file.
Other options?
TIA,
Scott
You can use the spring-boot-starter-parent like a "bom" (c.f. Spring and Jersey other projects that support this feature now), and include it only in the dependency management section with scope=import.That way you get a lot of the benefits of using it (i.e. dependency management) without replacing the settings in your actual parent.
The 2 main other things it does are
define a load of properties for quickly setting versions of dependencies that you want to override
configure some plugins with default configuration (principally the Spring Boot maven plugin). So those are the things you will have to do manually if you use your own parent.
Example provided in Spring Boot documentation:
<dependencyManagement>
<dependencies>
<dependency>
<!-- Import dependency management from Spring Boot -->
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.1.3.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
Update 2022-05-29 with 1.5.9.RELEASE.
I have full code and runable example here https://github.com/surasint/surasint-examples/tree/master/spring-boot-jdbi/9_spring-boot-no-parent (see README.txt to see that you can try)
You need this as a basic
<dependencyManagement>
<dependencies>
<dependency>
<!-- Import dependency management from Spring Boot -->
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${springframework.boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
But that is not enough, you also need explicitly define goal for spring-boot-maven-plugin (If you use Spring Boot as parent, you do not have to explicitly define this)
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${springframework.boot.version}</version>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
Otherwise you cannot build as executable jar or war.
Not yet, if you are using JSP, you need to have this:
<properties>
<failOnMissingWebXml>false</failOnMissingWebXml>
</properties>
Otherwise, you will get this error message:
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-war-plugin:2.2:war (default-war) on project spring-boot-09: Error assembling WAR: webxml attribute is required (or pre-existing WEB-INF/web.xml if executi
ng in update mode) -> [Help 1]
NO NO , this is still not enough if you are using Maven Profile and Resource Filter with Spring Boot with "#" instead of "${}" (like this example https://www.surasint.com/spring-boot-maven-resource-filter/). Then you need to explicitly add this in
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
And this in
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>2.7</version>
<configuration>
<delimiters>
<delimiter>#</delimiter>
</delimiters>
<useDefaultDelimiters>false</useDefaultDelimiters>
</configuration>
</plugin>
See the example in the link https://www.surasint.com/spring-boot-with-no-parent-example/.
As per Surasin Tancharoen's answer, you may also want to define maven surefire plugin
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>${maven-surefire-plugin.version}</version>
</plugin>
and possibly include fail-fast plugin
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>${maven-failsafe-plugin.version}</version>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
</execution>
</executions>
</plugin>

Aggregate findbugs report in Maven 3.0.5

I am using multi-module Maven Project ( more than 10 modules ). I am trying to create a findbugs report of all module in single html page. Is there any way?
For creating individual report for each module, i am using the below
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>findbugs-maven-plugin</artifactId>
<version>3.0.0</version>
<configuration>
<!--
Enables analysis which takes more memory but finds more bugs.
If you run out of memory, changes the value of the effort element
to 'Low'.
-->
<effort>Max</effort>
<!-- Build doesn't fail if problems are found -->
<failOnError>false</failOnError>
<!-- Reports all bugs (other values are medium and max) -->
<threshold>Low</threshold>
<!-- Produces XML report -->
<xmlOutput>false</xmlOutput>
<skip>${skipFindbugs}</skip>
<!-- Configures the directory in which the XML report is created -->
<findbugsXmlOutputDirectory>${project.build.directory}/findbugs</findbugsXmlOutputDirectory>
</configuration>
<executions>
<!--
Ensures that FindBugs inspects source code when project is compiled.
-->
<execution>
<phase>compile</phase>
<goals>
<goal>findbugs</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>xml-maven-plugin</artifactId>
<version>1.0</version>
<configuration>
<transformationSets>
<transformationSet>
<!-- Configures the source directory of XML files. -->
<dir>${project.build.directory}/findbugs</dir>
<!-- Configures the directory in which the FindBugs report is written.-->
<outputDir>${project.build.directory}/findbugs</outputDir>
<!-- Selects the used stylesheet. -->
<!-- <stylesheet>fancy-hist.xsl</stylesheet> -->
<stylesheet>${project.parent.basedir}/default.xsl</stylesheet>
<!--<stylesheet>plain.xsl</stylesheet>-->
<!--<stylesheet>fancy.xsl</stylesheet>-->
<!--<stylesheet>summary.xsl</stylesheet>-->
<fileMappers>
<!-- Configures the file extension of the output files. -->
<fileMapper implementation="org.codehaus.plexus.components.io.filemappers.FileExtensionMapper">
<targetExtension>.html</targetExtension>
</fileMapper>
</fileMappers>
</transformationSet>
</transformationSets>
</configuration>
<executions>
<!-- Ensures that the XSLT transformation is run when the project is compiled. -->
<execution>
<phase>compile</phase>
<goals>
<goal>transform</goal>
</goals>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>com.google.code.findbugs</groupId>
<artifactId>findbugs</artifactId>
<version>3.0.0</version>
</dependency>
</dependencies>
</plugin>
According to official documentation of the plugin (question n. 1), it is not possible.
However, here is the approach I used to achieve it:
Add an additional module to your existing multimodule project. This additional module will only be used for reporting
Configure the Buildhelper Maven Plugin to dynamically add the source code of the other modules to the reporting module. Note: you can do the same for resources, if required.
Configure the Findbugs plugin only on the reporting module
Add the other modules as dependencies of the reporting module, in order to have the Maven reactor build to build it only at the end.
If required: you don't want the reporting module to be part of your default build, create a profile in the aggregator/parent module which redefines the modules element and add the reporting module to it. As such, only when the profile will be activated (i.e. via command line, on demand) the reporting module will be added and the aggregated report will be created.
As an example, in the aggregator/parent module you can define as following:
<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.sample</groupId>
<artifactId>findbugs-parent</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>pom</packaging>
<modules>
<module>findbugs-module1</module>
<module>findbugs-module2</module>
</modules>
<profiles>
<profile>
<id>findbugs-reporting</id>
<modules>
<module>findbugs-module1</module>
<module>findbugs-module2</module>
<module>findbugs-reporting</module>
</modules>
</profile>
</profiles>
</project>
Note: the findbugs-reporting module is only added in the findbugs-reporting profile. By default, the build will ignore it.
In the findbugs-reporting module, configure the POM using the configuration you posted (findbugs and XML maven plugin) and also add as following:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>1.9.1</version>
<executions>
<execution>
<id>add-source</id>
<phase>generate-sources</phase>
<goals>
<goal>add-source</goal>
</goals>
<configuration>
<sources>
<source>..\findbugs-module1\src\main\java</source>
<source>..\findbugs-module2\src\main\java</source>
</sources>
</configuration>
</execution>
</executions>
</plugin>
Note the added sources from other modules (change it according to your project).
Furthermore, we also need to add dependencies to the reporting module. It has to depend on other modules in order to be built at the end (and as such make sure to take the latest changes/sources from other modules). As an example:
<dependencies>
<dependency>
<groupId>com.sample</groupId>
<artifactId>findbugs-module1</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.sample</groupId>
<artifactId>findbugs-module2</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
</dependencies>
Finally, you can invoke the reporting build as following from the aggregator/parent dir:
mvn clean install -Pfindbugs-reporting
As such, you will build the whole project and additionally activate the reporting module, which will dynamically include sources from other modules (as configured) and generate an aggregated report.
Depending on your needs, you can avoid the profile step (if you want it as part of your default build) or activate the profile by default (so that you can skip the reporting build deactivate it via -P!findbugs-reporting) or use the skipFindbugs property you already configured (and without the profile, in such a case).

Linkage failure when running Apache Flink jobs

I have a job developed in Flink 0.9 that is using the graph module (Gelly). The job is running successfully within the IDE (Eclipse) but after exporting it to a JAR using maven (mvn clean install) it fails to execute on the local flink instance with the following error
"The program's entry point class 'myclass' could not be loaded due to a linkage failure"
java.lang.NoClassDefFoundError: org/apache/flink/graph/GraphAlgorithm
Any idea why is this happening and how to solve it?
It looks like the code of flink-gelly did not end up in your jar file.
The most obvious reason for this issue is the missing maven dependency in your project's pom file. But I assume the dependency is present, otherwise developing the job in the IDE would be impossible.
Most likely, the jar file has been created by the maven-jar-plugin, which is not including dependencies.
Try adding the following fragment to your pom.xml:
<build>
<plugins>
<!-- We use the maven-shade plugin to create a fat jar that contains all dependencies
except flink and it's transitive dependencies. The resulting fat-jar can be executed
on a cluster. Change the value of Program-Class if your program entry point changes. -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.3</version>
<executions>
<!-- Run shade goal on package phase -->
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<filters>
<filter>
<artifact>org.apache.flink:*</artifact>
<excludes>
<exclude>org/apache/flink/shaded/**</exclude>
<exclude>web-docs/**</exclude>
</excludes>
</filter>
</filters>
<transformers>
<!-- add Main-Class to manifest file -->
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>YOURMAINCLASS</mainClass>
</transformer>
</transformers>
<createDependencyReducedPom>false</createDependencyReducedPom>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<!-- A profile that does everyting correctly:
We set the Flink dependencies to provided -->
<id>build-jar</id>
<activation>
<activeByDefault>false</activeByDefault>
</activation>
<dependencies>
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-java</artifactId>
<version>0.9-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-streaming-core</artifactId>
<version>0.9-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-clients</artifactId>
<version>0.9-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
</dependencies>
</profile>
</profiles>
Now, you can build the jar using mvn clean package -Pbuild-jar.
The jar file will now be located in the target/ directory.
You can manually check whether the jar (zip) file contains class files in /org/apache/flink/graph/

Resources