Introduction
|
Paul Webster |
|
Sopot Çela |
|
Lars Vogel |
Overview
- Customizing dependency injection behavior with custom annotations
- Exploiting Eclipse4 advanced rendering
- Framework services replacement and model extensions
Eclipse Core DI
- Retrieves its information from the
IEclipseContext
.
- Can access both data and services.
- Keeps the fields and methods up to date as the data changes.
- DI is applied to POJOs instantiated by the system (Parts, Processors, Addons).
ContextInjectionFactory
uses data in IEclipseContext
to instantiate an object.
Annotations
Annotation |
Description |
@Inject |
Identifies injectable constructors, methods, and fields. |
@Named |
Specifies a String used to look up the injected value. |
@PostConstruct |
The PostConstruct annotation is used on a method that needs to be executed
after dependency injection is done to perform any initialization. |
@PreDestroy |
The PreDestroy annotation is used on methods as a callback notification to
signal that the instance is in the process of being removed by the container. |
@Singleton |
Identifies a type that the injector only instantiates once. |
Annotations - Eclipse Specific
Annotation |
Description |
@Optional |
This annotation can be applied to methods, fields, and parameters to
mark them as optional for the dependency injection. |
@Creatable |
Specifies that the target class can be created by an injector as needed. |
@Active |
This annotation can be added to injectable fields ands methods
to indicate that the injected value should come from the active context. |
Eclipse Contexts
The source for our DI data and services.
- Look up the local value for that key.
- If it's a regular result, return the result.
- If it's an
IContextFunction
evaluate and return the result.
- Ask the parent
IEclipseContext
.
ContextInjectionFactory
- Check for a
Provider<T>
- Check for an
ExtendedObjectSupplier
- Check the static
IEclipseContext
- Check the primary
IEclipseContext
- Check for any registered
IBindings
- Check to see if the type is
@Createable
Annotations - Eclipse Extensions
Annotation |
Description |
@Preference |
Access a preference value from IEclipsePreferences . |
@OSGiBundle |
Access the Bundle or BundleContext of the injected class. |
Extended Object Supplier
- You need to register an OSGi service to provide
org.eclipse.e4.core.di.suppliers.ExtendedObjectSupplier
- Your service needs to identify your annotation in a property
dependency.injection.annotation
- Provide an implementation that extends
org.eclipse.e4.core.di.suppliers.ExtendedObjectSupplier
@Preference
@Qualifier
@Documented
@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface Preference {
String value() default ""; // key in the node
String nodePath() default "";
}
@Preference - Usage
public class EclipseSplashHandler {
@Inject
@Preference("SHOW_BUILDID_ON_STARTUP")
boolean showBuildId;
@Inject
@Preference(nodePath="org.eclipse.ui", value="SHOW_PROGRESS_ON_STARTUP" )
boolean showProgress;
}
@Preference - Contributing
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0"
name="org.eclipse.e4.core.services.preferences">
<implementation
class="org.eclipse.e4.core.di.internal.extensions.PreferencesObjectSupplier"/>
<service>
<provide interface="org.eclipse.e4.core.di.suppliers.ExtendedObjectSupplier"/>
</service>
<property name="dependency.injection.annotation" type="String"
value="org.eclipse.e4.core.di.extensions.Preference"/>
</scr:component>
@Preference - Implementation
Argument |
Description |
descriptor |
descriptor of the object requested by the requestor. |
requestor |
the originator of this request. |
track |
If the object supplier should notify the requestor of a change to the returned object. |
group |
If the change notification can be grouped. |
@Preference - Implementation II
public Object get(IObjectDescriptor descriptor, IRequestor requestor,
boolean track, boolean group) {
Class<?> descriptorsClass = getDesiredClass(descriptor.getDesiredType());
String nodePath = getNodePath(descriptor, requestor.getRequestingObjectClass());
String key = getKey(descriptor);
return getPreferencesService().getString(nodePath, key, null, null);
}
Enhance an RCP application
- This is an Eclipse4 application.
- It dynamically loads and unloads plugins.
- It provides an extension point so that plugins can state their author, company.
- We want to consume the contributed extensions using DI.
Enhance an RCP application - 1.1
- https://github.com/scela/EclipseCon2014
- org.eclipse.e4.examples.di.product - the RCP application
- org.eclipse.e4.examples.di.extensions - adds support for
@Extension
- Open
/org.eclipse.e4.examples.di.product/org.eclipse.e4.examples.di.product.product
and choose
"Launch an Eclipse Application"
Exercise - 1.1
- We're replacing
OldExtensionReader
, getting rid of the boilerplate code.
- Replacing the calls to
process()
, added(final IExtension[])
, and removed(final IExtension[])
.
@Inject
@Optional
public void setExtensions(
final @Extension(SamplePart.EXTENSION_POINT) List<IConfigurationElement> elements) {
//... stuff
}
Exercise - 1.2
- Provide the
@Extension
annotation for the object supplier.
- Provide an implementation class that extends
ExtendedObjectSupplier
.
- Register the OSGi service using Declarative Services.
Exercise - 1.3
- Make sure we're calling the @Extension object supplier.
- Have
SamplePart
use DI to instantiate the ExtensionReader
.
Exercise - 1.4
- Return the valid configuration elements for
@Extension
.
- Get the
IExtensionRegistry
.
- Get the annotation information.
- Return the requested information.
Exercise - 1.5
- Add a registry listener to respond to changes if the request should be tracked.
- Re-evaluate the requestor by resolving the arguments and then executing it again.
- Check for requestor validity.
Exercise - 1.6
- Added bonus: remove all listeners from a requestor.
- In some scenarios, a single requestor can generate multiple listeners.
- Store them in a set and remove them if a requestor becomes invalid.