The injector attempts to resolve objects in the context. If they are not found in the context, but the class exists, then the injector will instantiate and return a new instance ''providing'' that its injectable dependencies can be resolved.

The injector attempts to resolve objects in the context. If they are not found in the context, but the class exists, then the injector will instantiate and return a new instance ''providing'' that its injectable dependencies can be resolved.

+

+

This behaviour can be a bit confusing, so let's walk through a somewhat subtle example that frequently causes confusion to new developers with E4 and DI. Consider an E4 RCP app with two MParts, <tt>OverviewPart</tt> and <tt>DetailPart</tt>. Since the <tt>OverviewPart</tt> provides an overview of the contents shown by <tt>DetailPart</tt>, it needs to get ahold of the <tt>DetailPart</tt>. A first attempt at writing <tt>OverviewPart</tt> and <tt>DetailPart</tt> might be:

+

<source lang="java">

+

public class OverviewPart {

+

@Inject private Composite detail;

+

@Inject private DetailPart detail;

+

+

@PostConstruct private void init() { /* ... */ }

+

}

+

+

public class DetailPart {

+

@Inject private Composite detail;

+

+

@PostConstruct private void init() { /* ... */ }

+

}

+

</source>

+

If you try to run with this code, it seems to work — but somehow the <tt>OverviewPart</tt> and <tt>DetailPart</tt> receive the same <tt>Composite</tt>! What's wrong?

+

+

There are several problems in the code above:

+

# Objects are resolved through the context ancestry, and never through the context tree. Since <tt>MPart</tt>s are siblings, an MPart will never be resolved through injection alone.

+

# Despite their names, neither <tt>OverviewPart</tt> nor <tt>DetailPart</tt> are actually <tt>MPart</tt>s. They are the <em>contributed objects</em> of an <tt>MPart</tt> that implement the behaviour. These contributed object are not available through the injection context.

+

# Even if contributed objects could be injected, there could be several instances in the model. Consider the Eclipse IDE with multiple windows with the <em>Outline</em> view in each.

+

+

So how did the code above seem to work? It works because of a subtle feature of the Dependency Injector called <em>instance autogeneration</em> (also supported by Guice). When trying to inject a field or method argument of type T, our DI tries to resolve an object of type T using the provided context. If an object of type T cannot be found, it examines the type T: if it is a concrete class, and either has a 0-argument constructor or a constructor marked with <tt>@Inject</tt>, it will <em>autogenerate</em> an instance using the provided context.

+

+

So the flow looks something like this.

+

# <tt>MPart(OverviewPart)</tt> is to be rendered. A new <tt>IEclipseContext</tt> is created hanging off of the <tt>MPart(OverviewPart)</tt>'s parent.

+

## DI is requested to create <tt>OverviewPart</tt>, using the <tt>IEclipseContext for <tt>MPart(OverviewPart)</tt>

+

## <tt>OverviewPart</tt>'s constructor was called.

+

## The <tt>OverviewPart</tt> instance's fields were examined for injection

+

### DI found the field for <tt>DetailPart</tt>. It tried to resolve that type in the <tt>MPart(OverviewPart)</tt>'s context, but nothing was found.

+

#### DI then looked to see if <tt>DetailPart</tt> was concrete and either had a 0-argument constructor or an <tt>@Inject</tt>able constructor; it found a 0-argument constructor. DI then created an instance of <tt>DetailPart</tt> and ''began injecting this new <tt>DetailPart</tt> using <tt>MPart(OverviewPart)</tt>'s context''. Note that DI did not create a new context for this object!

+

#### DI looked to see if this new <tt>DetailPart</tt> object had any injectable fields.

+

##### DI found a field of type <tt>Composite</tt>. DI checked in <tt>MPart(OverviewPart)</tt>'s context for <tt>Composite</tt> — and found an instance. But this instance was the <tt>Composite</tt> for <tt>OverviewPart</tt>. The field was injected.

+

#### DI then looked for methods of the new object to be injected.

+

## DI looked for any methods in <tt>OverviewPart</tt> to be injected.

+

# The <tt>OverviewPart</tt> object is returned.

+

+

(The correct solution is to use the <tt>EModelService</tt> to find the detail part.)

=== Why is my widget/part not displaying? Why am I getting a new Shell? ===

=== Why is my widget/part not displaying? Why am I getting a new Shell? ===

Dependency Injection & Contexts

What services are available for injection?

How can I override a provided object?

FIXME For example, to provide an alternative StatusReporter or Logger

How do I provide singleton objects?

Typical E4AP applications have a single injector, accessible through org.eclipse.e4.core.di.InjectorFactory#getDefault(). Within this injector, any class or interface annotated with the javax.inject.Singleton will be treated as a singleton instance.

Another approach is to use a IContextFunction that checks and sets a value in the top context.

FIXME: Can the injector also be configured to bind @Singleton to a particular class?

Why am I getting a new instance of an object?

The injector attempts to resolve objects in the context. If they are not found in the context, but the class exists, then the injector will instantiate and return a new instance providing that its injectable dependencies can be resolved.

This behaviour can be a bit confusing, so let's walk through a somewhat subtle example that frequently causes confusion to new developers with E4 and DI. Consider an E4 RCP app with two MParts, OverviewPart and DetailPart. Since the OverviewPart provides an overview of the contents shown by DetailPart, it needs to get ahold of the DetailPart. A first attempt at writing OverviewPart and DetailPart might be:

If you try to run with this code, it seems to work — but somehow the OverviewPart and DetailPart receive the same Composite! What's wrong?

There are several problems in the code above:

Objects are resolved through the context ancestry, and never through the context tree. Since MParts are siblings, an MPart will never be resolved through injection alone.

Despite their names, neither OverviewPart nor DetailPart are actually MParts. They are the contributed objects of an MPart that implement the behaviour. These contributed object are not available through the injection context.

Even if contributed objects could be injected, there could be several instances in the model. Consider the Eclipse IDE with multiple windows with the Outline view in each.

So how did the code above seem to work? It works because of a subtle feature of the Dependency Injector called instance autogeneration (also supported by Guice). When trying to inject a field or method argument of type T, our DI tries to resolve an object of type T using the provided context. If an object of type T cannot be found, it examines the type T: if it is a concrete class, and either has a 0-argument constructor or a constructor marked with @Inject, it will autogenerate an instance using the provided context.

So the flow looks something like this.

MPart(OverviewPart) is to be rendered. A new IEclipseContext is created hanging off of the MPart(OverviewPart)'s parent.

DI is requested to create OverviewPart, using the IEclipseContext for <tt>MPart(OverviewPart)

OverviewPart's constructor was called.

The OverviewPart instance's fields were examined for injection

DI found the field for DetailPart. It tried to resolve that type in the MPart(OverviewPart)'s context, but nothing was found.

DI then looked to see if DetailPart was concrete and either had a 0-argument constructor or an @Injectable constructor; it found a 0-argument constructor. DI then created an instance of DetailPart and began injecting this new DetailPart using MPart(OverviewPart)'s context. Note that DI did not create a new context for this object!

DI looked to see if this new DetailPart object had any injectable fields.

DI found a field of type Composite. DI checked in MPart(OverviewPart)'s context for Composite — and found an instance. But this instance was the Composite for OverviewPart. The field was injected.

DI then looked for methods of the new object to be injected.

DI looked for any methods in OverviewPart to be injected.

The OverviewPart object is returned.

(The correct solution is to use the EModelService to find the detail part.)

Why is my widget/part not displaying? Why am I getting a new Shell?

The fix is to annotate the use with "@Named(ACTIVE_SHELL)".

Why am I being injected with null?

Typically null values are only injected when an argument or field is marked as @Optional. But a null value will be injected if the value has previously been explicitly set to null in the context.

The context obtained using EclipseContextFactory.getServiceContext(bundleContext) is completely dissociated from the context created for an application in E4Application. If you want to populate a context such that a part can be injected, you either need to use an addon or an IContextFunction.

What is the difference between IEclipseContext#set and IEclipseContext#modify?

publicclass MyPart {
@Inject IEclipseContext context;
...
privatevoid repositoryChanged(IRepository repository){// set the variable "repository" in this part's context: the value is only visible to// this part and any children
context.set("repository", repository);// search up the context stack to see if the variable exists in one of the the context's // ancestors; otherwise it does a set in the specified context
context.modify("repository", repository);}
...
}

A placeholder can be made for #modify with IEclipseContext#declareModifiable() or a <variable> declaration in an Application.e4xmi.

Commands and Handlers

Why is my parameterized handler not triggered?

When binding a command to a UI element (e.g., an MHandledToolItem or MHandledMenuItem), the binding must provide a parameter for each of the parameters defined by the command. The attribute names used (as of 4.2M3) for establishing a correspondance between command parameters and handler arguments can lead to some confusion.

The parameters to a command are specified as instances of MCommandParameter. The identifier for each parameter, used for matching, is taken from the elementId attribute. The name attribute is a descriptive label for the parameter.

The confusion arises as each binding parameter (an instance of MParameter) also have an elementId, but it is the name attribute that is used for matching against the command parameters. The binding parameter's elementId merely serves to identify that parameter instance within the model.

For example, consider defining a command to perform a CSS theme switch, where the theme identifier is provided as a command parameter themeId. We might configure the command (programmatically) as follows:

Why does org.eclipse.core.commands.Command's isEnabled() and getHandler() not work?

Command's isEnabled() and getHandler() and are specific to Eclipse 3.x based API and are not supported in Eclipse 4. Hence they will always return false or null in Eclipse 4 applications. Applications should use the EHandlerService to query against a command.

UI

What's the difference between the xmi:id and elementId?

The xmi:id are unique identifiers are internal to EMF and used for resolving model-level references between objects, similar to a memory reference. The elementIds are Eclipse 4 identifiers and serve to provide a well-known name to an object. '

Unlike EMF's xmi:id identifiers, which are expected by EMF to be unique, Eclipse 4's elementIds do not necessarily have to be unique. For example, it may make sense for every part stack containing editors to have elementId editor-stack (though we might instead recommend using a tag). Some elementIds are expected to be unique for particular uses. For example, an MCommands elementId serves as the unique command identifier.

How do I enable Drag N Drop (DND) of parts?

The DND addon is found in the org.eclipse.e4.ui.workbench.addons.swt plugin. However it requires the compatibility layer and is not available for native E4AP applications.

Why are my CSS theming not taking effect?

Assuming that you are using the CSS theming through the 'org.eclipse.e4.ui.css.swt.theme extension point:

Ensure the org.eclipse.e4.ui.css.swt.theme bundle is included with its prereqs

Verify that a plugin.xml defines one or more themes on the org.eclipse.e4.ui.css.swt.theme extension point

Verify that your product specifies a "cssTheme" property, or is passed "-cssTheme" on the command-line, with a valid theme-id

A common symptom: your switch-theme handler cannot be injected as IThemeEngine could not be resolved

Verify that your CSS files have no errors: add a breakpoint to org.eclipse.e4.ui.css.core.exceptions.UnsupportedClassCSSPropertyException, org.eclipse.e4.ui.css.core.exceptions.DOMExceptionImpl, and org.w3c.css.sac.CSSException