RSS feed
<< Something to Park Out Behind Your Garage | Home | Two Fantastic Uses for AspectJ: Part One, Backward Compatibility >>

Now, Which Jar Did I Put That In?

Imagine this scenario: you've got a directory full of jar files, and your build is failing because it's missing some classes that are in one of them. You're not sure which; only that the missing classes are in here somewhere.

I've been running into this problem a lot lately, as I try to convert a series of old Ant builds over to Maven. At times, I've found that the jar name doesn't even come close to indicating whether it contains the key classes I need to make my build start working. To address this problem, I've started a short Ruby script that I'm tentatively calling jargrep.rb.

Before I show you this, please remember that I'm a little green when it comes to Ruby, so there may be some elegant one-liner that I'm missing here or there...and it may look decidedly Java-ish to the "native" Ruby programmer. Oh, and I'm not looking to win any architectural or OO-design awards here; I only needed a script to scratch a very persistent itch. Finally, this script is lacking a lot of polish when it comes to options I might want to include, etc. For this, I'd use OptionParser, but I couldn't be bothered to lookup the syntax, etc. today when I needed this script...

jargrep.rb

#!/usr/bin/ruby

if ( ARGV.length < 2 )
  STDOUT.puts "Searches jar archives for files within that match a particular pattern.\n"
  STDOUT.puts "Usage: #{$0} <pattern> -"
  STDOUT.puts "\tRead jar list from standard in, searching them for the specified pattern."
  STDOUT.puts "\t\t-OR-"
  STDOUT.puts "Usage: #{$0} <pattern> <file> [<file>]*"
  STDOUT.puts "\tSearch the jars in the file list for the specified pattern."
  STDOUT.puts "\n\nNOTES:"
  STDOUT.puts "\n\t1. Does NOT use egrep (yet)."
  STDOUT.puts "\n\t2. Currently, lists matches in the following format:"
  STDOUT.puts "\n\t\t<jar-file-name[0]>:\n"
  STDOUT.puts "\n\t\t<matching-path-within-jar[0]>"
  STDOUT.puts "\n\t\t<matching-path-within-jar[1]>"
  STDOUT.puts "\n\t\t<matching-path-within-jar[2]>"
  STDOUT.puts "\n\n\t\t<jar-file-name[1]>:\n"
  STDOUT.puts "\n\t\t<matching-path-within-jar[0]>"
  STDOUT.puts "\n\t\t..."
  exit 1
end

pattern = ARGV[0]

if ( ARGV[1] == '-' )

  files = STDIN.read
  files.each_line do |file|
  
    file.chomp!
    matches = `jar tvf #{file} | grep #{pattern}`.chomp
    
#    status = $?.exitstatus
#    STDOUT.puts "jar returned with status: #{status} for file: #{file}"
    
    if matches.index( 'java.util.zip.ZipException' ) == 0
      STDOUT.puts "\n\n!!!\nFailed to search jar: #{file}\nError:\n\n#{match}!!!\n\n"
    elsif ( !matches.empty? )
      STDOUT.puts "\n#{file}:\n\n#{matches}"
    end
    
  end
  
else

  ARGV.shift
  ARGV.each do |file|
  
    file.chomp!
    matches = `jar tvf #{file} | grep #{pattern}`.chomp
    
    if ( !matches.empty? )
      STDOUT.puts "\n#{file}:\n\n#{matches}"
    end
    
  end
  
end

Have you ever run into a situation like this? How did you solve it? Remember, each time I run across a problem like this, I fully expect to see it come up again, so I'm not looking for the ideal linux command line to execute one time then lose once it rolls out of my .bash_history file... Anyway, for what it's worth, enjoy.



Re: Now, Which Jar Did I Put That In?


I've done something similar with Java/Groovy: it is _very_ useful and I'm a kindred spirit in terms of solving a problem with a tool that can be used over and over again.

The grep-ish name is fine.  I call mine &quot;which&quot; in homage to the Unix command of the same name.

ps. I haven't looked at the Ruby code closely but it can be useful to have the program recursively descend subdirectories.

Re: Now, Which Jar Did I Put That In?

I went with the "ideal Linux command" approach, but wrapped in a script so that I didn't have to remember it (http://blog.uncommons.org/?p=20). That's on my path, so now I just run findclass.sh (works with Cygwin too).

Re: Now, Which Jar Did I Put That In?

windows: open search file dialog -> filename=*.jar, with text=MyClass. Some tweaking of XP might be in order, to avoid the Index Server from filtering your results.
linux: grep MyClass *.jar */*.jar */*/*.jar
linux: grep MyClass `find . -name '*.jar'`

There are more (more accurate) commands, but these are simple and do the trick most of the time.

Re: Now, Which Jar Did I Put That In?

We run into this often during ant->maven conversions and use an eclipse plugin: http://www.alphaworks.ibm.com/tech/jarclassfinder

Re: Now, Which Jar Did I Put That In?

I ran into this enough in Java that I wrote an app to help out. It's a gui that lets you search recursively or just within a directory, switch back and forth between dirs, search for other file types, etc. You can grab it free from the &quot;Documents and Files&quot; section of https://jarsearch.dev.java.net/ if interested.

It ain't exactly pretty since we keep adding features ad hoc, but it works.

Re: Now, Which Jar Did I Put That In?

If you're using cygwin or in Linux, you can also do this:

for n in *.jar; do grep -H &quot;package.name.Class&quot; $n; done

This will tell you which of the jars contain the classes.

Re: Now, Which Jar Did I Put That In?

Oops, just read the bottom of that: not looking for the linux command etc.  But it's easy enough to remember, that you can tap it out in seconds whenever you need it.

Add a comment Send a TrackBack