【问题标题】:how to find the jar file containing a class definition? [closed]如何找到包含类定义的jar文件? [关闭]
【发布时间】:2011-03-30 16:28:14
【问题描述】:

是否有工具、插件或脚本可以用来在一堆 jar 文件中查找 java 类?

我经常继承抱怨不存在的类的代码,这只是因为 jar 文件未包含在类路径中。但是,类在什么 jar 文件中?我可能没有 JAR(所以我必须在线搜索),或者将 JAR 添加到类路径可能会产生重复的类定义问题。

我显然更喜欢 Eclipse 插件,但我愿意接受任何适用于 Windows 的软件。

我知道...Windows 不是我的选择,但这就是我必须使用的。

谢谢!

路易斯

附:谢谢您的回答。在查看了一些回复后,我意识到我应该更好地解释我的场景。我们有一个下载或创建的 JAR 文件库,但有时课程会在某个地方在线。

【问题讨论】:

  • 好问题。我一直遇到这个。不知道为什么它被关闭为题外话。奇怪
  • 这就是你的 stackoverflow。

标签: java windows search class jar


【解决方案1】:

我通常为此使用 bash:grep -lr "ClassName" . 诀窍是名称不会以任何方式编码。您可以在文本编辑器中打开 jar 文件,您会看到它们。 (您甚至可以在搜索查询中包含包名称。)

我怀疑,也有一些 Windows 等价物。

【讨论】:

  • 是的,但问题是很难判断文件是否包含类的定义或使用。而且,是的,有一个可以下载的 grep 实用程序。谢谢!
  • @luiscolorado 以前从来没有给我误报过。我不知道,可能大部分内容(包括引用的类)都以某种方式编码。
  • Mmmmmhh... 不幸的是我得到了一堆误报。或者可能是因为该类在多个包中具有相同的名称。无论如何,我会再试一次。谢谢,尼基塔!
【解决方案2】:

您总是可以在 Eclipse 中将参考库添加到您的项目中,然后在包浏览器中,只需展开 JAR 文件中的包,直到找到您要查找的类。

【讨论】:

  • 当然!虽然我在寻找更快的东西:) 我必须在这个项目中列出 20 个 jar 文件,谁知道有多少类。
  • 对于构建路径上的 jars,只需使用 Ctrl-Shift-T 来定位一个类。
  • 仍然不是我的那杯茶,但我们拭目以待。
【解决方案3】:

@Nikita Rybak:AstroGrep for Windows 是我们的朋友:http://astrogrep.sourceforge.net/

【讨论】:

  • 我喜欢 AstroGrep!与命令行版本相比,我发现它很友好。但是,它与任何 grep 都有相同的问题(请参阅我对 Nikita Rybak 的评论)。
  • True... 但是 使用 AstroGrep 您可以将其设置为返回 +/- N 行数。所以这当然不是最好的选择,但它可能会奏效。
【解决方案4】:

我经常继承抱怨一个不存在的类的代码,这只是因为 jar 文件未包含在类路径中。

如果它不在类路径中,那么您可能根本没有 JAR 文件本身。通过 Eclipse 的内置 Ctrl+Shift+T 函数搜索不会有太大帮助。通常你可以利用包名来“猜测”你可以从互联网上从哪里得到 JAR 文件。例如。 org.apache.commons.lang.XXX 课程可在 http://commons.apache.org/lang 获得。

对于不明显的,我自己使用http://grepcode.com,JAR 源代码搜索引擎。

【讨论】:

  • 如果它不在类路径中,那么您可能根本没有 JAR 文件本身 嗯,我经常遇到 jboss。数百个内部库,您通常只需要很少的库来编译您的代码。不过,感谢您的链接,这很有趣。
  • @Nikita:在这种特定情况下,您希望将动态 Web 项目的目标服务器更新为 JBoss。
  • 嘘...... 8 年后仍然无法使用!我认为 Maven Repo 应该提供这个......它拥有所有的东西......它所要做的“所有”就是保持一个最新的 Lucene 索引,是的,它的所有 .jar 中的每个类!跨度>
【解决方案5】:

使用这个:

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();
        }
    }
}

【讨论】:

    【解决方案6】:

    在与 BalusC 的答案相同的行中(我还不能发表评论,也不能链接 2 个 url,没有声誉 :(),由于这 2 个 jar finder 引擎,你可以找到一个 jar: - http://www.jarfinder.com/ - 查找罐

    【讨论】:

    【解决方案7】:

    我为此编写了一个程序:https://github.com/javalite/jar-explorer 它还会反编译现有的字节码以显示接口、方法、超类,将显示其他资源的内容 - 文本、图像、html 等。

    【讨论】:

    • 谢谢!!好工具!!!
    • 我正在使用你的工具,但我遇到了一些错误:OpenJDK 64-Bit Server VM warning: INFO: os::commit_memory(0x00000000ebcff000, 196608, 0) failed; error='Cannot allocate memory' (errno=12) # # 内存不足,Java 运行时环境无法继续。 # 本机内存分配 (mmap) 未能映射 196608 字节以提交保留内存。 # 包含更多信息的错误报告文件保存为: # /host/tools/jar-explorer/target/hs_err_pid6786.log 它不打算与 OpenJDK 一起使用吗?是否有建议分配给此 JAR 的内存量?
    • 不知道为什么。我刚刚在 OpenJDK 版本 8 上运行它,它按预期工作。您可以下载源代码并使用 JDK 在本地构建。它没有依赖关系,因此构建很容易
    【解决方案8】:

    我无数次遇到同样的问题,所以我写了一个小工具来找到它们。

    一个简单的命令行: findclass MyClass -classpath ...

    它会为您的班级搜索目录、jar、zip、war 和 ear 文件。 几年前我写了它并一直使用它。 我想其他人可能也会觉得它有用,所以我上传到了 github。

    它可以免费下载: https://github.com/eurozulu/Findclass/tree/master/dist

    如果您想查看源代码,它位于同一个站点中: https://github.com/eurozulu/Findclass/tree/master

    如果你喜欢它,请告诉我,给我那种温暖舒适的感觉 :)

    【讨论】:

    • 我发现你的工具很有用。谢谢!
    【解决方案9】:

    我使用jarscan。它是一个可执行的 jar 文件,可以递归地在整个文件夹结构中搜索包含您要查找的类的 jar。它按类名、包名或正则表达式搜索。

    【讨论】:

      【解决方案10】:

      (这是对我在以前版本的答案中的脚本的改进,因为它以一些 awk 特殊/丑陋的引用的价格产生了更清晰的输出。)

      我已经构建了一个脚本 (findinjars),它就是这样做的。

      #!/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
      

      然后你可以调用它:

      $findinjars a.b.c.d.Class [directoryTreeRoot or, if missing, current dir]
      

      或者只是

      $findinjars partOfClassName [directoryTreeRoot or, if missing, current dir]
      

      完全限定类名中的点字符将被解释为“任何字符”的正则表达式,但这没什么大不了的,因为这是一个启发式实用程序(这就是为什么它也不区分大小写 BTW)。通常我不关心完整的类名,只输入其中的一部分。

      【讨论】:

        【解决方案11】:

        Grepj 是一个命令行实用程序,用于在 jar 文件中搜索类。

        您可以像grepj package.Class my1.jar my2.war my3.ear一样运行该实用程序

        搜索范围是

        • jar 文件中的类
        • 嵌套工件中的类,例如 ear 和 war 文件中的 jars
        • WEB-INF/classes 也会被搜索。

        可以提供多个jar、ear、war文件。

        【讨论】:

          【解决方案12】:

          这里只想提一下,第三方可以在jarfinder中搜索一些特定的文件名 虽然它没有直接回答问题,但它不会伤害:)

          希望对你有帮助

          【讨论】:

          • 这本质上是一个链接的答案。此外,已经提供了它的链接,实际上是投票最多的答案。你忍了三年
          【解决方案13】:

          一个更简单的命令。您不必使用 'while-do',如果 'grep' 找到类,则使用 '&&' 打印文件名。

          find . -name '*.jar' -print0 |  xargs -0 -I '{}' sh -c 'jar tf {} | grep Hello.class &&  echo {}'
          

          【讨论】:

            【解决方案14】:

            for x in $(find .-name '*.jar') 做 解压-l $x | grep WCCResponseImpl 完成

            【讨论】:

              【解决方案15】:

              我尝试了其中一些 Unix 命令,但由于各种原因它们出错了。这是我编写的 Perl 脚本。它专门设计用于使用 Cygwin 版本的 Perl 在 Cygwin 上运行。

              #!/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;
              }
              

              【讨论】:

                【解决方案16】:

                最好和最简单的方法是使用 JAD 反编译器。是的,它是一个 ECLIPSE 插件

                Download 并将插件保存在您机器上的任何位置。

                插件包含以下文件:

                1. temp 文件夹
                2. 一个 jad.exe 文件
                3. *net.sf.jadclipse_3.3.0.jar* JAR 插件
                4. 自述文件

                执行以下步骤:

                1. 将JAR插件复制到eclipse文件夹的plugins文件夹中
                2. 打开日食。转到窗口 >> 首选项 >> Java >> JADClipse >> 反编译器路径。
                3. 给出jad.exe的路径
                4. 重启 Eclipse

                现在选择任意班级并按 F3。

                .class 文件会自动反编译并显示内容!

                【讨论】:

                  【解决方案17】:

                  我最近创建了一个搜索类、包和库的工具。你可以试试http://javasearch.buggybread.com/。点击框架,它会帮你定位依赖信息(jar,pom)。

                  【讨论】:

                  • 链接似乎已失效
                  • 现在可以使用了。
                  猜你喜欢
                  • 2020-06-29
                  • 2015-05-17
                  • 1970-01-01
                  • 2011-06-12
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多