Consider the API you're creating here, especially regarding future extensions or implementations. You evidently have a number of stateful FirstDep instances around, because the SecondDep depends on the particular FirstDep, but a future SecondDep may not depend on that same FirstDep (or any FirstDep at all). The fact that createMyObject(first)
can be a shorthand to createMyObject(first, factory.createSecond(first))
is specific to your business case, and I don't think there's a shorthand in Guice to make that assumption.
That said, you have two options. One, you can create a very small helper:
// Encapsulate the createMyObject(first) shorthand.
class MyObjectHelper {
@Inject MyObjectFactory rawFactory;
MyObject createMyObject(FirstDep first) {
return rawFactory.createMyObject(first, rawFactory.createSecond(first));
}
}
Or, two, you can use @AssistedInject
to have Guice effectively overload the constructor:
class MyObject {
// Multiple @AssistedInject constructors, selected based on which parameters
// are marked with @Assisted.
@AssistedInject public MyObject(@Assisted FirstDep first,
SecondFactory secondFactory, ThirdDep third) {
this(first, secondFactory.createSecond(first), third);
}
@AssistedInject public MyObject(@Assisted FirstDep first,
@Assisted SecondDep second, ThirdDep third) { /**/ }
}
interface SecondFactory {
// Note that @Assisted annotations are not needed here. Every parameter in
// these interfaces is for assisted injection, by definition.
SecondDep createSecond(FirstDep first);
}
interface MyObjectFactory {
MyObject createMyObject(FirstDep first);
MyObject createMyObject(FirstDep first, SecondDep second);
}
Though it's slightly more verbose to create a separate factory per class, I think you'll find it to be helpful in keeping your classes/factories separate and easy-to-follow, and it neatly avoids a potential circular-reference that I can't remember offhand if Guice supports. I tend to expose my factories as nested interfaces:
class SecondDep {
interface Factory {
SecondDep create(FirstDep first);
}
@Inject public SecondDep(@Assisted FirstDep first) { /**/ }
}
...which then lets you find and update Second.Factory
exactly adjacent to the class it supports.