0

I run into problems at Maven compile when using JMockit together with JUnit and Android:

[INFO] UNEXPECTED TOP-LEVEL EXCEPTION: [INFO] java.lang.IllegalArgumentException: already added: Ljunit/framework/TestResult$1;

At least JUnit and JMockit contain TestResult, so I thought about using the shade plugin to exclude these files:

    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-shade-plugin</artifactId>
        <version>2.0</version>
        <executions>
            <execution>
                <phase>package</phase>
                <goals>
                    <goal>shade</goal>
                </goals>
                <configuration>
                    <filters>
                        <filter>
                            <artifact>com.googlecode.jmockit:jmockit</artifact>
                            <excludes>
                                <exclude>junit/framework/**</exclude>
                            </excludes>
                        </filter>
                        <filter>
                            <artifact>junit:junit</artifact>
                            <excludes>
                                <exclude>junit/framework/**</exclude>
                            </excludes>
                        </filter>
                    </filters>
                    <minimizeJar>true</minimizeJar>
                </configuration>
            </execution>
        </executions>
    </plugin>

Unfortunately I still get these errors. Any ideas what's wrong here or did I misunderstand what this plugin is about? Or maybe you know a better solution to get rid of multiple package clashes with Maven?

UPDATE

(Meanwhile I unpacked and removed the conflicting dependencies manually from the jars and repacked all packages into an uber jar and installed it into the local repository. This works. But I still would be interested in a more professional solution)

Bevor
  • 8,396
  • 15
  • 77
  • 141

2 Answers2

1

As far as I know there is no good way to solve your issue. Normally in Maven you would exclude the problematic transitive dependency on Junit from the JMockit framework. However JMockit has the same problem some maven thirdparty jars have. They have included the Junit dependency in the JMockit jar instead of declaring a dependency in the pom of JMockit. See exclude dependencies how you could solve this with maven when JMockit would be packaged more maven friendly.

But there is no way to specify that you want to remove some classes from the JMockit dependency with the maven dependency mechanism.

So you already choose the correct way of creating a correct jar file and putting it in your repository. The only thing could be better would be to not do it manually. Create a new maven module creating this for you and use it as dependecy in your android project.

The new module would only depend on Junit and JMockit and no source code and would have the following shade plugin conf:

            <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-shade-plugin</artifactId>
            <version>2.0</version>
            <executions>
                <execution>
                    <phase>package</phase>
                    <goals>
                        <goal>shade</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>

Since this module would be jar module and not compiled with Android it did not have any problems of the duplicate class and the shade plugin will only package one TestResult class. If you want to ensure the correct one is packaged you can still use filtering to exclude the JMockit classes and rely on the JUnit once.

With an extra module you ensure the process is documented as pom file and you could easily switch to a newer JUnit or JMockit version. Also you would not rely on a file installed in your local repository which could be deleted by accident or is missing on an other pc.

mszalbach
  • 10,612
  • 1
  • 41
  • 53
  • I solved it by creating a new local package and installed it into the repository. Moreover, my first approach doesn't work because the compile phase is before package phase, I guess that's the reason why there was no result. Maybe it could help when I change the execution of shade plugin to compile phase. – Bevor May 21 '13 at 09:12
0

Not sure what you mean, that you are getting an error during maven compile?

Anyways, I believe that you should not at all package your JUnit dependencies to the "uber-jar", and you should only use them in maven test scope:

<dependency>
  <groupId>junit</groupId>
  <artifactId>junit</artifactId>
  <version>${junit.vesrion}</version>
  <scope>test</scope>
<dependency>
<dependency>
  <groupId>com.googlecode.jmockit</groupId>
  <artifactId>jmockit</artifactId>
  <version>${jmockit.vesrion}</version>
  <scope>test</scope>
<dependency>
Zilvinas
  • 5,518
  • 3
  • 26
  • 26
  • I cannot use them in test scope because this project (Android app) needs JUnit in compile scope. So JMockit needs to be in compile scope too. If they are in test scope, I don't have any problems and I'm able to compile then, but this doesn't work in Android Instrumentation testing. Meanwhile I figured out that JMockIt doesn't work with Android, but I still would like to know how to exclude package clashes in compile scope properly. – Bevor May 20 '13 at 10:28
  • 1
    please check this plugin: http://sonatype.github.io/jarjar-maven-plugin/ - it can help you to re-package jars as you like – Zilvinas May 29 '13 at 07:00