Create MessageDigest with Guice

Viewed 41

I'm trying to find a way to initialize MessageDigest with Guice. Currently I have this:

public class MyClass {

    MessageDigest md;
    
    public MyClass() {
        try {
            md = MessageDigest.getInstance("MD5");
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException(e);
        }
    }
....
}

I'm trying to see if it can written as:

@Inject
MessageDigest md;

But how do I make Guice call MessageDigest.getInstance("MD5") ?

2 Answers

Edit

I did not know MessageDigest is a single use class. You showed an injection of that class, which by definition cannot provide multiple instances. So the question is flawed.

You must fix the problem by binding a factory function that creates an MD rather than the MD itself. E.g. a Supplier:

final MessageDigestModule extends AbstractModule {
  @Provide
  Supplier<MessageDigest> provideMd5Digest() {
    return () -> MessageDigest.getInstance("MD5");
  }
}

Then when creating the injector, install new MessageDigestModule(). You will use @Inject Supplier<MessageDigest> md5DigestSupplier;. At the places where you need one, you'll say md5DigestSupplier.get().

If you'll need more than one kind of MessageDigest, then you should declare annotations and use them to separate the bindings.

@BindingAnnotation @Target({ FIELD, PARAMETER, METHOD }) @Retention(RUNTIME)
@interface Md5 {}
@BindingAnnotation @Target({ FIELD, PARAMETER, METHOD }) @Retention(RUNTIME)
@interface Sha256 {}

and then

final MessageDigestModule extends AbstractModule {
  @Provide
  @Md5
  Supplier<MessageDigest> provideMd5Digest() {
    return () -> MessageDigest.getInstance("MD5");
  }
  @Provide
  @Sha256
  Supplier<MessageDigest> provideMd5Digest() {
    return () -> MessageDigest.getInstance("SHA-256");
  }
}

And then finally:

@Inject
@Sha256
Supplier<MessageDigest> sha128DigestSupplier;

MessageDigest is a very special class. All its instances are one-use only. Therefore it must be injected very carefully.

First, you'll have to tell Guice to create multiple instances of the class. This is done as below in your Module class.

@Provides
MessageDigest provideMD5() throws NoSuchAlgorithmException {
  return MessageDigest.getInstance("MD5");
}

Then, once you have your provider that can create instances everytime, it's injected, you might not actually want only one instance per injected instance. So you will probably have to do the following:

@Inject
Provider<MessageDigest> md5Provider;

...

// Later in the class
MessageDigest md5 = md5Provider.get();
Related