Does maven shade plugin automatically downcase the package names on Windows? - java

I have two local artifacts: one with com.org.abc, another with COM.org.xyz. I have created a shaded jar including these 2 and all the other needed dependencies.
WHEN I CREATE A SHADED JAR ON LINUX, 2 SEPARATE FOLDERS ARE CREATED : com and COM. BUT ON WINDOWS ONLY SINGLE FOLDER IS CREATED.
When I create a shaded jar on windows, it creates a single folder: com.org with folders abc and xyz inside. No separate uppercase COM folder is created. Therefore the code dependent on uppercase COM package fails with could not initialize class error.
(I didn't name the above 2, they were created and distributed individually by 2 separate teams and many teams have been using these jars so changing the package name is a long cycle)
Maven config:
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-install-plugin</artifactId>
<version>2.5.2</version>
<executions>
<execution>
<id>add-mylocal</id>
<phase>clean</phase>
<configuration>
<file>${jars.path}/mylocal.jar</file>
<repositoryLayout>default</repositoryLayout>
<groupId>com.org</groupId>
<artifactId>mylocal</artifactId>
<version>1.0</version>
<packaging>jar</packaging>
<generatePom>true</generatePom>
<localRepositoryPath>${local.repo.path}</localRepositoryPath>
</configuration>
<goals>
<goal>install-file</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.1.0</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<source>1.7</source>
<target>1.7</target>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<manifestEntries>
<Build-Version>${buildversion} (${timestamp})</Build-Version>
</manifestEntries>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
Any solution to make it work on windows?

Documenting the discussion from the comments as an answer for posterity:
The issue here isn't maven-shade-plugin, which doesn't modify (or even care about) the case of the package. The issue here is that the underlying [windows] filesystem is case-insensitive, and does not differentiate between com and COM.
Unless you're willing to change the package names, there's no workaround from within maven-shade-plugin. You'll have to use a case-sensitive file system. Once appealing option would be to use the Windows Subsystem for Linux, which provides its own case-sensitive file system (ext4, IIRC).
There's also a method to make an NTFS filesystem case sensitive (see, e.g., this SU thread), but I've never done so myself, and can't recommend it based on personal experience.

While maven shade actually seems to delete the uppercase COM directory, it actually merges it with the lowercase one.
This distinction seems small, but allows us to use a special part of maven shade to solve this, namely, the relocation feature.
Using this feature, we can relocate the weirdly named uppercase library to lowercase, without requiring any changes in the source of those libraries.
<relocations>
<relocation>
<pattern>COM.org.xyz</pattern>
<shadedPattern>com.org.xyz</shadedPattern>
</relocation>
</relocations>
Your final shade config will look like:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.1.0</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<source>1.7</source>
<target>1.7</target>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<manifestEntries>
<Build-Version>${buildversion} (${timestamp})</Build-Version>
</manifestEntries>
</transformer>
</transformers>
<relocations>
<relocation>
<pattern>ME.ferrybig.uppercase.com</pattern>
<shadedPattern>me.ferrybig.uppercase.com</shadedPattern>
</relocation>
</relocations>
</configuration>
</execution>
</executions>
</plugin>

I found the solution to the above problem. Although the best practice, as also suggested by Ferrybig and Mureinik in their answers, is to enforce the lowercase package name standards to the projects but since in my case this was not possible, I have followed following approach.
Issue in short:
On Windows, shade plugin was merging COM folders with com , because Windows treat them as case-insensitive so if a package com is already created, it would add contents of COM in this only rather than creating new one.
Solution:
In my shade plugin, I have created 2 uber jars - one containing uppercase COM packages and second with all the other dependencies. This solved the issue because because there was no conflict with com in the first jar as it containing only COM.
The configuration that I used was from this post.
Basically in first execution block, I included artifacts containing COM packages and excluded the same from second execution block:
Execution block 1:
<include><artifact_name_with_COM_package></include>
Execution block 2:
<exclude><artifact_name_with_COM_package></exclude>
NOTE: Once again, the first choice should be to enforce naming standards in packages. But if you want a quick workaround you can try this.

Related

Renaming a fat jar with Maven

When I create a jar file I want to fit inside my dependencies. For that, I use maven-assembly-plugin such as follows:
<build>
...
<plugins>
...
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.4</version>
<configuration>
<finalName>${project.artifactId}-GUI</finalName>
<archive>
<manifest>
<mainClass>gui.MyMainClass</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<!-- <appendAssemblyId>false</appendAssemblyId>-->
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
This code works OK and it does what it's expected to do. However, this creates a new jar called myjar-GUI-jar-with-dependencies.jar. I would like to eliminate that "jar-with-dependencies" ending. Does anybody knows how to do that?
I have used that commented line you can see on my code, but that produces the following warning that I don't know how to solve it:
[WARNING] Configuration options: 'appendAssemblyId' is set to false, and 'classifier' is missing.
Instead of attaching the assembly file: [myJar-GUI].jar, it will become the file for main project artifact.
NOTE: If multiple descriptors or descriptor-formats are provided for this project, the value of this file will be non-deterministic!
[WARNING] Replacing pre-existing project main-artifact file: [myJar].jar with assembly file: [myJar-GUI].jar
EDITED
After the solution the user Tunaki suggested, I used a different pluggin and maven works as I want it to do it. The code is as follows:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.4.2</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
<configuration>
<transformers>
<transformer
implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>gui.SparkISGUI</mainClass>
</transformer>
</transformers>
</configuration>
</plugin>
First, you need to understand why you are getting this warning.
The Maven convention is that one project should create a single main artifact. For a project of packaging jar, the main artifact is the result of the maven-jar-plugin. This plugin will package as a JAR the classes contained in your project only.
One project can eventually generate additional artifacts that will be distinguished from the main one by their classifier:
Beside the main artifact there can be additional files which are attached to the Maven project. Such attached filed can be recognized and accessed by their classifier.
The classifier is an identifier than will be appended to the main artifact name.
So what happens when you want to create an uber-jar? Somehow, your project needs to generate two jars. The main one will be a JAR containing the classes of your project and the second one will be the uber-jar resulting of maven-assembly-plugin. To distinguish this secondary additional artifact from the main one, the classifier jar-with-dependencies is added.
So when you remove the classifier, you effectively replace the main artifact with the uber-jar. maven-assembly-plugin will emit a warning in this case, and that's the warning you are having. You can ignore it completely: it just reminds you that you are replacing the main artifact of the project by an additional artifact.
Besides the maven-assembly-plugin, do note that you can also generate an uber-jar with the maven-shade-plugin:
This plugin provides the capability to package the artifact in an uber-jar, including its dependencies and to shade - i.e. rename - the packages of some of the dependencies.

How to set additional Class-Path entries in manifest with onejar Maven plugin?

Is there a way to add an arbitrary classpath entry to a JAR file manifest using onejar-maven-plugin?
I found the way to configure maven-jar-plugin to do this, but it appears that there is no such option for onejar-maven-plugin.
This is not done to find additional classes (otherwise why use the onejar plugin, right?), but rather to locate a configuration file that must be external to the JAR.
Is there a direct solution or a workaround for this?
Is the usage of the one-jar plugin really required?
You can achieve the same goal (packaging in one single jar your application AND all the required dependencies, including transitive ones, AND add configuration for Class-Path AND using a more stable/standard plugin) applying the following approach:
Configure the Class-Path entry in your application Jar using the Maven Jar Plugin and the approach you mentioned in the question
Use the Maven Assembly Plugin to package one single JAR including dependencies, as explained here, in another stackoverflow question/answer.
An example of one-jar executable file (without using the one-jar plugin) could be as following:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<!-- your further configuration here -->
</configuration>
</plugin>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<archive>
<manifest>
<mainClass>com.sample.MainApp</mainClass>
<!-- your further configuration here -->
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
If you need to further play with classpath and Maven, I would suggest to also check this question here on stackoverflow.
Adding arbitrary manifest entries is possible in 1.4.5:
<plugin>
<groupId>org.dstovall</groupId>
<artifactId>onejar-maven-plugin</artifactId>
<version>1.4.5</version>
<executions>
<execution>
<configuration>
<manifestEntries>
<Build-Status>Yes</Build-Status>
</manifestEntries>
</configuration>
<goals>
<goal>one-jar</goal>
</goals>
</execution>
</executions>
</plugin>
The onejar-maven-plugin project doesn't seem to be in active development anymore, so you might want to switch to other solutions (e.g. maven-assembly-plugin) eventually.
The plugin is not available on Maven Central. Someone else put up a version of it to Maven Central with a different group ID.
Additional libraries can be added to the classpath at the time of launch.
The property one-jar.class.path can be used
one-jar.class.path
Extra classpaths to be added to the execution environment. Use platform independent path separator '|'
Example: --one-jar.class.path="./lib/two.jar|/opt/lib/three.jar"
Source: http://one-jar.sourceforge.net/index.php?page=details

Maven build two copies: one with lib shaded in, one without

I have a maven project that uses the maven-shade plugin to bundle a common-code-library jar into several distributed software plugins I make.
These plugins are all for the same main application - so when someone uses more than one plugin, it becomes a problem because each plugin has a copy of the shaded lib and they're not always using the same version.
I'm not sure how to resolve this. Is there a way I can configure maven to make two builds - one with the library shaded in, and one without? For the one without, we'll provide only one copy of the library needed as a separate resource.
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.1</version>
<configuration>
<artifactSet>
<includes>
// our common lib
</includes>
</artifactSet>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
Just change the finalName configuration property of shade plugin. See here. It's just overwriting your original package. If you change the output name both packages will be left.
You can use something like
<configuration>
...
<finalName>${build.finalName}-nodep.jar</finalName>
</configuration>
You can alternatively change outputFile or outputDirectory
Also if you want to preserve original artifact name but use classifier set shadedArtifactAttached to true.
The solution to my issue is to relocate the classes I'm shading, so they won't load copies found in other jars:
http://maven.apache.org/plugins/maven-shade-plugin/examples/class-relocation.html

Using Different Properties Files for Runnable Jars, Maven Eclipse

I am new to Maven. I apologize if this is a silly question. I have a Maven Eclipse project with a pom file that creates a runnable jar using the shade plugin. My plan is to include one of several properties files in the build (please correct me if my terminology is incorrect. I really am green). I have multiple properties files located in src/main/resources.
I would like to find a way to include in the runnable jar only the properties file that applies. Specifically, I have two properties files (config1.properties, config2.properties) in my project and each build will only use one of these files depending on the desired functionality of the resulting jar. The properties file would be reassigned a generic name, specifically "defaultconfig.properties", so that it plays nicely with the code.
The resulting jar files (a different one for each different properties file) will run as separate cron jobs. I think I will be using different Jenkins projects to deploy the runnable jars to specific servers based on what task the properties file configures the project for (I think I got this part). The cron jobs will run on these servers.
my questions are:
1) where does the logic go that determines which properties file to include in the runnable jar?
for example, suppose I have config1.properties (that specifies to use var1 = blah and var2 = blip and var3 = boink) and config2.properties (which specifies to use var1 = duh var2 = dip and var3 = doink). Where do I tell Maven which of these two files to use for specific builds?
2) am I supposed to pass in a parameter that tells Maven which properties file to use? If so, who do I pass this parameter too? Is this something that can be configured in a Jenkins project? (even just some basic reading would help me here, as I am not sure if this would be a maven issue or a jenkins issue. I am green with both.)
Here is a the relevant portion of my pom.xml file:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.2</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<transformers>
<transformer
implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>com.foo.dashboard.bar.Runner</mainClass>
</transformer>
</transformers>
<finalName>FooBar</finalName>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
I have tried using IncludeResourceTransformer to rename the properties file and but was not sure how include the logic for switching properties files based on desired jar file functionality.
Thank you.
This is what I came up with. I would love to know other approaches or the best way to do this however. Being totally new to all of this.
Create separate executions in the same plugin. Note: They must be assigned different <id> values.
Each <execution> can be configured differently. To rename the resources that you are including use the <transfomer>implementation = implementation="org.apache.maven.plugins.shade.resource.IncludeResourceTransformer">.
To exclude resources that are not needed (in my case, other properties files) use <transformer> implementation = "org.apache.maven.plugins.shade.resource.DontIncludeResourceTransformer">. This is more nicety than necessity. Why bundle up unneeded files in your jar?
Make sure each <execution> has a different <finalName> so that the resulting jars don't overwrite each other.
Here is my pom file.
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.2</version>
<executions>
<execution>
<id>ID1</id>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<transformers>
<transformer
implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>com.foo.dashboard.bar.Runner</mainClass>
</transformer>
<transformer
implementation="org.apache.maven.plugins.shade.resource.IncludeResourceTransformer">
<resource>defaultconfig.properties</resource>
<file>src/main/resources/defaultconfig_1.properties</file>
</transformer>
<transformer
implementation="org.apache.maven.plugins.shade.resource.DontIncludeResourceTransformer">
<resource>defaultconfig_2.properties</resource>
</transformer>
</transformers>
<finalName>FooBar1</finalName>
</configuration>
</execution>
<execution>
<id>ID2</id>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<transformers>
<transformer
implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>com.foo.dashboard.bar.Runner</mainClass>
</transformer>
<transformer
implementation="org.apache.maven.plugins.shade.resource.IncludeResourceTransformer">
<resource>defaultconfig.properties</resource>
<file>src/main/resources/defaultconfig_2.properties</file>
</transformer>
<transformer
implementation="org.apache.maven.plugins.shade.resource.DontIncludeResourceTransformer">
<resource>defaultconfig_1.properties</resource>
</transformer>
</transformers>
<finalName>FooBar2</finalName>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
I know this is not the final answer since this set up yields multiple jar files and I was originally looking for a solution that would give me only the jar file associated with a specific properties file, not all of the jar files from all of the properties files.
So I'm still taking suggestions on how to improve this solution so that the build would only a yield a single jar.

Generating sources by running a project's java class in Maven

I'm converting a largish Ant build to Maven. As part of the Ant build, we have several steps which created Java classes by invoking one of the project's classes, simplified as:
javac SomeGenerator.java
java SomeGenerator generated # generate classes in generated/
javac generated/*.java
I've split each generator in its own Maven module, but I have the problem of not being able to run the generator since it's not yet compiled in the generate-sources phase.
I've tried something similar to
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.1.1</version>
<executions>
<execution>
<id>generate-model</id>
<goals>
<goal>java</goal>
</goals>
<phase>generate-sources</phase>
<configuration>
<mainClass>DTOGenerator</mainClass>
<arguments>
<argument>${model.generated.dir}</argument>
</arguments>
</configuration>
</execution>
</executions>
</plugin>
Which sadly does not work, for the reasons outlined above. Splitting the code generators into two projects each, one for compiling the generator and another for generating the DTOs seems overkill.
What alternatives are there?
Using Maven 2.2.1.
You can execute the maven-compile-plugin in the generate-sources phase. Just add another execution before the existing execution and configure it so that it just picks up the sources for the generator.
Or split the project in two: build the generator with a separate POM and include the generator library as a dependency to the POM that's generating the sources.
Personally I would split the project. Keeps the build files cleaner and easier to maintain.
I didn't want to have 2 different projects, so I tried to setup Maven for adding the generated compiled code to the final jar package.
This is the working solution I've used:
In process-classes phase (executed just after the compile phase):
exec-maven-plugin for executing a main class able to generate my source files in target/generated-sources/java folder (in my specific case I used the Roaster library for source code generation);
build-helper-maven-plugin for adding the generated sources in the correct location
In prepare-package phase:
maven-compiler-plugin, in order to detect the changes and recompile the module
maven-jar-plugin for producing the jar package
This is my pom.xml:
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.6.0</version>
<executions>
<execution>
<phase>process-classes</phase>
<goals>
<goal>java</goal>
</goals>
<configuration>
<mainClass>com.example.MyClassWriter</mainClass>
<arguments>
<argument>${project.basedir}</argument>
<argument>${project.build.directory}</argument>
</arguments>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>3.0.0</version>
<executions>
<execution>
<phase>process-classes</phase>
<goals>
<goal>add-source</goal>
</goals>
<configuration>
<sources>
<source>${project.build.directory}/generated-sources/java</source>
</sources>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.6.1</version>
<executions>
<execution>
<phase>prepare-package</phase>
<goals>
<goal>compile</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.0.2</version>
<executions>
<execution>
<phase>prepare-package</phase>
</execution>
</executions>
</plugin>
</plugins>
</build>
In order to do this in one project, there are 3 steps:
Compile generator code
We can do it in generate-sources phase, using maven-compiler-plugin. You can also exclude other source files.
Run generator to generate code
We can do it in process-sources phase, using exec-maven-plugin.
Compile project
Below is the key part of pom.xml
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
<executions>
<execution>
<id>compile-generator</id>
<phase>generate-sources</phase>
<goals>
<goal>compile</goal>
</goals>
<configuration>
<includes>
<include>source/file/of/generator/*.java</include>
</includes>
<excludes>
<exclude>other/source/files/*.java</exclude>
</excludes>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.6.0</version>
<executions>
<execution>
<id>generate-codes</id>
<goals>
<goal>java</goal>
</goals>
<phase>process-sources</phase>
<configuration>
<mainClass>your.main.class.of.generator</mainClass>
</configuration>
</execution>
</executions>
</plugin>
We faced the same problem. We wanted to respect Maven's behavior as closely as possible, to have no problems with plugins and so on... Fighting Maven is just too expensive!
We realized that the update frequency of the generated code was usually very different from the one of the code that we manually write, so separating the code had very good performance characteristics for the build. So we accepted to have our generated classes as a dependency of the manually written.
We adopted the following structure, that had just one little change from a regular maven config, a change in the source directory.
Parent project : Generations
We created a parent project for all our generations.
It has a JAR type if it contains code to be compiled, otherwise POM.
There we have our generating code, in /src.
It can compile in /target as usual.
It runs the generation, each generator producing code in a sub-directory of /target.
Note: if you want several generated results in the same jar, just put them in the same sub-directory.
Child jar projects : Generateds
It is a subdirectory of the Generations project.
It has a JAR type.
The source directory points to the sub-directory in the parent's target.
<sourceDirectory>../target/generated1</sourceDirectory>
It compiles normally in its own /target directory.
That structure allows us to :
have as little modification to the standard maven layout as possible, so every maven command and plugin keeps working nicely.
scale nicely if you have several generators,
scale nicely if you want to generate several jars (we had a case wsdl2java where one generator produced code that should be split into several jars ; each child generated project would have the same source directory, but would be configured with an <includes> to handle only some of the classes).
I posted a minimal working setup here https://github.com/baloise/inlinesourcecodegenerator
It uses build-helper compiler and exec plugins and has all code in the same project.

Categories