Saturday, August 31, 2013

NetBeans 7.4 Beta Hints Warn of Ineffective Exception Handling

There are numerous examples of how Java exception handling can be more difficult than it might first appear and Josh Bloch devoted an entire chapter of Effective Java (both editions) to exception handling. The checked exception model in Java remains "controversial." I was pleased to see that the NetBeans 7.4 beta I recently downloaded has some hints to help with at least a few nuances of Java exception handling.

I recently downloaded NetBeans 7.4 beta and installed this latest version of NetBeans on my laptop. I downloaded the "All" NetBeans IDE Download Bundle (includes GlassFish Server Open Source Edition 4.0 and Apache Tomcat 7.0.41 and Groovy support) and installed it on my machine.

Two of the new hints in the "probable bugs" category that are in the "current development version" of NetBeans are "'finally' block suppresses exceptions" and "'throw' inside 'finally' block." In this blog post, I will demonstrate these hints and briefly discuss why the hints help improve exception handling.

'finally' block suppresses exceptions

As documented in posts such as James Stauffer's Don't return in a finally clause and in forums such as Java try-finally return design question, it is generally accepted that having a method return from a finally block is a bad idea. An example of this poor Java coding practice is shown next.

Example of finally Block Suppressing Exception
private void throwException() throws Exception
{
   throw new Exception("A checked exception!");
}

/**
 * Demonstrate NetBeans hint "The 'return' statement in the 'finally' block
 * discards unhandled exceptions" by returning a value from the "finally"
 * block.
 * 
 * @return Integer value that is really meaningless in this case.
 * @throws RuntimeException This exception is always thrown.
 */
public int demonstrateReturnFromFinallyBlock()
{
   int value = 5;
   try
   {
      value = 7;
      throwException();
   }
   catch (Exception exception)
   {
      throw new RuntimeException(exception);
   }
   finally
   {
      return value;
   }
}

When the method demonstrateReturnFromFinallyBlock() in the above code snippet is executed, the output appears as follows:

Returned Value: 7

Although one might expect the demonstrateReturnFromFinallyBlock() method to throw a Runtime exception instead of returning an integer value of 7 (as the Javadoc for that method even advertises!), the "always thrown" exception is actually discarded because of the return statement in the finally block. This is a potentially nasty issue that might only be obvious at runtime rather than at compile time. Fortunately, NetBeans 7.4 beta includes a hint about this potential issue as demonstrated in the next screen snapshot:

The above screen snapshot demonstrates NetBeans 7.4 beta warns of the condition of a return statement in a finally block by underlining it in yellow. It also shows that when one hovers over that yellow-underlined piece of code, the NetBeans editor hints "The 'return' statement in the 'finally' block discards unhandled exceptions."

One can also find out about this same condition by passing -Xlint:finally to the javac compiler. This can obviously be done on the command line as I previously blogged about in javac's -Xlint Options, but the next screen snapshot shows the same thing being done in NetBeans through specification of -Xlint:finally via project.properties setting javac.compilerargs=-Xlint:finally.

'throw' inside 'finally' block

Throwing an exception from inside of a finally block is generally a bad idea because it will hide any exception thrown in that finally block's associated try block. The next code listing shows an example of this bad form.

/**
 * Demonstrate NetBeans hint warning that throwing an exception from a
 * 'finally' block is a bad idea because it hides the original exception.
 */
public void demonstrateThrowFromFinallyBlock()
{
   Integer twoDividedByZero = null;
   try
   {
      twoDividedByZero = 2 / 0;
   }
   finally
   {
      if (twoDividedByZero == null)
      {
         throw new RuntimeException("Cannot calculate quotient with division.");
      }
   }
}

One might think that executing the above method would result in an ArithmeticException being thrown and might be a bit surprised when a more general (and parent) RuntimeException is thrown instead.

The next screen snapshot shows NetBeans 7.4 beta warning of this condition.

Hovering over the yellow underlined code leads to display of the NetBeans warning "The 'throw' statement in 'finally' block may hide the original exception." The above screen snapshot shows this to be exactly what happened in this case: the ArithmeticException and its stack trace were hidden by the RuntimeException thrown from the finally block.

If I comment out the line throwing the exception from the finally block, the original exception is available again. This is demonstrated in the next screen snapshot.

Enabling even -Xlint:all (or simply -Xlint) will not warn of the bad form of throwing an exception from a finally block. In this particular example, the -Xlint:devzero (or -Xlint:all or -Xlint) would have shown that a divide by zero occurs in the code, but in general there is no -Xlint warning to have javac warn you when throwing from a finally block is hiding an original exception. This makes this particular NetBeans hint particularly useful.

Conclusion

There are many nuances and corner cases in Java exception handling. NetBeans 7.4 beta introduces two new "probable bugs" hints that warn of dangerous practices in exception-related finally blocks. The two cases are particularly insidious because they are not generally caught by the compiler (although one can optionally be caught as a warning), will not be found until runtime, and are not likely to be discovered easily from reading and reviewing the code.

Wednesday, August 28, 2013

Book Review: TestNG Beginner's Guide

I was happy to accept Packt Publishing's invitation to review the recently released (July 2013) book TestNG Beginner's Guide because I welcomed the opportunity to learn more about TestNG. I have read about and played a little bit with TestNG before, but the vast majority of my Java unit testing experience has been with JUnit.

Author Varun Menon opens TestNG Beginner's Guide with the following statement in the Preface, "Currently, TestNG is the most widely used testing framework in the software industry." This is definitely not what I've found in my experience where JUnit has been used far more than TestNG in the different Java projects that I've worked on. The Preface lists four things needed for getting most use out of TestNG Beginner's Guide: Java JDK, Eclipse, Linux or Windows, "basic knowledge of Java and testing."

Chapter 1: Getting Started

The first chapter of TestNG Beginner's Guide opens with a brief introduction to testing and automated testing. The chapter then introduces TestNG and provides a brief history and overview of the features of that open source unit testing framework. The chapter describes how to acquire TestNG via download (testng-6.8.jar in the book) and explains five ways it can be run: command line, Eclipse plugin, IntelliJ IDEA plugin, Ant, and Maven. The chapter spends multiple pages and several screen snapshots demonstrating configuration of TestNG within Eclipse via the plugin update site http://beust.com/eclipse. It demonstrates creating an Eclipse project, associating the TestNG library with the Eclipse project, writing a TestNG-based test class, and executing the TestNG test class in Eclipse. There are numerous screen snapshots in this Equinox-heavy portion of the chapter. Similar instructions on using TestNG with Eclipse can be found in the TestNG Eclipse documentation. The TestNG documentation includes a section on running TestNG from the command line.

Chapter 2: Understanding testng.xml

The second chapter of TestNG Beginner's Guide focuses on the testng.xml file, which it describes as "a configuration file for TestNG" that is "used to define test suites and tests in TestNG" and is "used to pass parameters to test methods." The chapter focuses on using testng.xml to specify test suites. It covers use of TestNG within Eclipse and from the command line. This chapter contains some of the concepts central to using TestNG. The examples shown are Eclipse-oriented, but XML snippets are shown as well, which is useful for those not using Eclipse. As testng.xml is a core part of TestNG, it is not surprising that Chapter 2 is a core part of TestNG Beginner's Guide.

Chapter 3: Annotations

The third chapter of TestNG Beginner's Guide, like the second chapter, focuses on a core part of TestNG. In this case, it's on TestNG's annotations. The chapter introduces Java annotations and standard Java annotations (@Override, @Deprecated, and @SuppressWarnings) before covering TestNG's specific annotations in a table with annotation name and brief description.

Chapter 3 of TestNG Beginner's Guide examines TestNG's annotations in more detail after the initial listing of them in the table with annotations names and descriptions. This more detailed examination includes code uses of these annotations. Annotations covered in this chapter include the @Test annotation (including specification of timeouts and expected exceptions), several of the wide variety of "before" and "after" TestNG annotations (such as @BeforeClass and @AfterMethod), @Optional, @Parameters, and @DataProvider. This, along with Chapter 2, is another "core" chapter of the book because annotations are core to TestNG. The third chapter also includes additional references to testng.xml.

Chapter 4: Groups

The fourth chapter of TestNG Beginner's Guide covers TestNG Groups. Coverage of test groups covers grouping of tests, running those groups of tests, specifying tests as parts of more than one group, using regular expressions to specify which groups to run, and grouping test groups within groups (metagroups). As with many of the other chapters, this chapter includes numerous screen snapshots showing Eclipse used with the different concepts, but code snippets are also included.

Chapter 5: Dependencies

TestNG Beginner's Guide's fifth chapter is on dependencies, a TestNG mechanism that allows tests to be executed in a particular order via expression of dependencies between tests and other tests or groups of tests. Screen snapshots of Eclipse and code listings are used to illustrate creating a dependency between one test on another, between one test on multiple other tests, between one test and a test in another class in the same inheritance hierarchy, and between a test and a group. The chapter also covers use of regular expressions with test dependencies and using XML to specify test dependencies.

Chapter 6: The Factory Annotation

The sixth chapter of TestNG Beginner's Guide introduces TestNG factories. The chapter explains the use of factories to "define and create tests dynamically at runtime." Through more screen snapshots of Eclipse and mode code listings, the chapter introduces the @Factory annotation and shows how it is used. This chapter also introduces the @DataProvider annotation and demonstrates using these two annotations together. The chapter also includes explanation of how @Factory and @DataProvider differ and when each is most appropriate.

Chapter 7: Parallelism

The seventh chapter of TestNG Beginner's Guide covers parallelism, or running tests with multiple threads. The chapter includes a brief section describing two reasons why being able to run tests in parallel can be advantageous.

Chapter 8: Using Build Tools

The eighth chapter of TestNG Beginner's Guide begins by outlining the "advantages of automating a build" and highlights Ant, Maven, and Gradle as the "major build tools that are being used by the software industry when it comes to Java or Java related languages." The rest of the chapter focuses on incorporating TestNG with Ant and with Maven using TestNG's custom Ant task and Maven plug-ins.

Chapter 9: Logging and Reports

Chapter 9 of TestNG Beginner's Guide introduces TestNG support for reporting and logging with an introductory paragraph on how reporting and logging are generally beneficial. The chapter introduces the interfaces ITestListener and IReporter and very briefly differentiates between these and where each is more appropriate. Like several other chapters, the ninth chapter mixes screen snapshots of Eclipse with code listings to demonstrate how to write a custom logger implementing the ITestListener interface, how to write a custom reporter implementing the IReporter interface, using TestNG-provided XML and HTML reports, and generating a JUnit HTML report with Ant. This chapter also introduces ReportNG, which is described on its website as "a simple HTML reporting plug-in for the TestNG unit-testing framework" that "is intended as a replacement for the default TestNG HTML report." This chapter also introduces Reporty-ng, formerly known as TestNG-XSLT.

Chapter 10: Creating a Test Suite through Code

The tenth chapter of TestNG Beginner's Guide covers "how to configure and run [a] test suite through code" to help "in configuring and running tests at runtime." In short, this chapter covers how to run TestNG tests programmatically rather than via specification in a testng.xml file. The chapter introduces and describes "the API classes" XmlSuite, XmlTest, XmlClass, XmlPackage, XmlDependencies, and a few more. The chapter adapts examples that were used earlier in the book to demonstrate using testng.xml for configuration but instead specify configuration in the code itself.

Chapter 11: Migrating from JUnit

The eleventh chapter of TestNG Beginner's Guide was one that I most looked forward to as I scanned the table of contents of the book. I find documentation on migration of one product (or version) to another product (or version) useful for two reasons. First, if I know the product or version being migrated from, I can better understand how the product or version being migrated to implements the same functionality. It helps me to learn the new product or version. Second, if I decide to adopt the new product or version, the migration guide is helpful in transitioning to that new product or version.

The section of the TestNG documentation called Migrating from JUnit states, "TestNG can automatically recognize and run JUnit tests, so you can use TestNG as a runner for all your existing tests and write new tests using TestNG." TestNG Beginner's Guide begins Chapter 11 with coverage of executing JUnit tests in TestNG. The chapter continues with a demonstration of running JUnit and TestNG tests together via testng.xml specification and then demonstrates "running JUnit tests along with TestNG [tests] through Ant."

Chapter 11 also covers true migration of JUnit-based unit tests to TestNG-based unit tests (as opposed to simply running JUnit-based tests in TestNG). This section includes an extremely handy table that compares the feature of TestNG to use compared to the feature of JUnit 3 and JUnit 4 to fulfill the same use case. This table is one of my favorite features of TestNG Beginner's Guide. The table validated my own internal mapping that I had been creating in my mind of TestNG concepts to JUnit concepts. The chapter also discusses how assert statements are handled differently in JUnit versus TestNG and this reminded me of why I prefer Hamcrest-based assertions with their high readability over straight JUnit assertions in which I must remember which of the two is an expected value and which is the actual value.

Chapter 12: Unit and Functional Testing

The final chapter of TestNG Beginner's Guide focuses on using TestNG for unit and functional testing. The chapter provides basic definitions of unit testing and functional testing before examining each approach in more detail via examples.

The unit testing section of Chapter 12 provides a table of assertions supported by TestNG and demonstrates use of an assertion in a code sample. That section also focuses on mocking with TestNG. Although this chapter specifically mentions jMock, Mockito, EasyMock, PowerMock, and JMockit as a "few of the mocking utilities," the chapter's focus is on jMock and Mockito.

After contrasting functional testing against unit testing, Chapter 12 includes a "list of functional testing automation tools that are available in the market" including Selenium, Sikuli, and SilkTest. Selenium is the product in the functional test coverage that gets the same focus that jMock and Mockito got in the unit test coverage.

The final paragraph of the Summary of Chapter 12 is also the summary paragraph for the entire book.

Overall Positives
  • For Beginners - As its title TestNG For Beginners correctly advertises, this book is aimed at beginners. I found my experience with JUnit to make it very easy to understand the concepts covered in this book, but I think most Java developers, even with less JUnit experience, would find this book highly approachable.
  • Screen snapshots and Images - TestNG Beginner's Guide features numerous screen snapshots that can be helpful in learning how to use TestNG, particularly in conjunction with the Eclipse plugin. The one downside is that many of the images are Eclipse-specific. This is a positive for Eclipse users, but may be a bit of a negative for users of other IDEs.
  • Code Listings - TestNG Beginner's Guide includes numerous code examples and listings. Because they are listed for nearly every covered topic, users of IDEs other than Eclipse should still be able to use this book.
Overall Negatives
  • Editing and Polish - One of the weaknesses of several (not all) of the Packt titles I have reviewed has been occasional convoluted sentence structure and weird grammar and incorrect spelling. This particular book has some strange grammar in a couple places as well as several spelling errors. Examples of spelling errors include @SupressWarnings (only one "p") and "TestNg" rather than "TestNG" on the same page 52. The good news is that these are mostly just minor distractions or annoyances and rarely take away from understanding of the meaning.
  • For Beginners - This is an advantage for new Java developers and developers new to unit testing, but is a bit of a disadvantage for more experienced developers (especially with JUnit). The book does a sound job of covering the most important features of TestNG, but there is very little coverage of why these features are useful. The simplicity and clarity of the examples comes at the price of the examples not providing very realistic ideas of how these TestNG features might be used in real code.
  • Eclipse-centric - The book provides enough code listings to largely overcome this limitation and this is not a limitation, of course, for Eclipse users.
Other Observations

The title says it all: TestNG Beginner's Guide is for those new to TestNG.

As already mentioned this book is targeted most closely at Eclipse users. That stated, I think developers with at least some Java experience will find it easy to pick up the concepts and even implement the code listings in their favorite IDE even when that IDE is not Eclipse. Complete code examples are typically provided and most of the many Eclipse screen snapshots are showing reported results which will be shown on the command line or in other IDEs.

The ordering of the chapters is not the same order I'd have chosen, but this is not a big deal. For the most part, one could read the chapters in the order one prefers or even skip chapters on subjects that are not of interest or which the reader is already familiar. The chapters rely slightly on each other, but for the most part could be read fairly independently of one another. There are references to earlier parts of the book in several chapters, but these references are often not necessary to understand the newly covered topic.

Most of the material covered in TestNG Beginner's Guide is covered online in TestNG documentation and in blog post. I have linked to specific sections or pages of these resources several times in my review of this book. Cédric Beust's blog is another obvious source of information on TestNG. The TestNG site includes the More TestNG Reading page with links to numerous additional online TestNG resources. Although there is little in TestNG Beginner's Guide that is not available online, this book provides organization for the introductory material and can provide context that is especially helpful when accessing seemingly unrelated blog postings.

TestNG Beginner's Guide is close to 250 pages of content plus more pages for table of contents, index, and so forth. Much of the space on these pages consists of code listings and screen snapshots, so the overall prose content is well below 250 pages. The examples are very simple, making it easy to focus on the TestNG feature being demonstrated, but also meaning that more subtle understanding of when certain features would be useful might be missed, especially by those not familiar with unit testing.

Conclusion

TestNG Beginner's Guide is squarely aimed at developers new to TestNG. Its twelve chapters cover the basics of TestNG and are approachable for anyone with some basic Java ability, but are especially easy to understand with some Java and JUnit experience. The book is probably too introductory for advanced TestNG users, but its title suggests that this is intentional. The only caveat I'd offer to a person new to TestNG who is trying to decide whether to obtain this book is to consider whether the book helps fill a need that is not covered adequately by the broad TestNG documentation or blog posts such as those by mkyong. I personally find some advantages to learning from books in conjunction with online resources, but I understand that this is a matter of taste.

Monday, August 26, 2013

Is Java Riskier than C/C++?

The following is a contributed article from Jon Jarboe of Coverity:


Is Java Riskier than C?
Jon Jarboe
Senior Technical Manager, Coverity

Lately, I’ve heard a number of folks discussing whether Java development is riskier than development in C/C++ (from here on out, I’ll just refer to "C"). They’re not rehashing the age-old discussion of which language is best, but are wondering whether teams developing in Java have unique risks compared to teams developing in C. They are particularly interested to learn how projects can better understand and manage risk.

For purposes of this post, I’ll ignore sources of risk that span languages—things like social engineering and configuration/training problems, which are presumably constant. What follows is based on my own experience - biases and all - with the understanding that this isn't a numbers discussion.

To my shame, I initially thought the answer was obvious: Java was designed to address many of the most important pitfalls of C, so it must be safer. Hackers have been exploiting C vulnerabilities like out of range memory accesses and null pointer dereferences for decades, circumventing controls and interrupting business-critical—and in some cases, mission- and life-critical—functions. (Activist hacker Barnaby Jack was planning to disclose lethal, exploitable vulnerabilities in implantable medical devices before his recent, untimely passing)

Java eliminates many of these vulnerabilities entirely, providing internal protections that automatically enforce buffer bounds and intercept and pass null and invalid memory references to the application for graceful handling. Whereas C programs need to navigate a maze of APIs like POSIX and Windows for threading and concurrency management capabilities, Java provides language primitives to enable developers to consistently manage concurrency.

While C memory management is notoriously tricky, Java provides a garbage collector to make resource management almost foolproof. While C applications are compiled to have direct hardware and OS access, Java programs are run in a virtual machine sandbox that tries to prevent them from interacting with the rest of the system. Surely that means that Java is less risky.

Of course, we regularly hear about data exposures and web site attacks—areas where Java is very commonly used. In fact, the vast majority of security vulnerabilities, such as injections, cross-site scripting, and authentication/session management, originate in faulty code—meaning that Java applications can’t be immune to these security problems. There are plenty of other types of risk that originate in the application code, impacting things like availability, data integrity and performance. When it comes down to it, this question is more complex than I initially realized.

After taking a step back, I realized that my initial reaction was focused on the risk inherent in the runtime environment. Java improves upon the weaknesses of C, especially in preventing application users from being able to gain control of the machine(s) upon which the application runs. But gaining control of the machine is rarely the goal—it is often just a means to gain access to, or interrupt the flow of, data. Considering the relevance of the application vulnerabilities that obviously still exist, those improvements are apparently just a step in the right direction.

To understand the implications, maybe I should consider the bigger picture. General purpose programming languages like Java and C are by definition designed to apply to a wide variety of programming tasks. They provide the toolbox that enables developers to implement their applications. It is the developer’s responsibility to craft a good logical model for the application, and to correctly implement that model using the available tools. From that perspective, the "riskier" language might be the one where developers have limited ability to effectively manage that risk.

Both C and Java have robust tools to manage application risk—from feature-rich IDEs to sophisticated analysis and debugging tools to testing frameworks and high-quality reusable components. I don’t think that either language is at a disadvantage for managing risk, so maybe the language isn't the source of risk. Maybe it's actually the applications or the developers.

I guess we have answered the original question: neither language is riskier than the other. But I don’t think we’re done yet; there is still the interesting question of managing risk. I don’t think it’s particularly important to characterize the source of the risk further. Suffice it to say, much of it originates in source code, with the nature of the application generally defining the major types of risk.

So where does that leave us as developers?

Above all, deeply understand your toolbox. What are the strengths and weaknesses of your languages/environments of choice? Do they insulate you from system-level concerns? Are there performance tradeoffs? For each project you undertake, understand the risks you’re facing with the application. Do you need to worry about concurrency, data security and/or resource constraints?

Java has a garbage collector that will free certain resources sometime after your program finishes using them but that doesn't mean that you should be lazy. Not all resources are handled automatically, and it can take a significant amount of time for resources to become available for reuse—impacting application availability and performance. By preparing for the worst case, you can minimize the chance it will happen. Actively manage as many resources as you can, to lessen the load on the garbage collector and reduce the chance of availability and performance problems.

Concurrency is tricky, even when you have the luxury of language primitives. If you want to get it right, you need to understand your application’s behavior on a deep level and you need to understand the intricacies of the concurrency tools you are using. Even sophisticated analysis and debugging tools have their limits—just because the code is valid doesn't mean that it’s correctly implementing your requirements.

Once you understand the risks, see whether you can find existing components and frameworks that have proven themselves in similar applications—it is often much harder to invent a better wheel than we anticipate. After understanding the risks of your application and the strengths and weaknesses of your tools, you can start to match up tool strengths to application needs and find the best way forward.

Ultimately, the question of which language is best – or riskiest – is just a distraction. To understand and manage risk, you need to ensure that your developers understand the intricacies of their tools, that you have a solid plan for attacking the challenges presented by your application, and that you have sufficient internal controls to recognize when you are off course.


The article above was contributed by Jon Jarboe of Coverity. I have published this contributed article because I think it brings up some interesting points of discussion. No payment or remuneration was received for publishing this article.

Tuesday, August 20, 2013

Ant Properties Nuances

Every once in a while, I'm reminded of a few subtle nuances of Ant properties that can, when forgotten, lead to confusion when dealing with Ant. In particular, the fact that Ant properties are generally immutable (not counting local properties as of Ant 1.8) and are set "permanently" upon their first setting can lead to slightly surprising results.

The properties section of the Ant Manual states, "Normally property values can not be changed, once a property is set, most tasks will not allow its value to be modified." The section of that manual on the Property task adds, "Properties are immutable: whoever sets a property first freezes it for the rest of the build; they are most definitely not variables."

The order of definition of properties influences their setting. In general, once a property is set, its value cannot be changed by a later attempt at redefinition in the same build file or in called build files. Furthermore, there are a set of properties that are already defined that generally cannot be redefined within an Ant build file. These include Java System properties and the built-in Ant properties.

Although definition of properties within an Ant build file cannot override the values of the default Ant built-in properties or the Java system properties, these values for these properties' names can generally be set with the -D option on the Ant launcher. However, a small number of these cannot be reset even with the -D option. For example, ant.file cannot be changed from the path and name of the Ant build file even when passed as a parameter via the -D option. Of course, it's probably just as well because there seems to be no good reason to pretend that the Ant build file is any other than what it really is.

To demonstrate the above "rules" of Ant property resolution, the following simple Ant build file can be used.

build.xml Displaying Properties in Ant
<project name="Project" default="showProperties" basedir=".">

   <property environment="env"/>
   
   <target name="showProperties">
      <!-- Java System Properties -->
      <echo message="java.home: ${java.home}" />
      <echo message="user.home: ${user.home}" />
      <!-- Custom Properties -->
      <echo message="name.last: ${name.last}" />
      <echo message="name.first: ${name.first}" />
      <!-- Ant Built-in Properties -->
      <echo message="ant.file: ${ant.file}" />
      <echo message="ant.version: ${ant.version}" />
      <echo message="ant.java.version: ${ant.java.version}" />
   </target>

</project>

There are a couple of Java system properties, a couple of custom properties, and a few Ant built-in properties in this example. These allow me to easily demonstrate how properties can be overridden or not overridden. The next screen snapshot shows the "default" settings of the properties without being overridden. The two custom ones are not defined at all, but the others (Java system and Ant built-in properties) have values automatically set for the Ant build.

The next screen snapshot shows an attempt to supply the values for the properties used in the build by passing them in via the -D parameters. As the example shows, even the system properties and Ant built-in properties can be overridden with the -D property setting, but the ant.file property is not overridden.

A common way to specify properties used in an Ant file are to specify them within the Ant build file using the Property task. The next code listing adds internally defined properties to the file shown above.

build.xml Defining Properties Internally
<project name="Project" default="showProperties" basedir=".">

   <property environment="env"/>
   <property name="user.home" value="/bin" />
   <property name="java.home" value="java" />
   <property name="name.last" value="Flintstone" />
   <property name="name.first" value="Fred" />
   <property name="ant.file" value="text.txt" />
   <property name="ant.version" value="1.8." />
   <property name="ant.java.version" value="6" />

   <target name="showProperties">
      <!-- Java System Properties -->
      <echo message="java.home: ${java.home}" />
      <echo message="user.home: ${user.home}" />
      <!-- Custom Properties -->
      <echo message="name.last: ${name.last}" />
      <echo message="name.first: ${name.first}" />
      <!-- Ant Built-in Properties -->
      <echo message="ant.file: ${ant.file}" />
      <echo message="ant.version: ${ant.version}" />
      <echo message="ant.java.version: ${ant.java.version}" />
   </target>

</project>

The next screen snapshot shows running this Ant file without any properties provided with the -D arguments. Note that the only properties which have been successfully set by the internal specification are the custom properties. The Java system properties and built-in Ant properties are unaffected by the attempts to internally set the properties.

There are advantages to Ant's properties generally being immutable. However, one must be cautious when assuming just because a property is declared in a particular Ant build file (or in a property file referenced by that build file), that it is actually the value to which that property is set for the build. If the property has already been set elsewhere, the local attempt at redefining the property has no effect other than to falsely advertise a value for that property which does not actually apply.

Wednesday, August 14, 2013

Searching JARs for String (Linux)

I recently thought about writing a Groovy script to search JARs for a specific string, but decided to first look for an alternative rather than writing a script. The alternative needed to be easy to use, freely available, and not bogged down with a load of dependencies. I was glad I looked first, because the Linux-based approach provided by "jan61" satisfied my need nicely. In this blog post, I look at that example more closely.

As documented on the LinuxQuestions.org thread searching contents of .class file within jar (for strings), a single line command in Linux nicely does the job of searching JARs recursively from a given directory for a given String. This search isn't searching for the names of the entries themselves in the JAR, but rather is searching the contents of each searchable file in the JAR. Here is that simple line (the token <stringWithOrWithoutSpacesToFind> represents the string to search for):

Linux Command to Search Contents of .jar Files for Specific String
find . -iname '*.jar' -printf "unzip -c %p | grep -q '<stringWithOrWithoutSpacesToFind>' && echo %p\n" | sh

I like to have this in script form (or as an alias) because that name is easier to remember than typing in that entire command each time. Here is an example script that could be used.

Linux Script Form of Above Command
printf "Searching JARs for string '${1}'...\n"
find . -iname '*.jar' -printf "unzip -c %p | grep -q '${1}' && echo %p\n" | sh

The two versions of the command shown immediately above will work as-is and the rest of this blog post focuses on how the command works. I start analyzing the command from the inside and move outward.

The Linux unzip command "list[s], test[s] and extract[s] compressed files in a ZIP archive." The -c passed to the unzip command "extract[s] files to stdout" and includes the name of the extracted files with that standard output. The %p is associated with the Linux find command. More specifically, %p is a directive to the -printf flag of the find command that directs it to include the found file's name.

Each found file is unzipped and its content directed to standard output where it is piped to a grep command to search for the provided text String. The provided -q parameter specifies "quiet" mode in which nothing is written to standard output and the grep exits immediately with zero status code upon detecting a match. The && symbols indicate that the echo command will be run to print out the file name with content matching the grep-ed for String if (and only when) the grep command returns a successful status (0).

All of the above are only executed against files with .jar extension thanks to the find . -iname '*.jar' command. The whole thing is piped to a shell.

Thanks to jan61 for the elegant Linux command covered in this post that makes it easy to search contents of files in JARs for a given string.