34

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

TZubiri
  • 886
  • 11
  • 30
luiscolorado
  • 1,525
  • 2
  • 16
  • 23

17 Answers17

44

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

Marcus Junius Brutus
  • 26,087
  • 41
  • 189
  • 331
12

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

Fanny H.
  • 755
  • 1
  • 7
  • 18
11

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 {}'
Wenbing Li
  • 12,289
  • 1
  • 29
  • 41
6

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.

Nikita Rybak
  • 67,365
  • 22
  • 157
  • 181
  • Yeah, but the problem is that it's hard to tell if the file contains a definition or a use of the class. And, yes, there's a grep utility that can be downloaded. Thanks! – luiscolorado Aug 16 '10 at 21:56
  • @luiscolorado It's never given me false positive before. I don't know, probably most of content (including referenced classes) is encoded in some way. – Nikita Rybak Aug 16 '10 at 22:02
  • Mmmmmhh... Unfortunately I got a bunch of false positives. Or maybe it's because the class has the same name across multiple packages. In any case, I'll give it another shot. Thanks, Nikita! – luiscolorado Aug 16 '10 at 22:12
6

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 :)

Rob
  • 61
  • 1
  • 1
2

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.

Mike Pone
  • 18,705
  • 13
  • 53
  • 68
2

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.

rrevo
  • 1,647
  • 1
  • 16
  • 22
2

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.

ipolevoy
  • 5,432
  • 2
  • 31
  • 46
  • thanks!! great tool!!! – danilo Jan 29 '18 at 02:33
  • I'm using your tool but I'm having some errors: OpenJDK 64-Bit Server VM warning: INFO: os::commit_memory(0x00000000ebcff000, 196608, 0) failed; error='Cannot allocate memory' (errno=12) # # There is insufficient memory for the Java Runtime Environment to continue. # Native memory allocation (mmap) failed to map 196608 bytes for committing reserved memory. # An error report file with more information is saved as: # /host/tools/jar-explorer/target/hs_err_pid6786.log Is it not intended to be used with OpenJDK? Is there a recommended amount of memory to be assigned to this JAR? – jpruiz114 Aug 13 '19 at 17:19
  • not sure why. I just ran it on OpenJDK version 8, and it is working as expected. You can pull down the sources and build locally with your JDK. It has no dependencies, so building is easy – ipolevoy Aug 16 '19 at 00:54
1

for x in $(find . -name '*.jar') do unzip -l $x | grep WCCResponseImpl done

1

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:

  1. A temp folder
  2. A jad.exe file
  3. A *net.sf.jadclipse_3.3.0.jar* JAR plugin
  4. A Readme

Perform the following steps:

  1. Copy the JAR plugin to the plugins folder of eclipse folder
  2. Open eclipse. Goto Window >> Preferences >> Java >> JADClipse >> Path to Decompiler.
  3. Give the path of jad.exe
  4. Restart Eclipse

Now select any class and press F3.

The .class file will automatically decompile and display the contents !

Neal
  • 537
  • 2
  • 12
  • 23
1

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.

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • 1
    _If it's not in the classpath, then you likely don't have the JAR file itself at all_ Well, it often happened to me with jboss. Hundreds of internal libs and you often need few of them to compile your code. Thanks for the link, though, that's interesting. – Nikita Rybak Aug 16 '10 at 22:00
  • @Nikita: In that specific case, you'd rather like to update the target server of your dynamic web project to JBoss. – BalusC Aug 16 '10 at 22:17
  • Boo... still unavailable 8 years later! I think Maven Repo should offer this... it's got all the stuff... "all" it has to do is keep an up-to-date Lucene index on, yes, EVERY single class in all its .jars! – mike rodent Feb 25 '18 at 14:45
1

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();
        }
    }
}
ILMTitan
  • 10,751
  • 3
  • 30
  • 46
1

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

Vivek Vermani
  • 1,934
  • 18
  • 45
0

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;
}
Lyle Z
  • 1,269
  • 10
  • 7
0

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.

Arunabh Das
  • 13,212
  • 21
  • 86
  • 109
0

@Nikita Rybak: AstroGrep for Windows is our friend: http://astrogrep.sourceforge.net/

NinjaCat
  • 9,974
  • 9
  • 44
  • 64
  • I liked AstroGrep! I found it friendly compared with the command line version. However, it has the same problem that any grep (see my comment to Nikita Rybak). – luiscolorado Aug 16 '10 at 22:08
  • True... _but_ with AstroGrep you can set it to return +/- N number of lines. So it's certinaly not the best option, but it might work. – NinjaCat Aug 16 '10 at 22:11
-1

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

Mark Bramnik
  • 39,963
  • 4
  • 57
  • 97
  • This is essentially a one-link answer. Additionally, the link that it is was already provided, and is, in fact, the top-voted answer. You were ninjaed by *three years* – Ben Barden Jan 02 '14 at 21:40