Software - JPostal

What Is It?

JPostal provides a Java API for validating city-state pairs against a U.S. postal code (also known as a Zip Code™), as well as up-to-date postal code data in a special format designed to enable fast lookup and low memory consumption. The aim of this project is to cultivate more sophisticated address validation within the Java community, and especially the Java EE community.

Visit releases to download the latest version.

Usage

Usage of the JPostal is straightforward, consisting of a configuration and initialization step followed by an arbitrary number of validations and data storage events, and, finally, a dispose step.

Configuration and Initialization

Configuration and initialization consists of the following steps:

  1. Creation and initialization of a PostalRetrievalStrategy with the index and data files for U.S. postal data. Currently, the only recommended strategy for production use is the ReadOnceStrategy because it minimizes validation time while keeping memory requirements low. In addition, it maintains thread-safety which is an important characteristic for server-based applications.
  2. Creation and initialization of a USPostalCodeService instance, passing in an initialized postal code retrieval strategy.
The block of code below illustrates this.
Creating and initializing JPostal
PostalRetrievalStrategy retrievalStrategy = null;
inMemoryStrategy = new ReadOnceStrategy();
inMemoryStrategy.initialize(indexFile, dataFile);

USPostalCodeService uspcs = new USPostalCodeService();
uspcs.initialize(retrievalStrategy);

Validation

Validation is a three step process and consists of the following:
  1. Validation of the state against the zip code using the method USPostalCodeService.isPostalCodeIn. If validation fails (i.e. returns false) on this step, there is no need to move forward to the next step.
  2. Match the city against the postal code using USPostalCodeService.match. Care must be given to specify MatchingOptions that meet the applications business requirements. For example, a non-interactive program may only allow matching against cities the US Postal Office recognizes as "actual" or "acceptable" for a given postal code, whereas an interactive program may also include recognized but "unacceptable" cities in the matching process in order to provide more feedback to end users in the event of a validation error.
  3. Loop through the list of closest matches and determine the application-specific next step. For example, an application may require an exact match on the city name in order to consider the address valid, while another application may give a one character leeway. A non-interactive application may simply record a validation error and move one while an interactive application might use the closest-match list to present a user with a list of possible corrections.

The block of code below illustrates proper validation. For many more examples, along with (light) commentary, look at SimpleTester.java, which is included in the distribution.

Proper Validation with JPostal
System.out.println("Match Los Angeles, CA against 90064 with default options.");
validState = uspcs.isPostalCodeIn(90064, "CA");
System.out.println("  USPostalCodeService.isPostalCodeIn(90064, \"CA\") = " + 
                      validState);
if (validState) {
	results = uspcs.match("Los Angeles", 90064);
	System.out.println("  Found " + results.size() + " results:");
	for (MatchResult result: results) {
		System.out.println("    " + result);
	}
	System.out.println("    ");
	System.out.println("  Preferred for 90064 is " + uspcs.getActualFor(90064));
}

Data Storage

JPostal should also be used to normalize mailing addresses before storage by calling USPostalCodeService.getActualFor in order to return the city officially recognized as "acceptable" by the USPS for a given postal code.

Disposal

Explicit disposal of both the USPostalCodeService and PostalRetrievalStrategy are required, in that order, whenever your program has finished using them. Note that these methods are not thread-safe in the following sense: if one thread is trying to do a lookup using a service instance while a second is disposing the same service instance, the results of the first thread are not guaranteed to be valid because the dispose call will not block until the lookup completes. This is not an issue for single threaded environments and is unlikely to be an issue for Java EE based applications because the lifecycle contracts of Java EE services (Message Driven Beans, Session Beans, and Servlets) generally preclude such scenarios from occurring, assuming that disposal of the USPostalCodeService coincides with disposal of the containing Java EE service.

The block of code below illustrates disposal:

Disposing a JPostal Service Instance
uspcs.dispose()
retrievalStrategy.dispose();

License

JPostal is available for free under the terms of the GNU General Public License. JPostal is also available under a commercial, single-server license for 100 USD. Please contact me for details.

Feedback

As always, I would like you feedback on this tool, so please feel free to send me an email with any comments for improvement or otherwise. User feedback is one metric that helps determine how much time I spend improving a product.