1

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.

J Fabian Meier
  • 33,516
  • 10
  • 64
  • 142

2 Answers2

4

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.

Vlad
  • 18,195
  • 4
  • 41
  • 71
0

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.

Davide Lorenzo MARINO
  • 26,420
  • 4
  • 39
  • 56
  • That is not what I want. I want to write a program that I give long list of jars (say, 100), and it returns for each of them the list of jars that are "used" (imported, etc., reflection might be ignored). – J Fabian Meier Mar 09 '16 at 13:46
  • The information that a jar use another jar is not listed in the jar itself. If you use a system that trace dependencies like maven you can do that. Otherwise not. – Davide Lorenzo MARINO Mar 09 '16 at 13:48
  • Not jars, but classes. If I e.g. open a jar in jd-gui (decompiler), I see the decompiled imports of the different source files. – J Fabian Meier Mar 09 '16 at 13:53
  • Yes but a class uses only another class.... not a jar. That class can be potentially be present in many jars. Because in the jar there is not reference to the jar needed to build it is not possible to have any sure information about that. – Davide Lorenzo MARINO Mar 09 '16 at 13:55
  • To make the point absolutely clear. I want to find out which CLASSES are referenced in a JAR. I am not interested in where these classes come from. I want something where I input "foo.jar" and it outputs a list like org.apache.SomeClass, org.apache.AnotherClass, ... This information must be somewhere in the jar (resp. the included class-files) because it is used by the class loader. – J Fabian Meier Mar 09 '16 at 13:59
  • I am sorry, in my first comment I wrote "jars" instead of "classes" which caused the confusion. – J Fabian Meier Mar 09 '16 at 14:25