Java: Type safe MessageDigest

The standard Java class MessageDigest can be used to return instances for various message digest algorithms. Implementing a simple factory helps you to return these instances in a type safe way without magic strings and preventing catch blocks with NoSuchAlgorithmException in your code.

Implementation

Our implementation will depend on an enum that contains all the different message digest algorithms and a factory that returns instances of MessageDigest.

Here’s the enum: it holds the different algorithms and the corresponding string identifier that’s passed to MessageDigest.getInstance().

public enum MessageDigestAlgorithm {
 
  MD2("MD2"), MD5("MD5"), SHA1("SHA-1"), SHA256("SHA-256"),
  SHA384("SHA-384"), SHA512("SHA-512");
 
  /** Algorithm name as defined in
     {@link MessageDigest#getInstance(String)} */
  private final String algorithm;
 
  private MessageDigestAlgorithm(final String algorithm) {
    this.algorithm = algorithm;
  }
 
  public String getAlgorithm() {
    return this.algorithm;
  }
}

The factory class is straight forward as well and just contains a method that returns instances of MessageDigest. The algorithms names hard coded in the above enum are passed to the getInstance method and the exception should never occur.

public class MessageDigestFactory {
 
  public static MessageDigest getMessageDigest(
    final MessageDigestAlgorithm algorithm) {
    // Validation
    if (algorithm == null)
      throw new IllegalArgumentException("Algorithm is 'null'.");
 
    try {
      return MessageDigest.getInstance(algorithm.getAlgorithm());
    } catch (final NoSuchAlgorithmException ignored) {
      // Should never happen
      return null;
    }
  }
 
  private MessageDigestFactory() {
    // can't be instantiated
  }
}

Testing

Finally here is a unit test that evaluates the different algorithms and makes sure that passing null to our above method results in an exception.

public class MessageDigestFactoryTest {
 
  @Test
  public void getMessageDigest() {
    Assert.assertEquals("MD2",
      MessageDigestFactory.getMessageDigest(
        MessageDigestAlgorithm.MD2).getAlgorithm());
    /* Test MD5, SHA-* as well... */
 
    try {
      MessageDigestFactory.getMessageDigest(null);
      Assert.fail("Should throw exception");
    } catch (final IllegalArgumentException ignored) {
    }
  }
}

Conclusion

Using an enum is an easy way to hard code expected magic strings and in combination with the factory returning instances of, e.g., MessageDigest in a type safe way without the need to check for a certain exception makes your code much cleaner.