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
Decompile the jar (I have no experience with that but there should be command line tools).
Look for imports and parse them.
But I hope that someone else has done something like this before and give me advice on this.
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.
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.
Related
Is there a feature in netbeans that'll let me easily config and replace all occurrences of "system.out" and "e.printstacktrace" to "logger.info/error/log" ?
I used find/replace to get rid of all the "system.out"s, and now i need to get rid of all the "printstacktraces", I can probably write a parser and read all my java files. But before I do that I just want to know if something like this is already implemented in netbeans, currently in netbeans 7.1 hints, they only show you where these things are, but I couldn't find an option for code refactoring.
Thanks
The following will open each .java file that contains printStackTrace in vim.
Of course you can substitute vim with your text editor of choice:
alias javafind='find . -name '\''*.java'\'' -print | xargs fgrep -il'
vim `javafind printStackTrace`
The first command creates an alias that returns all java files (starting in the current directory) that contain the first argument.
The second command says: open each file that contains the term printStackTrace with vim.
An even better solution would be to use sed to intelligently search/replace with a regex.
I am trying to list the order in which the Java class loader is loading my classes. if I use -verbose parameter it will list every single interface/class it loads, including tons of interfaces such as Serializable, exceptions etc. Is there a way to tweak this output so it only shows which classes are loaded in the class my main method is defined?
I guess your best bet is to do the following:
Output some fixed text once your main method starts and right before it ends.
Pipe the verbose output into a file
Use things like less or grep to find the classes loaded between the two tags from the main method.
There's a similar question and some answers here: Is there a way to get which classes a ClassLoader has loaded?
Did you try -verbose:class?
Here's a sed expression that will parse the output of java -verbose:class to produce pairs of loaded class name and its jar file. You can further pipe through a sort to get unique jar files. For example,
java -verbose:class -version 2>/dev/null |
sed -ne 's/\[Loaded \(.\+\) from \(.\+\)\]/\2/p' |
sort -u
outputs
/usr/local/jdk1.7.0_67/jre/lib/rt.jar
Is there an equivalent of the UNIX 'which' command, i.e. for given resource(s), traverse all classpath components and tell me in which component(s) it is found? In particular when there are multiple occurrences on the classpath?
(Context: I just spent the best part of a day chasing a bug which boiled down to a very long classpath having a source directory with stale source preceding (and thus eclipsing) a compiled jar with compiled newer code.)
(Yes I know you can get this with 'java -verbose' but that produces tons of output.
Maybe 'java -verbose ... | grep SpecificResource' is the best way?)
See jwhich, I believe it does exactly what you are looking for. It is not difficult to roll your own but why do that when it is readily available?
I use a shell script for finding classes within a set of JARs. The relevant part is this:
find /my/jars -name \*.jar | while read jar; do
jar -tf "$jar" | fgrep --label="$jar" -l foo/bar/SomeClass.class
done
which lists all JARs in /my/jars containing a file foo/bar/SomeClass.class.
Edit
This one-liner from the comments also works:
grep -rail --include=\*.jar foo/bar/SomeClass.class /my/jars
Your best bet is to take your classpath and search each element for the class(es) in question.
In theory, classes are guaranteed to be loaded in classpath order. If your classpath has a wildcard element, however, it's no longer deterministic. So you'd need to check for those and just dump out the classpath elements that match the resource in question.
A short JRuby/Groovy script should do it if java -verbose doesn't give you all the info you need.
When I have to generate javadocs for a new, unfamiliar project, I find that I spend a long time trying to simply write the correct command, specifying all the packages, all the source trees, etc. It's time-consuming and error-prone: I'm probably missing some source.
So let's say I have a directory myproj, and underneath it there are a few packages (and various other resources and stuff), and under those package directories there are eventually some src/ directories, and then lots of my/awesome/java/project/package type structures.
Is there a single command that will always recurse over EVERYTHING and generate ALL javadocs in one output location? I don't care how long it takes. Something brain-dead like javadoc -d doc -sourcepath . -subpackages * would be great. Failing that, what's the easiest way to generate all javadocs, no matter what the directory structure is?
Use find to find all Java source files and then send them to javadoc:
find . -type f -name "*.java" | xargs javadoc -d outputdir
On Windows you can do it like this:
Generate file list:
dir /s /b *.java > file.lst
Generate javadoc:
javadoc -d outputdir #file.lst
I am joining a competition that requires me to put all my java classes in one single .java file. Does there exist a tool that does this for me (including changing the visibility of classes to be able to do this)?
Addition: thanks for trying to help me to read the site of the competition but I quote:
It is possible to make more than one
class for your program, but you will
have to put the source for all classes
in a single .java file (the compiler
will produce multiple .class files
anyway). When you do this, you should
not declare your classes public, or
the compiler will complain about it.
So, only 1 .java file is allowed (no jar) and in that file I can have multiple non-public classes besides my public main class (and not only static inner classes as suggested).
If you have access to Unix-y shell (for Windows, you can install e.g. Git for a decent Bash implementation, and it gives you a great VC tool):
cat *.java | sed 's/public class/class/g' >AllTehCodez.java
Doesn't have to be more complicated than that (unless you have a lot of strings containing the substring "public class", of course).
Edit: Doesn't work for package and imports. But...
(
egrep -h ^package *.java | head -1
egrep -h ^import *.java | sort -u
egrep -hv '^(import|package)' *.java | sed 's/public class/class/g'
) >AllTehCodez.java
This does of course assume all the classes are in the same package.
If we exclude various "bijou scripting haquettes" along the lines suggested above, I seriously doubt that any serious tool exists for doing this.
Why? Because this kind of nonsense goes against all known Java style rules and conventions!
The people behind that website need to be taught about archive file formats; e.g. TAR, ZIP, JAR.
EDIT
I take that back. They DO understand JAR files. Quoting from one of their documents:
Using your own executable Java jar with Caia
You can also use your own Java jar in
Caia competitions. We have written the
jarwrapper for that. The source of
jarwrapper.c is put in the
caia_install_/jarwrapper/
folder. In the Windows distro this is
put into the src/ folder.
Suppose the name of your class file is
JavaPlayer.class. The only thing you
will have to do is to rename the
executable in the bin/ folder from
jarwrapper to JavaPlayer. The
executable now will perform the
command: java -jar JavaPlayer. The jar
file should contain a manifest which
points to the class with the main
method.
In manager.txt you can use the program
name JavaPlayer which refers to the
executable that starts your Java jar
player.