Skip to content

Question: (bad code smell) Is Injector as Singleton bad practice? #1636

Closed
@gallardo

Description

@gallardo

(I'm posting here as it seems that the google group https://groups.google.com/g/google-guice/c/sRzQInYrg6Y/m/Wm75m8R5BgAJ has no attention)

I'm trying to debug an issue (serenity-bdd/serenity-gradle-plugin#9) in a 3rd party framework that uses Guice. The problem has to do with the integration of the framework (serenity-bdd) in a gradle plugin, where some instance isn't recreated when needed.

Inspecting the code, I can summarize what I fell is a bad practice. The code has a Singleton more or less like this (see in the sources: https://github.com/serenity-bdd/serenity-core/blob/82cd173792d9f7898791cab0fe8d3a775bfb2825/serenity-model/src/main/java/net/thucydides/core/guice/Injectors.java):

public class Injectors {
    private static Injector injectors;
    public static synchronized getInjector() {
        if (injector == null) {
            injector = Guice.createInjector (new MyModule());
        }
         return injector;
    }
}

and then uses Injectors.getInjector() to get instances of classes everywhere through the code. For instance (see in the sources: https://github.com/serenity-bdd/serenity-core/blob/82cd173792d9f7898791cab0fe8d3a775bfb2825/serenity-core/src/main/java/net/serenitybdd/core/pages/PageUrls.java#L118-L124):

private static String namedUrlFrom(String annotatedBaseUrl) {
    String pageName = annotatedBaseUrl.substring(NAMED_URL_PREFIX.length());
    EnvironmentVariables environmentVariables = Injectors.getInjector().getInstance(EnvironmentVariables.class);
    return EnvironmentSpecificConfiguration.from(environmentVariables)
        .getOptionalProperty(pageName)
        .orElse(environmentVariables.getProperty(pageName));
}

There are also many places throughout the code where constructors uses the Injector to initialize its fields. For example (see in the sources: https://github.com/serenity-bdd/serenity-core/blob/82cd173792d9f7898791cab0fe8d3a775bfb2825/serenity-core/src/main/java/net/serenitybdd/core/annotations/locators/SmartAnnotations.java#L165-L167):

public SmartAnnotations(Field field, MobilePlatform platform) {
    this(field, platform, WebDriverInjectors.getInjector().getInstance(CustomFindByAnnotationProviderService.class));
}

I have no experience using Guice, and no experience with the framework, so I cannot say if it's very wrong or acceptable. But this (anti?)pattern is giving me hard times trying to debug. As it is now, many functions are quite compact, but I guess we are loosing many benefits of Guice, and I'm not sure if this is a legal use at all.

I have began to rewrite the code and prepare a Pull Request, but it's extremely costly and I'm not sure that I will do better than the current code. So the question for the experts: Is this so bad that it would require a complete rewrite of the relevant code? Am I missing something?

Best regards,

Alberto

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions