3

I'm writing a Java package to interact with a dynamo table, and I'm using Guice for DI. The package exposes a client to its users as follows -

// External client
public class Client {
    DataManager manager;

    public static Client getClient() {
        return Guice.createInjector(new MyModule()).getInstance(Client.class);
    }
}

// Manager class to interact with dynamo
public class DataManager {
    AmazonDynamoDb amazonDynamoDb;
    DynamoDbMapper dynamoDbMapper;

    @Time // IMPORTANT - This is AOP style metric recording which records the amount of time taken to do a particular operation
    public void addRecord();
    public void deleteRecord();
    ...
}

// Class that represents an entry in the table
public class Data {
}

One of the use cases is that a table check has to performed before the client instance is returned to the users of this package. Which basically means that I have to call an initializeTable() function somewhere in my code. My question is where should I put that logic?

  • In the constructor? Probably not because violates DI principles of doing only wiring in constructors, and makes testing difficult.
  • Inside a Guice module? I could create a @Provides function that initializes the client and before returning it, runs the init() function. But a limiting factor here is that I have AOP style annotations that won't work if the object instances are not created by Guice itself.

What I ended up doing was this (performing injection on a module itself which would be registered with Guice in the Client#getClient() method)-

public class InitializingModule extends AbstractModule {

/**
 * Perform injection on this instance so that the table initialization happens before any usable class is
 * returned to the clients of this package.
 */
@Override
protected void configure() {
    requestInjection(this);
}

/**
 * Configure dynamoDB to check for and initialize the table.
 *
 * @param startupUtil
 * @throws Exception
 */
@Inject
void configureDynamo(DynamoStartupUtil startupUtil) throws Exception {
    startupUtil.initialize();
}
}

So where is this initialization logic supposed to go so that the principles of DI are not violated and the classes are easily testable? Note that Guice does not support @PostConstruct yet.

  • [This](https://stackoverflow.com/questions/32635563/post-creation-initialization-of-guice-singleton) may help. The plugin seems to provide the `@PostConstruct` annotation for Guice too – BackSlash Jun 06 '17 at 22:36
  • Sorry I should have mentioned that such third party plugins have to undergo an approval procedure before I can use them (company policies), and I'm not looking to write my own processor for the `@PostConstruct` annotation. But the main question is that is @PostConstruct the right solution for this? Or is there a fundamental flaw in my API design? – Amanjot Singh Jun 06 '17 at 23:00
  • `@PostConstruct` is the way to go. It's the standard way, used by Spring and CDI alike. Only Guice doesn't support it directly. This doesn't change a bit: just use the simple `@PostConstruct` solutions spoken about by @BackSlash or use better ones like [Governator](https://github.com/Netflix/governator). And if it costs an "approval" procedure, make that pass it because in any way, they're doing it better than you could do it because I have not the faintest idea what happens in your code. – Olivier Grégoire Jun 06 '17 at 23:20
  • You can avoid the third party approval process completely by using Guice's builtin [InjectionListener](http://google.github.io/guice/api-docs/latest/javadoc/com/google/inject/spi/InjectionListener.html) via [Custom Injections](https://github.com/google/guice/wiki/CustomInjections). – Daniel Bickler Jun 07 '17 at 14:23
  • 1
    Possible duplicate of [Guice call init method after instantinating an object](https://stackoverflow.com/questions/2093344/guice-call-init-method-after-instantinating-an-object) – Daniel Bickler Jun 07 '17 at 14:25

0 Answers0