how to find the jar file containing a class definition? [closed]
We don’t allow questions seeking recommendatio开发者_StackOverflow中文版ns for books, tools, software libraries, and more. You can edit the question so it can be answered with facts and citations.
Closed 6 years ago.
Improve this questionIs there a tool, plugin, or script I can use to find a java class in a bunch of jar files?
Very often I inherit code that complains about a class that doesn't exist, and it is just because the jar file is not included in the classpath. But, in what jar file(s) is the class? I may not have the JAR (so I have to search online), or adding a JAR to the classpath could create a duplicated class definition problem.
I obviously would prefer an eclipse plugin, but I'm open to any piece of software that works with Windows.
I know... Windows is not my choice, but that's what I got to work with.
Thanks!
Luis
P.S. Thank you for your answers. After reviewing some responses, I became aware that I should have explained better my scenario. We had a library of downloaded or created JAR files, but sometimes the class would be online somewhere.
(This is an improvement over the script I had in previous versions of the answer as it produces much cleaner output at the price of some awk
special/ugly quoting.)
I've built a script (findinjars
) which does just that.
#!/usr/bin/env bash
if [[ ($# -ne 1) && ($# -ne 2) ]]
then
echo "usage is $0 <grep pattern to look for in 'jar tvf' output> [<top-of-dir-tree> or, if missing, current dir]"
else
THING_TO_LOOKFOR="$1"
DIR=${2:-.}
if [ ! -d $DIR ]; then
echo "directory [$DIR] does not exist";
exit 1;
fi
find "$DIR" -iname \*.jar | while read f ; do (jar tf $f | awk '{print "'"$f"'" " " $0}' | grep -i "$THING_TO_LOOKFOR") ; done
fi
you can then invoke it with:
$findinjars a.b.c.d.Class [directoryTreeRoot or, if missing, current dir]
or just
$findinjars partOfClassName [directoryTreeRoot or, if missing, current dir]
Dot characters in the fully qualified class name will be interpreted in the regexp sense of 'any character' but that's not a big deal since this is a heuristics utility (that's why it's case-insensitive too BTW). Usually I don't bother with the full class name and just type part of it.
In the same lines as BalusC's answer (I can't post comment yet nor link 2 urls, no reputation :( ), you can find a jar thanks to these 2 jar finder engines: - http://www.jarfinder.com/ - findjar
A simpler command. You don't have to use 'while-do', use '&&' to print file name if 'grep' finds the class.
find . -name '*.jar' -print0 | xargs -0 -I '{}' sh -c 'jar tf {} | grep Hello.class && echo {}'
I usually employ bash for that: grep -lr "ClassName" .
The trick is that names aren't encoded in any way. You can open jar file in text editor and you'll see them. (You can even include package name in search query.)
I suspect, there's some windows equivalent too.
I ran into the same problem countless times, so I wrote a little tool to find them.
A simple command line: findclass MyClass -classpath ...
It searches directories, jar, zip, war and ear files for your class. I wrote it a few years back and use it all the time. I thought others might find it useful too so I uploaded onto github.
It's freely available to download: https://github.com/eurozulu/Findclass/tree/master/dist
If you want to look at the source, it's in the same site: https://github.com/eurozulu/Findclass/tree/master
If you like it, just let me know to give me that warm comfy feeling :)
I use jarscan. It is an executable jar file that can recursively search an entire folder structure for jars that contain the class that you are looking for. It searches by class name, package name or regex.
Grepj is a command line utility to search for classes within jar files.
You can run the utility like grepj package.Class my1.jar my2.war my3.ear
Search scope is
- Classes in the jar file
- Classes within nested artifacts like jars within ear and war files
- WEB-INF/classes is also searched.
Multiple jar, ear, war files can be provided.
I have written a program for this: https://github.com/javalite/jar-explorer It will also decompile existing byte code to show you interfaces, methods, super classes, will show contents of other resources - text, images, html, etc.
use this:
public class Main {
private static final String SEARCH_PATH = "C:\\workspace\\RPLaunch";
private static String CLASS_FILE_TO_FIND =
"javax.ejb.SessionBean";
private static List<String> foundIn = new LinkedList<String>();
/**
* @param args the first argument is the path of the file to search in. The second may be the
* class file to find.
*/
public static void main(String[] args) {
File start;
new Scanner(args[0]);
if (args.length > 0) {
start = new File(args[0]);
if (args.length > 1) {
CLASS_FILE_TO_FIND = args[1];
}
} else {
start = new File(SEARCH_PATH);
}
if (!CLASS_FILE_TO_FIND.endsWith(".class")) {
CLASS_FILE_TO_FIND = CLASS_FILE_TO_FIND.replace('.', '/') + ".class";
}
search(start);
System.out.println("------RESULTS------");
for (String s : foundIn) {
System.out.println(s);
}
}
private static void search(File start) {
try {
final FileFilter filter = new FileFilter() {
public boolean accept(File pathname) {
return pathname.getName().endsWith(".jar") || pathname.isDirectory();
}
};
for (File f : start.listFiles(filter)) {
if (f.isDirectory()) {
search(f);
} else {
searchJar(f);
}
}
} catch (Exception e) {
System.err.println("Error at: " + start.getPath() + " " + e.getMessage());
}
}
private static void searchJar(File f) {
try {
System.out.println("Searching: " + f.getPath());
JarFile jar = new JarFile(f);
ZipEntry e = jar.getEntry(CLASS_FILE_TO_FIND);
if (e == null) {
e = jar.getJarEntry(CLASS_FILE_TO_FIND);
}
if (e != null) {
foundIn.add(f.getPath());
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
for x in $(find . -name '*.jar') do unzip -l $x | grep WCCResponseImpl done
The best and easiest way is to use the JAD Decompiler. And yes, its an ECLIPSE PLUGIN !
Download and save the plugin in any location on your machine.
The plugin contains the following files:
- A temp folder
- A jad.exe file
- A *net.sf.jadclipse_3.3.0.jar* JAR plugin
- A Readme
Perform the following steps:
- Copy the JAR plugin to the plugins folder of eclipse folder
- Open eclipse. Goto Window >> Preferences >> Java >> JADClipse >> Path to Decompiler.
- Give the path of jad.exe
- Restart Eclipse
Now select any class and press F3.
The .class file will automatically decompile and display the contents !
I recently created a tool to search class , packages and libraries. You can try it http://javasearch.buggybread.com/. Click on the framework and it will help you locate dependency information ( jar , pom).
Very often I inherit code that complains about a class that doesn't exist, and it is just because the jar file is not included in the classpath.
If it's not in the classpath, then you likely don't have the JAR file itself at all. Searching via Eclipse's builtin Ctrl+Shift+T
function won't help much. Usually you can make use of the package name to "guess" where you could get the JAR file from at the internet. E.g. a org.apache.commons.lang.XXX
class is available at http://commons.apache.org/lang.
For the unobvious ones, I myself use http://grepcode.com, the JAR source code search engine.
You could always add the Reference library to your project in Eclipse and then in Package Browser, just expand the packages in the JAR file until you find the class that you are looking for.
@Nikita Rybak: AstroGrep for Windows is our friend: http://astrogrep.sourceforge.net/
I tried some of those Unix commands, but they errored out for various reasons. Here's a Perl script I wrote. It's specifically designed to run on Cygwin using the Cygwin version of Perl.
#!/bin/perl
# This program searches recursively for a given class in .jar files contained in or below
# directories given as command-line arguments. See subroutine printUsageAndExit for details,
# or just run it with -h command-line argument.
#
# It is specfically designed to run on Windows via Cygwin, with Cygwin's version of Perl,
# though it could easily be modified to run elsewhere.
use strict;
use File::Find;
use Getopt::Std;
sub processCommandLineArguments (\$\@);
sub checkCommandLineArguments;
my $className;
my @startingDirectories;
&checkCommandLineArguments;
&processCommandLineArguments (\$className, \@startingDirectories );
my %options;
$options{wanted} = \&processFoundFile;
$options{no_chdir} = 1;
$options{follow} = 1; # So that $File::Find::fullname will be populated.
$options{follow_skip} = 2; # So it won't die if it encounters the same thing twice.
&find ( \%options, @startingDirectories ); # find comes from "use File::Find".
sub processFoundFile{
# This routine is called by File::Find.
#
# $File::Find::dir is the current directory name,
# $_ is the current filename within that directory
# $File::Find::name is the complete pathname to the file.
my $jarFileName = $_;
return unless /\.jar$/;
my $fullFileName = $File::Find::fullname; # set by File::Find only when $options{follow} == 1
# Windowize filename:
$fullFileName = qx{cygpath --windows $fullFileName 2>&1};
chomp $fullFileName;
$fullFileName = '"' . $fullFileName . '"';
my @results = qx{jar -tf $fullFileName 2>&1};
local $/ = "\r\n"; # So that this Unix-based Perl can read output from Windows based jar command.
for my $result ( @results )
{
chomp $result;
if ( $result =~ /\b(\w+)\.((java)|(class))$/ )
{
my $classNameFound = $1;
if ($classNameFound eq $className)
{
print $jarFileName, "\n";
return;
}
}
}
}
sub processCommandLineArguments (\$\@){
my $refClassName = shift;
my $refStartingDirectories = shift;
$$refClassName = '';
# parse @ARGV
while (@ARGV){
my $arg = shift @ARGV;
if ($arg =~ /\Q-c/){
$$refClassName = shift @ARGV;
}elsif ($arg =~ /\Q-directories/){
while ($ARGV[0] =~ m{^/(\w+/?)+\b}){
my $directory = shift @ARGV;
die "Can't find $directory $!" if ! -e $directory;
push @$refStartingDirectories, $directory;
}
}
}
die "Must give -c class_name argument $!" if $$refClassName eq "";
push @$refStartingDirectories, '.' if scalar (@$refStartingDirectories ) == 0;
}
sub checkCommandLineArguments
{
{
# getopts butchers @ARGV, so have to use it on a local version.
local @ARGV = @ARGV;
our $opt_h;
&getopts('hc'); # Have to specify all options given or getopts will die.
&printUsageAndExit if $opt_h;
}
my $className;
{
# getopts butchers @ARGV, so have to use it on a local version.
local @ARGV = @ARGV;
while (@ARGV){
my $arg = shift @ARGV;
if ($arg =~ /\Q-c/){
$className = shift @ARGV;
&printUsageAndExit if $className =~ /^\s*$/ ;
return;
}
}
}
&printUsageAndExit;
}
sub printUsageAndExit
{
print "Usage:\n\n";
print "$0 -c class_name_to_search_for [ -directories startingDirectory1 startingDirectory2 ...]\n\n";
print "Example:\n\n";
print "findJarContainingClass.pl -c ApplicationMaster -directories /home/lylez/Hadoop/hadoop-2.x/hadoop-2.2.0/share/hadoop/yarn/sources /home/lylez/Hadoop/hadoop-2.x/hadoop-2.2.0/share/hadoop/yarn\n\n";
exit;
}
Just wanted to mention here that thirdparties can be searched for some specific file name in jarfinder Although it doesn't directly answer the question, but it won't harm :)
Hope this helps
精彩评论