Main Content

Magnolia Community Forums: Get help with Magnolia: SimpleTranslator injection


  • kyriakos-schwarz
    kyriakos-schwarz
    Full name: Kyriakos Schwarz
    Posts: 8
    Last post: May 18, 2017 10:31:25 AM
    Registered on: Feb 1, 2016
    SimpleTranslator injection
    #1 by kyriakos-schwarz on May 18, 2017 10:31:25 AM

    I have some REST services (see code below) that all must use the same MyClass instance to do something, which includes an i18n translation. So, MyClass must have an instance of SimpleTranslator. My current solution makes it very hard to mock for testing and I want to write this code the magnolia way with @Inject (Documentation). From the code examples in the documentation I do not understand how I can implement this in my code.

    public MyRESTService1 {
    MyClass myClass = MyClass.getInstance();
    myClass.doSomething();
    }

    public MyRESTService2 {
    MyClass myClass = MyClass.getInstance();
    myClass.doSomething();
    }

    public MyRESTService3 {
    MyClass myClass = MyClass.getInstance();
    myClass.doSomething();
    }


    public class MyClass {

    private SimpleTranslator i18n; // How to inject this????
    // current solution that makes it hard to test (mock)
    // private SimpleTranslator i18n = Components.newInstance(SimpleTranslator.class, localeProvider);


    private static MyClass instance;

    public static MyClass getInstance() {
    if (instance == null)
    instance = new MyClass();

    return instance;
    }

    private MyClass() {
    ...
    }

    public doSomething() {
    i18n.translate(...);
    }
    }

  • creichenbach
    creichenbach
    Full name: Cedric Reichenbach
    Posts: 4
    Last post: May 19, 2017 11:13:09 AM
    Re: SimpleTranslator injection
    #2 by creichenbach on May 19, 2017 11:13:09 AM

    Hi Kyriakos,

    The most straight-forward way to combine dependency injection and unit testing (with mocks) is indeed constructor injection as in the docu page you linked. However, this only works if that object is created in a DI-aware way, that is, either injected itself or created with something like Components#newInstance. In this case, it's currently created manually with new, so injections don't work.

    In order to make your class DI-aware and still a singleton, you can annotate it with the @Singleton scope and make sure it's injected by classes using it instead of grabbed through #getInstance. But be aware that this will only work if classes using it are injected (or more precisely: DI-aware) themselves.


    public MyRESTService1 {
    // inject this somehow - ideally through constructor
    private final MyClass myClass;

    ...
    }

    public class MyClass {

    private final SimpleTranslator i18n;

    @Inject
    public MyClass(SimpleTranslator i18n) {
    this.i18n = i18n;
    }

    public doSomething() {
    i18n.translate(...);
    }
    }


    If for some reason injecting MyClass is not an option, you could work around it by manually provding a SimpleTranslator from unit tests. Either use Components#setComponentProvider with some binding for SimpleTranslator or, more directly, create a protected setter for i18n, which is visible within the same package, where your test class probably is. But those are somewhat hacky workarounds; proper constructor injection is most likely the high road.

    HTH,
    Cedric

You don't have the permission to post on this thread

Sign in

To login on this forum, you can use your Magnolia Forge, Support or Partner account, or, below, your Google, Yahoo! or OpenID account. If you have trouble logging in, or any other sort of issue, please let us know in the Meta forum, on the user-list, or simply by email at forum-admin at magnolia-cms dot com.

* Required

... or sign in with:

  • icon http://{your-openid-url}
  • icon
  • icon https://me.yahoo.com/