'which' command equivalent for finding resource(s) on Java classpath - java

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.

Related

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
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.

Write a batch file that starts a java program

So I have a java project with multiple java files.
I know that is almost straight forward to start a java application using batch file. But that is for a pretty simple java program with a single class.
However I am wondering if it is possible to do that with in a scale of a project that you usually create using eclipse. A large project with multiple packages, classes and multiple java files.
My try was to write a script and apply on the main class as following
set path = C:\Program Files\Java\jdk1.7.0_25\bin
javac -classpath twitter/twitter4j-stream-3.0.5.jar;twitter4j-core-3.0.5.jar" sourcepath="lib/twitter4j-core-4.0.1.jar;lib/twitter4j-core-4.0.1.jar;lib/twitter4j-stream-4.0.1.jar;svm_light_lib Program.java
java Program
However when I start the .bat file it automatically closes.
Any Ideas ?
Thanks in advance
First, never overwrite the environment variable path, not even
temporarily. Append your folder instead: set "path=%path%;%mypath%" or set "path=%mypath%;%path%".
(There exists a particular path command but I'm not sure about right syntax: path=%path%;%mypath% with = assignment or path %path%;%mypath% without it).
Use full path to a program if you know it, e.g. "%mypath%\javac".
For better readability, values for -classpath and -sourcepath options are stored to the environment variables mycpth and mysrcp, respectively. Note and use proper " quotation and no spacing around = to avoid any leading and trailing spaces in all set commands.
pause to see all the javac output. Displays the message Press any key to continue . . .
Next code should be (syntax) error-free. However, success depends (among others) on classpath and sourcepath entries visibility as well...
set "mypath=C:\Program Files\Java\jdk1.7.0_25\bin"
set "path=%path%;%mypath%"
set "mycpth=twitter/twitter4j-stream-3.0.5.jar;twitter4j-core-3.0.5.jar"
set "mysrcp=lib/twitter4j-core-4.0.1.jar;lib/twitter4j-core-4.0.1.jar;lib/twitter4j-stream-4.0.1.jar;svm_light_lib"
"%mypath%\javac" -classpath "%mycpth%" -sourcepath "%mysrcp%" Program.java
pause
java Program
However I am wondering if it is possible to do that with in a scale of a project that you usually create using eclipse. A large project with multiple packages, classes and multiple java files.
Of course it is possible!
In this case, I suspect the problem is that you java command doesn't have a "-cp" argument. The java command is probably failing because it can't find twitter classes ... at runtime.
Remember to include "." on the classpath ... or else java won't find the file that you just compiled.
#JB Nizet's suggestion is also very important advice for finding out what is actually happening.

Is there a way to replace all system.out/err and e.printstacktraces with logger in netbeans?

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.

Generic javadoc command that always generates all javadocs in a given tree?

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

Does there exist a tool for combining java files

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.

Categories

Resources