1

I have a Database-JDBC-Connection class and a Setup class that loads the details of the username, password, database host etc and many other properties by reading a configuration file. The database class has a dependency on Setup class and hence I am using Guice DI for my tests

@Guice(module = DBModule.class)
public class MyTest {

    @Inject DatabaseConn dbconn
}

And the Database Connnection class which depends on my Setup class.

@Guice(module = Setup.class)
public class DatabaseConn {

    @Inject Setup setupInstance.
}

PS : The @Guice annotation is used from the testng framework. More details Guice-Dependency-Injection-via-TestNG

After the instance of Setup class is created, I need to load the configuration properties (Not using Names.bindProprties()), perform some prerequisites in terms of asserting that certain properties exist and also try to resolve their values from Environment variables, System properties etc. or any other source, based on our framework.

import com.google.inject.*
import org.apache.logging.log4j.LogManager
import org.apache.logging.log4j.Logger
import aaa.bbb.ccc.Setup

public class SetupModule implements Module {

    private static Logger logger = LogManager.getLogger(SetupModule);

    @Override
    void configure(Binder binder){}

    @Provides @Singleton
    Setup getSetupProperties(){
        System.out.println("DEBUG : Loading setup properties")
        logger.info("Loading setup properties")
        Setup s = new Setup();

        logger.info("Loads the properties from configuration file.");
        s.loadProperties();

        logger.info("Verifies certain mandatory properties");
        s.performPrerequisites();

        logger.info("Resolve values from env. and system if required.");
        s.resolveValues();

        System.out.println("DEBUG : Done")
        return s
    }
}

However, this Setup class uses Log4j logger and I want to log the additional processing that I am doing (loading, asserting, resolving) using the log4j logger.


I have implemented the log4j listener etc. as suggested here Guice-Custom-Injection but the instance of logger is created in phase 2 of Guice injection. i.e. if you look at the sample code, the getSetupProperties() is initialized in the Guice Phase 1 and thus the log4j logger instance is not instantiated by then.

To prove that - I added the sysout in the injectMembers method of member injector class

@Override
void injectMembers(T instance) {
    try {
        System.out.println("DEBUG : Setting instance of logger")
        field.set(instance, logger)
    } catch (IllegalAccessException e) {
        throw new RuntimeException(e)
    }
}

So when I run, I see the following on the Sys out

DEBUG : Loading setup properties
DEBUG : Done
DEBUG : Setting instance of logger

Hence, nothing from the getSetupProperties method gets logged to my log4j log file.


My Database-Connection class uses @Inject Setup setupProperties and the above works. But because of the lack of logging, I am not able to debug anything in case of issues.

Hence, I want some mechanism that would instantiate my log4j logger during Guice phase 1 itself.

The question is more generic as well - i.e. for the cases where there are chained dependencies and before the 2nd dependent consumes the 1st instance, there is certain additional processing to be done. How to make sure that we have our logger available for those processing methods ?

There are 3 phases defined by Guice. More details Guice-Wiki

Appreciate any inputs if anybody has a direct solution or perhaps a workaround for the same.

PS : I have tried to give a snapshot of the problem, given that I cannot disclose exact implementation due to org policies.

Thanks.

palkarrohan
  • 459
  • 1
  • 4
  • 16
  • Could you explain what you mean by "phase 1" and "phase 2"? Those terms aren't explicit and Guice doesn't have such terms in their doc. Also, is your logger properly configured? Because from the code you have shown, the statements should be printed out, Guice or no Guice! – Olivier Grégoire Aug 20 '19 at 07:52
  • @OlivierGrégoire - there are 3 phases - Static Building, Injection, Singleton Preloading - mentioned here [Wiki](https://github.com/google/guice/wiki/Bootstrap). You are right, the logging works right now with or without Guice for anything that is happening after Guice injection completes... but I want the logging to happen in those ```@Provides``` or ```configure``` methods as well which are Guice specific. Hope that clarifies. – palkarrohan Aug 20 '19 at 08:18
  • My bad, I searched but couldn't find those phase terms. What I meant is that Logger is static. So it should work no matter what, and not conditionally. Unless you have a manual configuration of SLF4J that happens somewhere in Guice. If that's the case, you should extract that manual configuration and move it before you create your Guice modules. Your comment here-above confirms that. – Olivier Grégoire Aug 20 '19 at 08:26
  • I don't have any manual configuration by default - I have a ```log4j2.json``` placed under my ```src/test/resources/log4j2.json``` and it works fine for all log writes, occurring after guice injection completes. . The above log listener (or manual configuration) is just an alternative attempt to make sure that log4j2 get instantiated before Guice kicks in, but that's not happening. – palkarrohan Aug 20 '19 at 08:34

0 Answers0