Eclipse Project Natures This article describes how project natures can be implemented and how to use a custom project nature.

1. Project Natures in Eclipse

Project Natures are used in the Eclipse IDE in order to configure projects in the workspace. One project may have several project natures. The most popular project nature is org.eclipse.jdt.core.javanature, which is used to indicate that a project is a Java project. Some examples for project natures are:

Table 1. Examples of Project Natures
Project Nature’s ID Description

org.eclipse.jdt.core.javanature

Java Projects

org.eclipse.buildship.core.gradleprojectnature

Gradle Projects

org.eclipse.m2e.core.maven2Nature

Maven Projects

org.eclipse.pde.core.org.eclipse.pde.PluginNature

Eclipse Plugin Projects

org.eclipse.pde.core.org.eclipse.pde.FeatureNature

Eclipse Feature Projects

org.eclipse.pde.core.org.eclipse.pde.UpdateSiteNature

Eclipse Updatesite Projects

If your Eclipse installation offers some additional project natures, which can be applied to a project, you can usually convert the project via the context menu.

configure project popup
The Configure menu is only visible, if there are project natures, which can be applied. Otherwise it is not shown at all.

2. Define a project nature

Project natures are defined with the org.eclipse.core.resources.natures extension point. A bare project nature only needs a name, id and a class reference, to a class that implements IProjectNature.

<extension
    id="examplenature"
    name="Example nature"
    point="org.eclipse.core.resources.natures">
    <runtime>
        <run
            class="com.example.product.ExampleProjectNature">
        </run>
    </runtime>
</extension>

The implementation of the referenced ExampleProjectNature can look like this:

import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IProjectNature;
import org.eclipse.core.runtime.CoreException;

public class ExampleProjectNature implements IProjectNature {

    // ID of the natures, which consists of Bundle-SymbolicName + ID
    public static final String NATURE_ID = "com.example.project.examplenature";

    private IProject project;

    @Override
    public void configure() throws CoreException {
        // only called once the nature has been set

        // configure the project...
    }

    @Override
    public void deconfigure() throws CoreException {
        // only called once the nature has been set

        // reset the project configuration...
    }

    @Override
    public IProject getProject() {
        return project;
    }

    @Override
    public void setProject(IProject project) {
        this.project = project;
    }

}
The acutal id of a project nature consists of the Bundle-SymbolicName + id, which is defined for the extension point. See NATURE_ID in ExampleProjectNature.

2.1. Require a certain project nature as precondition

In some cases applying a project nature only makes sense, if the project already has a certain project nature. For example if your custom project nature should only be applicable on a Java project.

<extension
    id="examplenature"
    name="Example nature"
    point="org.eclipse.core.resources.natures">
    <runtime>
        <run
            class="com.example.product.ExampleProjectNature">
        </run>
    </runtime>
    <requires-nature
            id="org.eclipse.jdt.core.javanature">
    </requires-nature>
</extension>

2.2. Get and set a Project Natures

Every IProject has an IProjectDescription, which contains all natureIds. From the IProjectDescription a string array of all nature ids can be obtained. If you want to add a new project nature to a project, you need to add its id to the existing array. After that the new array (that contains the new project natures id at the end) needs to be validated. If the validation is successful the newNatures array can be set on the IProjectDescription object of the project.

IProject project = // get project...
IProjectDescription description = project.getDescription();

String[] natures = description.getNatureIds();
String[] newNatures = new String[natures.length + 1];
System.arraycopy(natures, 0, newNatures, 0, natures.length);
newNatures[natures.length] = ExampleProjectNature.NATURE_ID;

// validate the natures
IWorkspace workspace = ResourcesPlugin.getWorkspace();
IStatus status = workspace.validateNatureSet(newNatures);

// only apply new nature, if the status is ok
if (status.getCode() == IStatus.OK) {
    description.setNatureIds(newNatures);
    project.setDescription(description, null);
}

2.3. Using expressions to check for project natures

The existence of a certain project nature can also be checked with a core expression, which can be defined within the org.eclipse.core.expressions.definitions extension point.

<extension
    point="org.eclipse.core.expressions.definitions">
    <definition
        id="com.example.project.hasNature">
        <adapt
            type="org.eclipse.core.resources.IProject">
            <test
                property="org.eclipse.core.resources.projectNature"
                value="com.example.project.examplenature">
            </test>
        </adapt>
    </definition>
</extension>

Here you can see that a PropertyTester for project natures is already available and you can use the org.eclipse.core.resources.projectNature property to check for a certain project nature.

3. Exercise: Apply a project nature to a project

This exercise describes how to add a Convert to example project menu item to the Configure menu of a project.

3.1. Define an example project nature

Create a plugin project and add the following dependencies to it:

  • org.eclipse.core.runtime

  • org.eclipse.core.resources

  • org.eclipse.ui.ide

  • org.eclipse.ui

In the plugin.xml you need to add the org.eclipse.core.resources.natures extension point.

exercise project nature extension

In the ExampleProjectNature (run) we reference the ExampleProjectNature class:

import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IProjectNature;
import org.eclipse.core.runtime.CoreException;

public class ExampleProjectNature implements IProjectNature {

    // ID of the natures, which consists of Bundle-SymbolicName + ID
    public static final String NATURE_ID = "com.example.project.examplenature";

    private IProject project;

    @Override
    public void configure() throws CoreException {
        // only called once the nature has been set

        // configure the project...
    }

    @Override
    public void deconfigure() throws CoreException {
        // only called once the nature has been set

        // reset the project configuration...
    }

    @Override
    public IProject getProject() {
        return project;
    }

    @Override
    public void setProject(IProject project) {
        this.project = project;
    }

}

3.2. Add a convert command

Now use the org.eclipse.ui.commands extension point and add a command with com.example.product.examplenature.command as id and Convert to Example Project as name.

3.3. Add a convert handler

Add the org.eclipse.ui.handlers extension point and add a handler for the com.example.product.examplenature.command command. The class for the handler is ExampleProjectNatureHandler and looks like this:

import org.eclipse.core.commands.AbstractHandler;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.commands.IHandler;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IProjectDescription;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IAdapterManager;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Platform;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.ui.handlers.HandlerUtil;

import com.example.product.ExampleProductNature;

public class ExampleProjectNatureHandler extends AbstractHandler {

    @Override
    public Object execute(ExecutionEvent event) throws ExecutionException {

        ISelection currentSelection = HandlerUtil.getCurrentSelection(event);
        if (currentSelection instanceof IStructuredSelection) {

            Object firstElement = ((IStructuredSelection) currentSelection).getFirstElement();

            // Get an IResource as an adapter from the current selection
            IAdapterManager adapterManager = Platform.getAdapterManager();
            IResource resourceAdapter = adapterManager.getAdapter(firstElement, IResource.class);

            if (resourceAdapter != null) {
                IResource resource = resourceAdapter;
                IProject project = resource.getProject();
                try {
                    IProjectDescription description = project.getDescription();
                    String[] natures = description.getNatureIds();
                    String[] newNatures = new String[natures.length + 1];
                    System.arraycopy(natures, 0, newNatures, 0, natures.length);

                    // add our new "com.example.project.examplenature" id
                    newNatures[natures.length] = ExampleProjectNature.NATURE_ID;

                    // validate the natures
                    IWorkspace workspace = ResourcesPlugin.getWorkspace();
                    IStatus status = workspace.validateNatureSet(newNatures);

                    // only apply new nature, if the status is ok
                    if (status.getCode() == IStatus.OK) {
                        description.setNatureIds(newNatures);
                        project.setDescription(description, null);
                    }

                    return status;
                } catch (CoreException e) {
                    throw new ExecutionException(e.getMessage(), e);
                }
            }
        }

        return Status.OK_STATUS;
    }

}

3.4. Add the menu contribution for the conversion

The id of the Configure menu in a projects context menu is org.eclipse.ui.projectConfigure and therefore the locationURI of the menuContribution must be popup:org.eclipse.ui.projectConfigure. In this menuContribution we then reference the defined command.

exercise convert menucontribution

3.5. Optional - Add a core expression

As already mentioned the Configure menu is only visible, if it has elements in it. Therefore we should only apply the menuContribution to it, if the nature has not already been set. This can be done using a core expression with the org.eclipse.core.expressions.definitions extension point.

exercise core expression

The id of the definition should be com.example.project.hasNature, which adapts org.eclipse.core.resources.IProject as type and reuses a predefined PropertyTester, which is able to check for certain project natures. The property of the PropertyTester is org.eclipse.core.resources.projectNature.

exercise project nature propertytester

Now we only need to reference this definition in a visibleWhen definition for the menuContribution.

exercise visibleWhen expression

Do not forget to define (not) and then reference the com.example.project.hasNature definition. The (not) is not directly part of the definition itself, because we want to reuse this definition later on, where we want to ensure that the com.example.project.examplenature is applied to a project.

3.6. Validate

Start your plug-in within the Eclipse IDE and create a new General Project and then right click the project and click on Configure  Convert to Example Project. If you have done the optional part, the Convert to Example Project menu item should not appear in the Configure menu anymore.

4. Provide an image as decorator for the project

You may have noticed the J as decorator for a java project.

project nature java images

In order to provide such an decorator image if your project nature has been applied to a project, you can use the org.eclipse.ui.ide.projectNatureImages extension point.

project nature images extension point

So in case the com.example.project.examplenature project nature is applied to a project, this decorator will also be shown.

The recommended size of these images is 8x8 pixels. Any other size might not look as good.

When the com.example.project.examplenature is applied to a general test project it should look like this:

project nature image example

5. Properties of a Project

Each project also has properties, which can be configured. You can access these properties from the last menu item of the context menu of a project, which is called Properties. For a general project called test the properties might look like this:

minimal project properties

The org.eclipse.ui.propertyPages extension point can be used to add new property pages to the project’s properties dialog. In general a property page extends org.eclipse.ui.dialogs.PropertyPage class and also implements the org.eclipse.ui.IWorkbenchPropertyPage interface.

6. Exercise: Add a new custom property page

This exercise describes how to add a custom property page to the properties dialog of projects, that have the com.example.project.examplenature project nature.

The project from previous exercises is reused.

6.1. Adding a custom property page

Add the org.eclipse.ui.propertyPages extension point and configure the page like this:

exercise project nature property page

The referenced ExamplePropertyPage should extend the org.eclipse.ui.dialogs.PropertyPage class and implement the org.eclipse.ui.IWorkbenchPropertyPage interface.

import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Label;
import org.eclipse.ui.IWorkbenchPropertyPage;
import org.eclipse.ui.dialogs.PropertyPage;

public class ExamplePropertyPage extends PropertyPage implements IWorkbenchPropertyPage {

    @Override
    protected Control createContents(Composite parent) {

        // There will be no default, therefore remove default button
        noDefaultButton();

        Label label = new Label(parent, SWT.NONE);
        label.setText("PropertyPage example.");

        return label;
    }

}

6.2. Optional - Reuse project nature definition

We only want to add the custom property page, if the com.example.project.examplenature project nature is applied to the project. Therefore we need to define an enabledWhen definition, with the com.example.project.hasNature expression, which has been created in the previous optional exercise.

property page enablement

6.3. Validate

Start your plug-in within the Eclipse IDE, right click your project and click on the Properties menu item. Then select Example Settings and the result should look like this:

exercise project nature property page sample

In case you have also done the optional exercises the Example Settings should only be visible, if the com.example.project.examplenature project nature is applied to the project.

7. Eclipse Project Natures online resources