Finding Properties in JARs with Groovy

In previous blog posts I have looked at Searching JAR Files with Groovy to find entries (such as .class files) contained in the JAR and Viewing a JAR’s Manifest File with Groovy. In this post, I look at using Groovy to find a particular property in a properties file contained within a JAR. The script in this post searches JARs in a provided directory and its subdirectories for a properties file containing the specified property.

The following Groovy script leverages several advantages of Groovy to recursively search a specified directory and its subdirectories for JAR files containing properties files that contain the specified property. The script outputs matching JARs and their properties files entries that contain the specified property. The script also shows the value that each property is set to in each matched JAR/property file.

findPropertiesInJars.groovy

#!/usr/bin/env groovy

/**
 * findPropertiesInJars.groovy
 *
 * findPropertiesInJars.groovy -d <<root_directories>> -p <<properties_to_search_for>>
 *
 * Script that looks for provided properties (assumed to be in files with
 * .properties extension) in JAR files (assumed to have .jar extensions) in the
 * provided directory and all of its subdirectories.
 */

def cli = new CliBuilder(
   usage: 'findPropertiesInJars.groovy -d <root_directories> -p <property_names_to_search_for>',
   header: '\nAvailable options (use -h for help):\n',
   footer: '\nInformation provided via above options is used to generate printed string.\n')
import org.apache.commons.cli.Option
cli.with
{
   h(longOpt: 'help', 'Help', args: 0, required: false)
   d(longOpt: 'directories', 'Directories to be searched', args: Option.UNLIMITED_VALUES, valueSeparator: ',', required: true)
   p(longOpt: 'properties', 'Property names to search for in JARs', args: Option.UNLIMITED_VALUES, valueSeparator: ',', required: true)
}
def opt = cli.parse(args)
if (!opt) return
if (opt.h) cli.usage()

def directories = opt.ds
def propertiesToSearchFor = opt.ps

import java.util.zip.ZipFile
import java.util.zip.ZipException

def matches = new TreeMap<String, Set<String>>()
directories.each
{ directory ->
   def dir = new File(directory)
   propertiesToSearchFor.each
   { propertyToFind ->
      dir.eachFileRecurse
      { file->
         if (file.isFile() && file.name.endsWith('jar'))
         {
            try
            {
               zip = new ZipFile(file)
               entries = zip.entries()
               entries.each
               { entry->
                  def entryName = entry.name
                  if (entryName.contains('.properties'))
                  {
                     def fullEntryName = file.canonicalPath + '!/' + entryName
                     def properties = new Properties()
                     try
                     {
                        def url = new URL('jar:file:' + File.separator + fullEntryName)
                        def jarConnection = (JarURLConnection) url.openConnection()
                        properties.load(jarConnection.inputStream)
                     }
                     catch (Exception exception)
                     {
                        println 'Unable to load properties from ${fullEntryName} - ${exception}'
                     }
                     if (properties.get(propertyToFind) != null)
                     {
                        def pathPlusMatch = '${file.canonicalPath}\n\t\t${entryName}\n\t\t${propertyToFind}=${properties.get(propertyToFind)}'
                        if (matches.get(propertyToFind))
                        {
                           matches.get(propertyToFind).add(pathPlusMatch)
                        }
                        else
                        {
                           def containingJars = new TreeSet<String>()
                           containingJars.add(pathPlusMatch)
                           matches.put(propertyToFind, containingJars)
                        }
                     }
                  }
               }
            }
            catch (ZipException zipEx)
            {
               println 'Unable to open JAR file ${file.name}'
            }
         }
      }
   }
}

matches.each
{ propertyName, containingJarNames ->
   println '\nProperty '${propertyName}' Found:'
   containingJarNames.each
   { containingJarName ->
      println '\t${containingJarName}'
   }
}

When the above script is run against JARs, it lists JARs with properties files that have the named property and its assigned value. The screen snapshot shown next demonstrates running the script against the Apache Camel distribution on my machine to find all properties named ‘artifactId’ (Maven) in those numerous JAR files.

The above script takes advantage of several Groovy features. For example, Groovy’s ability to directly use Java APIs and libraries is evident throughout the script with use of classes such as ZipFile (for accessing JAR contents), Properties (for accessing contents of properties files), JarURLConnection (also for accessing properties files’ content), TreeSet (for easy sorting), and Apache Commons CLI (built into Groovy for command line support). Groovy’s closures and concise syntax lead to greater fluency and readability as well.

This script catches exceptions even though Groovy does not require any exception (whether checked or runtime) to be caught. The reason for this is that an uncaught exception would lead to the script terminating. By catching any encountered exception during opening each JAR file or loading from a property file, an exception in those cases will only prevent that particular JAR or property file from being loaded without stopping others from being processed.

This script makes a couple significant assumptions. The first assumption is that the JAR files to be searched have a .jar extension and that the contained properties files have .properties extensions. The script uses built-in CLI support’s nice feature of a single command-line flag allowing multiple directories and/or multiple property names to be searched for by separating the multiple values with commas.

There are times I want to know where a particular property is specified within my application and this script makes it easy to find where that particular property is specified in the JARs on the application’s classpath.
 

Reference: Finding Properties in JARs with Groovy from our JCG partner Dustin Marx at the Inspired by Actual Events blog.

Related Whitepaper:

Java Essential Training

Author David Gassner explores Java SE (Standard Edition), the language used to build mobile apps for Android devices, enterprise server applications, and more!

The course demonstrates how to install both Java and the Eclipse IDE and dives into the particulars of programming. The course also explains the fundamentals of Java, from creating simple variables, assigning values, and declaring methods to working with strings, arrays, and subclasses; reading and writing to text files; and implementing object oriented programming concepts. Exercise files are included with the course.

Get it Now!  

Leave a Reply


7 − seven =



Java Code Geeks and all content copyright © 2010-2014, Exelixis Media Ltd | Terms of Use
All trademarks and registered trademarks appearing on Java Code Geeks are the property of their respective owners.
Java is a trademark or registered trademark of Oracle Corporation in the United States and other countries.
Java Code Geeks is not connected to Oracle Corporation and is not sponsored by Oracle Corporation.

Sign up for our Newsletter

15,153 insiders are already enjoying weekly updates and complimentary whitepapers! Join them now to gain exclusive access to the latest news in the Java world, as well as insights about Android, Scala, Groovy and other related technologies.

As an extra bonus, by joining you will get our brand new e-books, published by Java Code Geeks and their JCG partners for your reading pleasure! Enter your info and stay on top of things,

  • Fresh trends
  • Cases and examples
  • Research and insights
  • Two complimentary e-books