1

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?

Mureinik
  • 297,002
  • 52
  • 306
  • 350
tryingToLearn
  • 10,691
  • 12
  • 80
  • 114
  • Are you using a case-insensitive file system (e.g., any filesystem on windows)? maven-shade-plugin shouldn't care about case – Mureinik Jul 05 '18 at 06:42
  • 1
    @Mureinik. You are right. I ran the same code on linux and there 2 separate folder are created - com and COM. Can you please suggest a solution for windows? – tryingToLearn Jul 05 '18 at 06:47
  • I don't think maven shade explicitly always downcases it, usually, it's the case of picking the first case variation it sees when processing the files – Ferrybig Jul 05 '18 at 06:55
  • @catchingUp The easiest would just be to use your linux machine to build :-) See my answer below - I've added a couple of options for windows too. – Mureinik Jul 05 '18 at 06:58
  • The first thing is having an install plugin call within your build is by definition a bad idea better use a repository manager and put your required jar's their. Furthermore having a uppercase package name is also a bad idea https://docs.oracle.com/javase/tutorial/java/package/namingpkgs.html which I recommend to fix cause it will cause always confusion...which in the end will solve your build problem for all platforms... – khmarbaise Jul 05 '18 at 07:48
  • @khmarbaise Actually existing behavior cannot be changed as that needs a big change cycle across multiple teams.I understand that it's a bad practice but only so much is in my control. Is there a way to have folder for both upper and lower cases included in windows? – tryingToLearn Jul 05 '18 at 07:54

3 Answers3

2

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.

Mureinik
  • 297,002
  • 52
  • 306
  • 350
  • A third option would be to run the shade plugin inside a docker container. Ideally the artifact would be created on a build server, where containers could be used for all builds. – Roald Bankras Jul 05 '18 at 07:04
1

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>
Ferrybig
  • 18,194
  • 6
  • 57
  • 79
  • The code that uses this shaded jar may , may not be built with maven. From what I understand from your answer is that there would be sort of a **softlink**. Some application that comes looking for COM will be redirected to com through above code? Is that correct? – tryingToLearn Jul 05 '18 at 07:25
  • When you use maven shade that way, maven shade will change the package names in the final jar file, making the `com` part lower case. This is recommended since package names are supposed to be lowercase according to the convention. If another 3th party depends on your "uber" jar, they are required to access the COM package with lowercase for both of your dependencies. – Ferrybig Jul 05 '18 at 07:32
  • Actually existing behavior cannot be changed as that needs a big change cycle across multiple teams.I understand that it's a bad practice but Is there a way to have folder for both upper and lower cases included in windows? – tryingToLearn Jul 05 '18 at 07:53
0

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.

tryingToLearn
  • 10,691
  • 12
  • 80
  • 114