If you haven’t read my last blog post where I described the problem of letting the DI container inject an instance of ModelElementFactory
directly you should do so before proceeding because it will help you understand the problem the following new concept introduced solves.
Our problem can be summerized as: To create an instance of ModelElementFactory
we need information from the IEclipseContext
(eg the EModelService
) and the component instance the value is created for.
We can satisfy the first requirement through an IContextFunction
who calculates its value on demand when first requested in the context but:
- an
IContextFunction
calculates the value ONLY once per context (technically this is not true because if you reparent an IEclipseContext the value is recalculated) - because of 1. it does not provide information for which component (object type) the value is created
We also can not use @Creatable
– which by the way was the worst idea ever in the history of Eclipse DI – because the type seen by the injector is only the interface (ModelElementFactory
) and not the concrete type.
So what can be done?
At first we need something that provides the information what real type we should create an instance for a given interface and guess what there’s a service API in org.eclipse.fx.core named TypeTypeProviderService
so if we want to teach the framework that it should create an instance of ModelElementFactoryImpl
if someone request ModelElementFactory
we’d register an OSGi-Service like this:
class ModelElementFactoryImpl implements ModelElementFactory { @Inject public ModelElementFactoryImpl(EModelService modelService, @Named(TypeTypeProviderService.DI_KEY) Class<?> ownerType) { // ... } } @Component class ModelElementFactoryTypeProvider implements TypeTypeProviderService<ModelElementFactory> { public boolean test(Class<?> clazz) { return clazz == ModelElementFactory.class; } public Class<? extends ModelElementFactory> getType(Class<?> clazz) { return ModelElementFactoryImpl.class; } }
and for the consumer we need a new annotation who informs the DI-Container to search a bit harder for the value to inject
class Component { @Inject public Component(@LocalInstance ModelElementFactory factory) { // ... } }