Yup, this is exactly what I meant!

The b.bar() in your gist, since it’s at the top level, is essentially an import-time operation.

Yup, this is exactly what I meant!

The b.bar() in your gist, since it’s at the top level, is essentially an import-time operation.

I would naively expect dependency injection in java to have no import-time operations, since it would be assigning some concrete class to fulfill some interface (i.e., deferring initialization until all such interfaces have their concrete equivalents determined *should* be possible, if the dependency injection is done using reflection instead of having the actual constructors request dependencies be fulfilled).

From your example, it doesn’t look like it’s done this way — it looks like you’re running some code to inject dependencies from the class that needs them, rather than having a static/class-level member that lists members, their abstract types, and an unbound variable of class Class for each, then having a separate dependency manager class handle injection before something is used (if necessary, called from the constructor of any class when those values aren’t filled in, filling them for the entire hierarchy).

I think, with clever use of partial deferral, the problem of cycles in runtime injection could probably be eliminated entirely (from a practical standpoint) just by ensuring that at no point does code that depends upon dependency injection run before the entire dependency hierarchy is fulfilled. (Of course, with a large existing codebase, converting all dependency injection to this form is tough — or even all dependency hierarchies beyond some problematic point! One might be motivated to make this change but not have the authority, as well.)