When an IContextFunction does not solve your problem – and the solution with e(fx)clipse 2.2.0


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:

  1. an IContextFunction calculates the value ONLY once per context (technically this is not true because if you reparent an IEclipseContext the value is recalculated)
  2. 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) {
    // ...
  }
}
Advertisement
This entry was posted in e(fx)clipse, e4. Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.