Home Tutorials Training Consulting Products Books Company Donate Contact us









NOW Hiring

Quick links

Share

Defining and using custom annotations in Eclipse 4 for dependency injection. This tutorial explains how to create and evaluate your own annotations in Eclipse 4 for the purpose of dependency injection.

1. Prerequisites

The following assumes that you have already basic Eclipse RCP development experience. See the http://www.vogella.com/tutorials/Eclipse4RCP/article.html - Eclipse RCP Tutorial for details.

2. Custom annotations

2.1. Custom annotations in Eclipse

The Eclipse platform uses dependency injection as the primary programming model. This mechanism is extensible with custom annotations. The following code demonstrates how you can define your custom annotation.

package com.example.e4.rcp.todo.ownannotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@javax.inject.Qualifier
@Documented
@Target({ ElementType.PARAMETER, ElementType.FIELD })
@Retention(RetentionPolicy.RUNTIME)
public @interface DirectTodo {

        /**
         * An id parameter can be passed to the DirectTodo, in order to inject a
         * java.util.Optional<Todo> with a given id.<br/>
         * <br/>
         * Without parameter the injected Todo is an absent java.util.Optional, because Todo ids begin
         * with 1 and the default is 0 (see ITodoService).
         *
         * @return the id, which is passed to the DirectTodo annotation or 0, if no parameter is passed
         */
        long id() default 0;
}

2.2. Define an annotation processor via an OSGi service

To process these custom annotations you can register an OSGi service for the abstract ExtendedObjectSupplier class from the org.eclipse.e4.core.di.suppliers package. In this registration you define via the dependency.injection.annotation property the annotation for which the service is responsible.

After this registration the Eclipse framework calls this annotation processor if it encounters the configured annotation.

The following snippet shows an example DirectTodoSupplier.xml file which registers an ExtendedObjectSupplier for the DirectTodo annotation.

<?xml version="1.0" encoding="utf-8"?>
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="com.example.e4.rcp.todo.ownannotation.DirectTodo">
   <implementation class="com.example.e4.rcp.todo.ownannotation.internal.DirectTodoObjectSupplier"/>
   <property name="dependency.injection.annotation" type="String" value="com.example.e4.rcp.todo.ownannotation.DirectTodo"/>
   <service>
      <provide interface="org.eclipse.e4.core.di.suppliers.ExtendedObjectSupplier"/>
   </service>
</scr:component>

The annotation processor registered via the DirectTodoSupplier.xml file returns an object. The following code shows an example for an annotation processor which returns an instance of an java.util.Optional<Todo> class, in case a proper id is passed to the DirectTodo annotation.

package com.example.e4.rcp.todo.ownannotation.internal;

import java.util.Optional;

import javax.inject.Inject;

import org.eclipse.e4.core.di.suppliers.ExtendedObjectSupplier;
import org.eclipse.e4.core.di.suppliers.IObjectDescriptor;
import org.eclipse.e4.core.di.suppliers.IRequestor;
import org.osgi.service.component.annotations.Component;

import com.example.e4.rcp.todo.model.ITodoService;
import com.example.e4.rcp.todo.model.Todo;
import com.example.e4.rcp.todo.ownannotation.DirectTodo;

@Component(service=ExtendedObjectSupplier.class,
property="dependency.injection.annotation=com.example.e4.rcp.todo.ownannotation.DirectTodo")
public class DirectTodoObjectSupplier extends ExtendedObjectSupplier {

        @Inject
        private ITodoService todoService;

        @Override
        public Object get(IObjectDescriptor descriptor, IRequestor requestor, boolean track, boolean group) {
                // get the DirectTodo from the IObjectDescriptor
                DirectTodo uniqueTodo = descriptor.getQualifier(DirectTodo.class);

                // get the id from the DirectTodo (default is 0)
                long id = uniqueTodo.id();

                // get the Todo, which has the given id or null, if there is no Todo with the given id
                Optional<Todo> todo = todoService.getTodo(id);

                return todo;
        }
}

2.3. Restrictions

Dependency injection can be used inside an ExtendedObjectSupplier implementation, so that services like the IEventBroker, EModelService and so on can be injected. But Extended object suppliers do not have access to the IEclipseContext in which they are called. This limits them to search for objects independent of the current Eclipse context.

For example preferences are implemented as extended object suppliers. They look for the preference values on the file system and do not know about the IEclipseContext.

3. Example usage

An example for using your custom annotations would be the Java Persistence API (JPA). You could create a custom annotation for the JPA persistence manager. The JPA persistence manager could be injected into the Eclipse 4 application based on that custom annotation and a corresponding annotation processor.

4. Exercise: Creating custom annotations

The following exercise demonstrates how to create a custom annotation and a processor for it.

The annotation processor is registered for a custom @DirectTodo annotation, which is a qualifier and therefore has to be used together with @Inject. The @DirectTodo annotation can have a id for requesting a Todo with a certain id.

4.1. Creating a new plug-in

Create a new simple plug-in project called com.example.e4.rcp.todo.ownannotation.

Add the following plug-ins as dependencies to your new plug-in.

  • org.eclipse.e4.core.di

  • com.example.e4.rcp.todo.model

  • org.eclipse.osgi.services

Also configure that the javax.inject package should be used.

4.2. Define and export annotations

Define the following annotation.

package com.example.e4.rcp.todo.ownannotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@javax.inject.Qualifier
@Documented
@Target({ ElementType.PARAMETER, ElementType.FIELD })
@Retention(RetentionPolicy.RUNTIME)
public @interface DirectTodo {

        /**
         * An id parameter can be passed to the DirectTodo, in order to inject a
         * java.util.Optional<Todo> with a given id.<br/>
         * <br/>
         * Without parameter the injected Todo is an absent java.util.Optional, because Todo ids begin
         * with 1 and the default is 0 (see ITodoService).
         *
         * @return the id, which is passed to the DirectTodo annotation or 0, if no parameter is passed
         */
        long id() default 0;
}

Export the com.example.e4.rcp.todo.ownannotation package via your MANIFEST.MF file.

4.3. Ensure annotation processing and plug-in activation is active

Ensure that OSGi services can be defined via annotations in the class via Window ▸ Preferences ▸ Plug-in Development ▸ DS annotations.

4.4. Create service implementation

Create the com.example.e4.rcp.todo.ownannotation.internal package and the following class. Based on the annotation this registers this class as service for the ExtendedObjectSupplier abstract class via OSGi declarative services.

package com.example.e4.rcp.todo.ownannotation.internal;

import java.util.Optional;

import javax.inject.Inject;

import org.eclipse.e4.core.di.suppliers.ExtendedObjectSupplier;
import org.eclipse.e4.core.di.suppliers.IObjectDescriptor;
import org.eclipse.e4.core.di.suppliers.IRequestor;
import org.osgi.service.component.annotations.Component;

import com.example.e4.rcp.todo.model.ITodoService;
import com.example.e4.rcp.todo.model.Todo;
import com.example.e4.rcp.todo.ownannotation.DirectTodo;

@Component(service=ExtendedObjectSupplier.class,
property="dependency.injection.annotation=com.example.e4.rcp.todo.ownannotation.DirectTodo")
public class DirectTodoObjectSupplier extends ExtendedObjectSupplier {

        @Inject
        private ITodoService todoService;

        @Override
        public Object get(IObjectDescriptor descriptor, IRequestor requestor, boolean track, boolean group) {
                // get the DirectTodo from the IObjectDescriptor
                DirectTodo uniqueTodo = descriptor.getQualifier(DirectTodo.class);

                // get the id from the DirectTodo (default is 0)
                long id = uniqueTodo.id();

                // get the Todo, which has the given id or null, if there is no Todo with the given id
                Optional<Todo> todo = todoService.getTodo(id);

                return todo;
        }
}

The ExtendedObjectSupplier class is not yet released as official API. See [e4overview_api].

4.5. Add the plug-in as dependency

Add your new plug-in as dependency to your com.example.e4.rcp.todo application plug-in via its MANIFEST.MF file.

4.6. Update the product configuration (via the features)

Include the new plug-in into your feature to make it available for your product.

4.7. Validate: Use your custom annotation

In order to use your new annotation, add it to a field or method parameter in one of your parts. For example, add the following method to your PlaygroundPart class.

// more code

// add this to one of your parts
@Inject
public void setTodo(@DirectTodo(id=1) java.util.Optional<Todo> todo) {
        // Printing the received t to the console
        todo.ifPresent(t-> System.out.println(t.getSummary()));
}

Start your application (via the product as you added a new plug-in). Ensure that you get the Todo with id 1 injected based on your @DirectTodo annotation.

5. Learn more about Eclipse 4 RCP development

I hope you enjoyed this tutorial. You find this tutorial and much more information also in the Eclipse 4 RCP book.

6. About this website

7.2. vogella GmbH training and consulting support

TRAINING SERVICE & SUPPORT

The vogella company provides comprehensive training and education services from experts in the areas of Eclipse RCP, Android, Git, Java, Gradle and Spring. We offer both public and inhouse training. Whichever course you decide to take, you are guaranteed to experience what many before you refer to as “The best IT class I have ever attended”.

The vogella company offers expert consulting services, development support and coaching. Our customers range from Fortune 100 corporations to individual developers.

Copyright © 2012-2016 vogella GmbH. Free use of the software examples is granted under the terms of the EPL License. This tutorial is published under the Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Germany license.

See Licence.