0

I have a bit tricky situation, where the main class(class A) injects a dependency(class B), and then inside one of the methods of class A it delegates calls to class B.

So far, this doesn't sound tricky at all, but here is the twist: as class B is injected into class A automatically, it doesn't get the required argument to construct itself properly. Let me show you what I'm talking about:

class A {

   @Inject // inject object B
   public A(B objectB) {
      this.objectB = objectB
   }

   // delegate call to object B, however param1 is required in class B constructor in order to be constructed correctly
   public void example_method(String param1) {
    this.objectB.someMethod();
   }
}


class B {
   private C objectC;
   // class B needs param1 in order to create object C, so param1 has to be passed at the creation time
   public B(String param1) {
        objectC = new C(param1);
   }

   public void someMethod() {
    objectC.someOtherMethod();
   }

  public void someMethod2() {
    objectC.someOtherMethod2();
   }

}

I hope you can see the issue here: because class B is injected into class A by Guice, it doesn't have access to the param1 which only gets passed to one of the class A methods. In a sense, class B is created prematurely without the required data.

Is there a way to construct the code so that the construction of class B is delayed after example_method() of class A has been called ? If that's not possible, how would you refactor this, having in mind that I need to construct class C directly in class B's constructor, as it's going to be called from many different methods inside class B.

Zed
  • 5,683
  • 11
  • 49
  • 81
  • Does this answer your question? [Guice: How to do late binding?](https://stackoverflow.com/questions/14833263/guice-how-to-do-late-binding) – aksappy Sep 08 '21 at 21:11
  • The issue with that is that I don't see how I can pass param to the provider. There's just method get() which doesn't accept anything, so I can't pass anything from class A to class B's provider, or am I mistaken ? @aksappy – Zed Sep 08 '21 at 21:41

1 Answers1

1

Use a factory.

Instead of injecting a B object to A object, inject to A a factory that creates B objects.

Example, without any JSR-330 semantics:

public class FactoryExample {

    static class A {
        BFactory bFactory;

        A(BFactory bFactory) {
            this.bFactory = bFactory;
        }

        public void example_method(String param1) {
            B b = bFactory.createB(param1);
            b.someMethod();
        }
    }

    static class BFactory {
        B createB(String param1) {
            return new B(param1);
        }
    }

    static class B {
        String param1;

        B(String param1) {
            this.param1 = param1;
        }

        void someMethod() {
            System.out.println("someMethod");
        }
    }
}

Creation of a B object might be more than a String parameter, and must be injected.

Solution: Guice - AssistedInject

Or better: StackOverflow: Guice - How to use AssistedInject

So you end end up with something like this:

public class FactoryExample {

    public static void main(String[] args) {
        Injector injector = Guice.createInjector(new AbstractModule() {
            @Override
            protected void configure() {
                bind(A.class);
                bind(X.class);
                install(new FactoryModuleBuilder().implement(B.class, B.class)
                        .build(BFactory.class));
            }
        });

        injector.getInstance(A.class).example_method("Michael Jackson is alive");
    }

    public static class A {
        BFactory bFactory;

        @Inject
        A(BFactory bFactory) {
            this.bFactory = bFactory;
        }

        public void example_method(String param1) {
            B b = bFactory.createB(param1);
            b.someMethod();
        }
    }

    public static interface BFactory {
        B createB(String parameter);
    }

    public static class X {

    }

    public static class B {
        String param1;
        X x;

        //X is injected by Guice
        //param1 is injected by the factory
        @Inject
        B(X x, @Assisted String param1) {
            this.x = x;
            this.param1 = param1;
        }

        void someMethod() {
            System.out.println("someMethod: " + param1);
        }
    }
}
George Z.
  • 6,643
  • 4
  • 27
  • 47