J Fabian Meier
J Fabian Meier

Reputation: 35843

Getting all imported classes for a jar

For a given jar, I want to find out all classes (as far as possible) that are used by this jar. Since I have a lot of jars, I want to automate this process. My best idea so far is to

  1. Decompile the jar (I have no experience with that but there should be command line tools).
  2. Look for imports and parse them.

But I hope that someone else has done something like this before and give me advice on this.

Upvotes: 1

Views: 2192

Answers (2)

Vlad
Vlad

Reputation: 18633

Using a specialised tool is probably the way to do this reliably.

However, one really janky way of doing this would be to grab a list of all the .class files in your JAR, put the JAR on the classpath and use javap to get references to other classes:

#!/usr/bin/env bash
javap -cp $1 -v \
   `zipinfo -1 $1 '*.class' | sed 's:/:.:g' | sed 's:\.class$::'` | \
   grep ' = Class' | sed 's:.*// ::' | sort | uniq

Running this on guava-19.0.jar gives this:

"[[B"
"[B"
"[[C"
"[C"
com/google/common/annotations/Beta
com/google/common/annotations/GwtCompatible
com/google/common/annotations/GwtIncompatible
com/google/common/annotations/VisibleForTesting
com/google/common/base/Absent
com/google/common/base/AbstractIterator
...............................................................
"[Lcom/google/common/util/concurrent/MoreExecutors$DirectExecutor;"
"[Lcom/google/common/util/concurrent/Service$State;"
"[Lcom/google/thirdparty/publicsuffix/PublicSuffixType;"
"[Ljava/io/File;"
"[[Ljava/lang/annotation/Annotation;"
"[Ljava/lang/annotation/Annotation;"
"[Ljava/lang/Class;"
"[Ljava/lang/Comparable;"
"[Ljava/lang/Enum;"
"[[Ljava/lang/Object;"
"[Ljava/lang/Object;"
"[Ljava/lang/reflect/Field;"
"[Ljava/lang/reflect/Method;"
"[Ljava/lang/reflect/Type;"
"[Ljava/lang/reflect/TypeVariable;"
"[Ljava/lang/StackTraceElement;"
"[Ljava/lang/String;"
"[Ljava/net/URL;"
"[Ljava/util/Iterator;"
"[Ljava/util/Map$Entry;"
"[[S"
"[S"
sun/misc/Unsafe
"[[Z"
"[Z"

You'll need more output formatting, and, as others have pointed out, it won't pick up any use of reflection.

How this works:

zipinfo -1 $1 '*.class' will print out the names of all .class files in $1, which is the argument to the script shown. The seds change /s to .s and remove the .class extension, so that you end up with a list of Java-style class names. You could do this more elegantly, but it should work.

The javap invocation puts the jar on the classpath with -cp, and passes all the classes. -v makes it output a lot of information, including some entries which represent references to names of classes. The grep ensures we're only looking at those, the sed removes some extra information we're not interested in. sort | uniq ensures we're not printing the name of any class more than once. It does need a bit more sedding to standardize an output format.

Upvotes: 6

Davide Lorenzo MARINO
Davide Lorenzo MARINO

Reputation: 26946

A simple way is to try to compile your code without adding that jar.

Try to compile and looking at the compiler errors is the fastest way to do that.

But remember that a class can be loaded also a runtime using reflection (for example via spring configuration files) and compiling the code without the jar will not inform you about potential errors at runtime.

Upvotes: 0

Related Questions