Bug 331746

Summary: Allow control over construction of contributions
Product: [Eclipse Project] Platform Reporter: Sven Efftinge <sven.efftinge>
Component: RuntimeAssignee: platform-runtime-inbox <platform-runtime-inbox>
Status: NEW --- QA Contact:
Severity: enhancement    
Priority: P3 CC: dany.eudes, felix, gunnar, john.arthorne, Lars.Vogel, ob1.eclipse, pwebster, remy.suen, sebastian.zarnekow, tom.schindl, wuppiwuppi
Version: 4.0Keywords: helpwanted
Target Milestone: ---   
Hardware: All   
OS: All   
See Also: https://bugs.eclipse.org/bugs/show_bug.cgi?id=500688
Whiteboard:
Bug Depends on:    
Bug Blocks: 331556    

Description Sven Efftinge CLA 2010-12-03 03:38:38 EST
With Equinox' extension registry a contribution is usually created by Equinox using the default constructor of the contributed class. This is often convenient, but generally the client is able to control how its objects are created and initialized by the means of an IExecutableExtensionFactory. This is important if you need to construct any contributed objects differently.

In e4 it seems that there is no such hook, and the EclipseContext is always responsible for creating and configuring the contributions. This is unpleasant because it is not possible to use a factory or any other construction pattern (e.g. dependency injection). 

Please provide something like an IExecutableExtensionFactory. 

In the style of e4 it could be an annotation like @Create which can specify arbitrary parameters which would be provided by e4.  

Example:

class MyFactory { 
  @Create
  MPart constructTheRealPart(Component parent, ModelService s) {
     ....
  }
}
Comment 1 Oleg Besedin CLA 2010-12-03 09:50:28 EST
Sorry, I don't understand this.

We are not changing how extension registry work. I'd like to do taht, but that is out of scope for the 4.1. Extension registry functionality remains unchanged between 3.x and 4.0/4.1.

If you are saying that it would be nice to customize objects created in DI, then I totally agree; moreover, we alcready provide this functionality.

In a simple example:

class MyPart { 
  @Inject
  public MyPart(Component parent, ModelService s) {
     ....
  }
} 

you can also add "@PostConstruct" method to "finalize" creation/injection process:

class MyPart { 
  @Inject
  public MyPart(Component parent, ModelService s) {
     ....
  }

  @PostConstruct
  public void init(@Optional ISelection initialSelection) {
     ....
  }
} 

you can have a factory classes by using IBinding:

InjectorFactory.getDefault().addBinding(MyPart.class).implementedBy(MyFactory.class)

or using ContextFunctions:

public class MyFactory extends ContextFunction {
 public Object compute(IEclipseContext context) {
  MPart result = ContextInjectionFactory.make(MyPart.class, context);
  doWhatever(result);
  return result;
}

Is there something missing?

(Note: factory functions are a bit more "advanced" topic and related APIs might change.)
Comment 2 Sven Efftinge CLA 2010-12-03 10:36:45 EST
E4 replaces a couple of extension points with the workbench model. E.g. action handlers are now contributed by the means of a workbench model snippet (or whatever you call it).

In Equinox the bundle where the contribution comes from can take care of the creation and initialization of objects. This is not possible in e4.

I suggest to allow to declare a factory instead of the actual type, such that e4 creates the factory and after that calls a certain method in order to obtain the real contributed object (e.g. action handler).

Some of the comments in Bug 331556 might help to understand my enhancement request.
Comment 3 John Arthorne CLA 2010-12-03 10:48:33 EST
I think the only thing missing is the magic line at the end, that checks if the constructed object is actually a factory, in which case it is replaced with the real part. This is the corresponding line in the extension registry:

// Deal with executable extension factories.
if (result instanceof IExecutableExtensionFactory)
	result = ((IExecutableExtensionFactory) result).create();

I don't think there is a corresponding place in e4 where the contributed object can be replaced. I imagine a simple change in somewhere like InjectorImpl#internalMake:

if (newInstance instanceof FactoryObject)
  newInstance = ((FactoryObject)newInstance).create();

I.e., we actually perform our injection into a factory object, which then creates the real object.
Comment 4 Paul Webster CLA 2012-01-04 08:09:02 EST
Can we look at this in M5?

PW
Comment 5 John Arthorne CLA 2012-04-24 11:11:02 EDT
Please review target milestone and bump to > 4.2 if appropriate.