The Dependency Conflict Cannot be Resolved

A project I work on is using both “com.google.sitebricks:sitebricks”, a now inactively under development web framework, and “org.drools:drools-compiler” as its dependencies, both of which then depend on “org.mvel:mvel2”. Maven used to find a version of mvel2 to satisfy both of the two dependencies.

However, when the “drools-compiler” dependency is upgraded to a newest version (“7.13.0.Final”), something unfortunate happens. The “drools-compiler:7.13.0.Final” uses a mvel2 version, which is incompatible with the one sitebricks uses. The “drools-compiler” uses some new APIs from the newer version of mvel2, unfortunately, that version of mvel2 deletes some APIs “sitebricks” uses. In this case, Maven cannot resolve the dependency conflict easily since there is NO version of mvel2 to satisfy “drools-compiler:7.13.0.Final” and “sitebricks:*”.

A Fix

Use Maven Shade Plugin to package sitebricks and its mvel2 dependency into a “shaded jar”, and also use this plugin to “relocate” mvel2 classes inside the “shaded jar”. “Relocation” here is to move mvel2 classes from package “org.mvel2” to some other package like “org.shaded.mvel2”, and to also modify bytecode of some sitebricks classes, which refers mvel2 classes, correspondingly, so that these “mvel2 classes” do not conflict with those used by “drools-compiler”.

Create a Maven project/module for the “shaded jar”.

<artifactId>sitebricks-shaded</artifactId>
<packaging>jar</packaging>
<build>
  <plugins>
    <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-shade-plugin</artifactId>
      <version>3.2.1</version>
      <executions>
        <execution>
          <phase>package</phase>
          <goals>
            <goal>shade</goal>
          </goals>
          <configuration>
            <finalName>sitebricks-shaded-${project.version}</finalName>
            <relocations>
              <relocation>
                <pattern>org.mvel2</pattern>
                <shadedPattern>org.shaded.mvel2</shadedPattern>
              </relocation>
            </relocations>
            <artifactSet>
              <includes>
                <include>org.mvel:mvel2</include>
                <include>com.google.sitebricks:*</include>
              </includes>
            </artifactSet>
          </configuration>
        </execution>
      </executions>
    </plugin>
  </plugins>
</build>
<dependencies>
  <dependency>
    <groupId>com.google.sitebricks</groupId>
    <artifactId>sitebricks</artifactId>
  </dependency>
</dependencies>

In the project, use the “sitebricks-shaded” as a dependency instead.

<dependency>
  <groupId>com.foo.bar</groupId>
  <artifactId>sitebricks-shaded</artifactId>
  <version>${project.version}</version>
</dependency>
<dependency>
  <groupId>org.drools</groupId>
  <artifactId>drools-compiler</artifactId>
  <version>${drools.version}</version>
</dependency>

And one more step. Look at the sitebricks-shaded-VERSION.pom in the ~/.m2, you will find the shaded jar only has one dependency, “org.projectlombok:lombok”. That means by simply replacing “sitebricks” with “sitebricks-shaded” in the project, it loses all the dependencies introduced and needed by the “sitebricks”.

Therefore create another Maven project (module) called “sitebricks-pom”,

  <artifactId>sitebricks-pom</artifactId>
  <packaging>pom</packaging>

In its pom.xml, simply copy all dependenciy of the “sitebricks” (which can be found in the file ~/.m2/PATH_TO/sitebricks-X.Y.Z.pom) but leave out those already included in the shaded jar.

Add “sitebricks-pom” as a dependency to the project.

That’s a fix to finally solve the problem.