jarjar

Jar Jar Links is a utility that makes it easy to repackage Java libraries and embed them into your own distribution.

735
94
Java

Jar Jar Links is a utility that makes it easy to repackage Java
libraries and embed them into your own distribution. This is useful
for two reasons:

You can easily ship a single jar file with no external dependencies.

You can avoid problems where your library depends on a specific
version of a library, which may conflict with the dependencies of
another library.

How does it work?

Jar Jar Links includes an Ant task that extends the built-in jar
task. The normal zipfileset element is used to embed jar files. A
new rule element is added which uses wildcards patterns to rename
the embedded class files. Bytecode transformation (via ASM) is used
to change references to the renamed classes, and special handling is
provided for moving resource files and transforming string literals.

Using with ant

In our imaginary project, the Ant “jar” target looks like:

<target name="jar" depends="compile">
    <jar jarfile="dist/example.jar">
        <fileset dir="build/main"/>
    </jar>
</target>

To use Jar Jar Links, we define a new task named “jarjar”, and
substitute it wherever we used the jar task. Because the JarJarTask
class extends the normal Ant Jar task, you can use jarjar without
any of its additional features, if you want:

<target name="jar" depends="compile">
    <taskdef name="jarjar" classname="com.tonicsystems.jarjar.JarJarTask"
        classpath="lib/jarjar.jar"/>
    <jarjar jarfile="dist/example.jar">
        <fileset dir="build/main"/>
    </jarjar>
</target>

Just like with the “jar” task, we can include the contents of another
jar file using the “zipfileset” element. But simply including another
projects classes is not good enough to avoid jar hell, since the class
names remain unchanged and can still conflict with other versions.

To rename the classes, JarJarTask adds a new “rule” element. The
rule takes a “pattern” attribute, which uses wildcards to match
against class names, and a “result” attribute, which describes how
to transform the matched names.

In this example we include classes from jaxen.jar and add a rule
that changes any class name starting with “org.jaxen” to start with
“org.example.jaxen” instead (in our imaginary world we control the
example.org domain):

<target name="jar" depends="compile">
    <taskdef name="jarjar" classname="com.tonicsystems.jarjar.JarJarTask"
        classpath="lib/jarjar.jar"/>
    <jarjar jarfile="dist/example.jar">
        <fileset dir="build/main"/>
        <zipfileset src="lib/jaxen.jar"/>
        <rule pattern="org.jaxen.**" result="org.example.@1"/>
    </jarjar>
</target>

The ** in the pattern means to match against any valid package
substring. To match against a single package component (by excluding
dots (.) from the match), a single * may be used instead.

The @1 in the result is a reference to the ** portion of the rule. For
every * or ** in the rule, a numbered reference is available for use
in the result. References are numbered from left to right, starting
with @1, then @2, and so on.

The special @0 reference refers to the entire class name.

Using with gradle

	dependencies {
		// Use jarjar.repackage in place of a dependency notation.
		compile jarjar.repackage {
			from 'com.google.guava:guava:18.0'

			classDelete "com.google.common.base.**"

			classRename "com.google.**" "org.private.google.@1"
		}
	}

See (jarjar-gradle/example/build.gradle) for some complete examples.

Using from the command line

From the command-line

java -jar jarjar.jar [help]

Prints this help message.

java -jar jarjar.jar strings <cp>

Dumps all string literals in classpath <cp>. Line numbers will be
included if the classes have debug information.

java -jar jarjar.jar find <level> <cp1> [<cp2>]

Prints dependencies on classpath <cp2> in classpath <cp1>. If <cp2>
is omitted, <cp1> is used for both arguments.

The level argument must be class or jar. The former prints dependencies
between individual classes, while the latter only prints jar->jar
dependencies. A “jar” in this context is actually any classpath
component, which can be a jar file, a zip file, or a parent directory
(see below).

java -jar jarjar.jar process <rulesFile> <inJar> <outJar>

Transform the <inJar> jar file, writing a new jar file to <outJar>. Any
existing file named by <outJar> will be deleted.

The transformation is defined by a set of rules in the file specified
by the rules argument (see below). Classpath format

The classpath argument is a colon or semi-colon delimited
set (depending on platform) of directories, jar files,
or zip files. See the following page for more details:
http://java.sun.com/j2se/1.5.0/docs/tooldocs/solaris/classpath.html

Mustang-style wildcards are also supported:
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6268383 Rules
file format

The rules file is a text file, one rule per line. Leading and trailing
whitespace is ignored. There are three types of rules:

rule <pattern> <result>
zap <pattern>
keep <pattern>

The standard rule (rule) is used to rename classes. All references to
the renamed classes will also be updated. If a class name is matched
by more than one rule, only the first one will apply.

<pattern> is a class name with optional wildcards. ** will match
against any valid class name substring. To match a single package
component (by excluding . from the match), a single * may be used
instead.

<result> is a class name which can optionally reference the substrings
matched by the wildcards. A numbered reference is available for every
* or ** in the <pattern>, starting from left to right: @1, @2, etc. A
special @0 reference contains the entire matched class name.

The zap rule causes any matched class to be removed from the resulting
jar file. All zap rules are processed before renaming rules.

The keep rule marks all matched classes as “roots”. If any keep rules
are defined all classes which are not reachable from the roots via
dependency analysis are discarded when writing the output jar. This
is the last step in the process, after renaming and zapping.