czyzby/gdx-lml

[Autumn] Dependency injection after ContextInitializer has done its part.

metaphore opened this issue · 6 comments

I have a case where I need to fill VerticalGroup with a complex items and I chose to go with individual controller instance per view item to encapsulate view logic and item model reference within. So this controller class has a lot of similarities with ViewController, like it has number of LML annotations and also should have injected dependencies to system-wide services/components.

I remember the discussion #40 and it gave me a good point to keep Context not disposed in case I will need to obtain any system component in a future. And so I can, by calling Context#getComponent(Class<?>), but I start thinking if there is a way to automate this process. I mean in that fancy elegant way like ContextInitializer#initiateComponents() does to resolve dependencies, but this time on demand for any specific instance with Autumn annotations like @Inject (maybe even for @OnEvent/@OnMessage, but this could lead to memleaks due to an each instance should be unsubscribed manually).

ContextInitializer is fully dedicated to only initialize Context and is not usable after. Feels like if there should be some injector service, then it better be outside of ContextInitializer and available system wide so anyone can utilize dependency injection later.

@czyzby what do you think, is it a good idea or even is it possible to add such utility functionality to the library core?

Well it is possible, no doubts. I just needed to copy most of the code from ContextInitializer to process annotations. Which in fact made me feel that if dep. injection on demand could exist, it's probably not the worst idea to merge it into ContextInitializer code somehow.

That's what providers are for. Annotate a class with @Provider or implement DependencyProvider directly. Initialize your objects using injected components and then call Context.provide to create a new instance. See provider examples.

Thanks for pointing me out, after reading those examples, it seems like I'm still missing some base Autumn architectural concepts. So I see that Provider is a good thing that I've been always ignoring.

Ok, so I should create Provider for my ItemViewController, and then call Context#provide(Class<T>) to obtain a new instance. But still I have to inject all the dependencies manually inside the DependencyProvider#provide(), right? Is there a simple way to obtain a new instance of Component on demand, so I just annotate ItemViewController's fields with Inject and they get resolved automatically?

No, I don't believe so. Now that I think about it, there should be a @Provided annotation for types, where it automatically registers a provider for you and uses constructor injection to create new objects.

Yeah, it could be a good solution. Feels like it will require some extra logic for Context or those automatically created Providers, because right now there is no code to inject fields except for ContextInitializer.

Should be very similar to converting current @Provider's methods to provider instances - you'd just invoke constructors instead of methods. See ReflectionDependencyProvider.