1. Using preferences to persist data

1.1. Preferences and scopes

Preferences store user settings, such as color preferences or runtime options, between application restarts. Preferences are stored as key-value pairs, where the key is a String. The value can be a String, a boolean, an int or another primitive type. For example, the user key may point to the value vogella.

The preference support in Eclipse is based on the Preferences class from the org.osgi.service.prefs package.

Eclipse preferences are similar to the standard Java preferences API but support different scopes. The scope defines how the preference data is stored and who can change it. The Eclipse runtime defines several scopes as explained in the following table.

Table 1. Eclipse Preference scope
Scope Description

Instance scope

Preferences in this scope are specific to a single Eclipse workspace. If you start an Eclipse application, these settings can be different for each workspace.

Configuration scope

Settings are identical for the same installation. Preferences stored in this scope are shared across all workspaces.

User scope

Settings are stored at the user level (in the user’s home directory). These preferences are shared across all Eclipse installations and workspaces for the same user. Available as of Eclipse 2024-09.

Default scope

Default values are not persisted to disk. This scope holds the default values for your keys, supplied via configuration files in plug-ins and product definitions.

BundleDefaultsScope

Similar to the default scope, these values are not written to disk. They are set by the preference initializer of a bundle or read from a customization file supplied with the bundle, typically named preferences.ini.

1.2. Storage of the preferences

Preferences are stored in the workspace of your application under the .metadata/.plugins/org.eclipse.core.runtime/.settings/ directory as <nodePath>.prefs files. The <nodePath> corresponds by default to the Bundle-SymbolicName of the plug-in but can be customized via the preferences API. By default, the workspace is the workspace folder in the directory from which the application is launched.

The workspace location, and therefore the storage location for preferences, can be adjusted through the -data launch parameter. For instance, to use the user’s home directory, use the -data @user.home parameter.

1.3. Working with the Eclipse preference API

You can create and manipulate preferences directly via singletons provided by the Eclipse runtime. The InstanceScope, ConfigurationScope, UserScope, and DefaultScope classes give access to the corresponding scope via their INSTANCE field.

Preference values are read and saved by the get() and put() methods. In the get() method, you specify a default value in case the key cannot be found. The clear() method removes all preferences, and the remove() method allows you to delete a selected preference value. Via the flush() method, you persist the preferences to the file system.

// access the instance scope
Preferences preferences = InstanceScope.INSTANCE.getNode("com.vogella.eclipse.preferences.test");

Preferences sub1 = preferences.node("node1");
Preferences sub2 = preferences.node("node2");
sub1.put("h1", "Hello");
sub1.put("h2", "Hello again");
sub2.put("h1", "Hallo"); // German
try {
    // forces the application to save the preferences
    preferences.flush();
} catch (BackingStoreException e) {
    e.printStackTrace();
}
// read values from the instance scope
Preferences preferences = InstanceScope.INSTANCE.getNode("com.vogella.eclipse.preferences.test");
Preferences sub1 = preferences.node("node1");
Preferences sub2 = preferences.node("node2");
String hello = sub1.get("h1", "default");
String helloAgain = sub1.get("h2", "default");
String hallo = sub2.get("h1", "default");

1.4. Reacting to changes in the preferences

You can register an IPreferenceChangeListener via the addPreferenceChangeListener() method of the IEclipsePreferences interface. The Eclipse framework calls the listener if a preference value changes.

IEclipsePreferences preferences = InstanceScope.INSTANCE.getNode("com.vogella.eclipse.preferences.test");

preferences.addPreferenceChangeListener(event -> {
    if ("MySTRING1".equals(event.getKey())) {
        // the new value is null if the preference was removed
        Object value = event.getNewValue();
    }
});

1.5. Default preference values via plugin_customization.ini

You can use a file to set the default values of preferences. The file that contains these defaults is typically named plugin_customization.ini.

Such a file needs to be registered via the preferenceCustomization property on the product extension point in the plugin.xml file, as demonstrated in the following screenshot.

Referring to the plugin_customization.ini file in the product extension

The format is <plug-in id>/<setting>=<value>, for example, com.vogella.tasks.ui/user=vogella.

2. Workspace location

An Eclipse-based application requires a place to store its configuration data. This is called the workspace location. By default, the workspace location is the workspace folder in the directory from which the application is launched.

2.1. Using the osgi.instance.area.default property

The osgi.instance.area.default property defines an alternative default workspace location. The property can be specified in the config.ini file of the RCP application. Usually, properties of the config.ini file are specified in the product configuration.

Product configuration with the osgi.instance.area.default property

It is possible to use variables like @user.home as a value. This is especially useful in environments like Citrix, where multiple users might use the same application but require separate workspaces.

2.2. Setting the workspace location programmatically

Many RCP applications have a login screen at startup, and the workspace location should be set according to the logged-in user. You typically create a login screen in your lifecycle class in the method annotated with @PostContextCreate.

import java.io.IOException;
import java.nio.file.Path;

import org.eclipse.core.runtime.Platform;
import org.eclipse.e4.ui.workbench.lifecycle.PostContextCreate;

public class LifeCycleManager {

    @PostContextCreate
    public void postContextCreate() throws IllegalStateException, IOException {
        // show a login dialog to the user and get the user name
        String userName = "test";

        // check if the instance location is already set,
        // otherwise setting another one will throw an IllegalStateException
        if (!Platform.getInstanceLocation().isSet()) {
            Path path = Path.of(System.getProperty("user.home"), userName, "workspace");
            Platform.getInstanceLocation().set(path.toUri().toURL(), false);
        }
    }
}

The instance location can only be set once. Therefore, the code checks Platform.getInstanceLocation().isSet() first.

When running the RCP application during development from the Eclipse IDE, the run configuration usually already defines a workspace. To be able to set the location during development, the Location field must be empty.

Launch configuration Main tab with an empty workspace Location

3. Using persistence in Eclipse applications

3.1. Working with preferences via dependency injection

The Eclipse platform allows you to use dependency injection for preferences handling. To access preferences, you use the @Preference annotation as a qualifier for the dependency injection annotation. This means that @Preference must be used together with @Inject or with another annotation that implies dependency injection, for example, the @Execute annotation.

The @Preference annotation allows you to specify the nodePath and the value as optional parameters.

The nodePath is the file name used to save the preference values to disk. By default, this is the Bundle-SymbolicName of the plug-in. The value parameter specifies the preference key for the value that should be injected.

If you omit the value parameter, Eclipse injects the IEclipsePreferences object, which you can use for storing values. If you use the value parameter, Eclipse injects the value directly. Use the value parameter for read access and the IEclipsePreferences object for storing or changing values.

The following code snippet demonstrates how to put values into the preference store. Note that @Preference is used in combination with @Execute.

// get IEclipsePreferences injected to change a value
@Execute
public void execute(@Preference(nodePath = "com.vogella.tasks.ui") IEclipsePreferences prefs) {
    prefs.put("user", "TestUser");
    prefs.put("password", "Password");
    try {
        // persist the values
        prefs.flush();
    } catch (BackingStoreException e) {
        e.printStackTrace();
    }
}

The next snippet demonstrates read access to preference values. This time, the preference annotation is used as a qualifier for @Inject.

@Inject
@Optional
public void trackUserSettings(@Preference(nodePath = "com.vogella.tasks.ui", value = "user") String user) {
    System.out.println("New user: " + user);
}

@Inject
@Optional
public void trackPasswordSettings(@Preference(nodePath = "com.vogella.tasks.ui", value = "password") String password) {
    System.out.println("New password: " + password);
}

The Eclipse platform automatically tracks the values and re-injects them into fields and methods if they change. Only changes in the instance scope are tracked, not changes in the ConfigurationScope, UserScope, and DefaultScope.

If you use the injected IEclipsePreferences to store new preference values, these values are stored in the instance scope.

3.2. Persistence of part state

Eclipse provides the @PersistState annotation for parts. A method annotated with it in the class referenced by a part can store the instance state of the part. The Eclipse framework calls such a method whenever the part or the application closes. The stored information can be used in the method annotated with @PostConstruct. A typical use case is to store the state of a checkbox.

The following example code demonstrates the usage of this annotation.

@PostConstruct
public void createControl(MPart part) {
    Map<String, String> state = part.getPersistedState();
    String value = state.get("key");
    ...
}

@PersistState
public void persistState(MPart part) {
    Map<String, String> state = part.getPersistedState();
    state.put("key", "newValue");
    ...
}

3.3. Preference pages for e4

See https://github.com/opcoach/e4Preferences for an introduction on how to use preference pages in Eclipse RCP applications.

4. Preference handling in Eclipse 3.x

4.1. Preference page

Eclipse 3.x provides a standard preference dialog to display and change preference values. To open the preference dialog, you can use the org.eclipse.ui.window.preferences command.

This functionality is specific to the Eclipse IDE and will not work for Eclipse 4 RCP applications. See e4 preferences for a pure e4 implementation.

To add a new preference page, a plug-in must provide a contribution to the org.eclipse.ui.preferencePages extension point.

This extension point defines a class that is responsible for creating a user interface and storing the preference values. This class must implement IWorkbenchPreferencePage and must have a constructor without parameters. The keywordReference element in this extension point can be used to define search terms for the preference page.

You can extend the PreferencePage class or one of its subclasses; a good template is usually FieldEditorPreferencePage.

4.2. Access preferences in different plug-ins

You can access preferences of other plug-ins via the IPreferencesService service.

For example, to access the MySTRING1 preference of the com.vogella.preferences.page plug-in, you can use the following code.

String text = Platform.getPreferencesService()
        .getString("com.vogella.preferences.page", "MySTRING1", "hello", null);

4.3. Secure storage of preferences

Eclipse allows you to encrypt preference values via the org.eclipse.equinox.security plug-in.

The key-value pairs are stored in the secure_storage file in the .eclipse/org.eclipse.equinox.security folder of the user’s home directory. Eclipse uses a class of type PasswordProvider for encrypting the preferences and has a default class registered.

Via the org.eclipse.equinox.security.secureStorage extension point, you can register your own PasswordProvider.

5. Prerequisites

The following assumes that you know how to create Eclipse plug-ins.

6. Tutorial: Preferences via code

You can create, store and retrieve preference values directly via your coding. The following gives an example for this.

Create the following custom composite for that. Use this composite in one of your parts.

The first Button will set the preference values. The next will display the values, and the last will clear the preference values.

package de.vogella.preferences.test.ui;

import org.eclipse.core.runtime.preferences.ConfigurationScope;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.osgi.service.prefs.BackingStoreException;
import org.osgi.service.prefs.Preferences;

public class ButtonComposite extends Composite {

    public ButtonComposite(Composite parent, int style) {
        super(parent, style);
        Button write = new Button(parent, SWT.PUSH);
        write.setText("Write");
        write.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {

                Preferences preferences = ConfigurationScope.INSTANCE
                .getNode("de.vogella.preferences.test");
                Preferences sub1 = preferences.node("node1");
                Preferences sub2 = preferences.node("node2");
                sub1.put("h1", "Hello");
                sub1.put("h2", "Hello again");
                sub2.put("h1", "Hallo"); // German

                try {
                    // forces the application to save the preferences
                    preferences.flush();
                } catch (BackingStoreException e2) {
                    e2.printStackTrace();
                }
            }
        });
        Button read = new Button(parent, SWT.PUSH);
        read.setText("Read");
        read.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                Preferences preferences = ConfigurationScope.INSTANCE
                        .getNode("de.vogella.preferences.test");
                Preferences sub1 = preferences.node("node1");
                Preferences sub2 = preferences.node("node2");
                System.out.println(sub1.get("h1", "default"));
                System.out.println(sub1.get("h2", "default"));
                System.out.println(sub2.get("h1", "default"));

            }
        });

        Button clear = new Button(parent, SWT.PUSH);
        clear.setText("clear");
        clear.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                Preferences preferences = ConfigurationScope.INSTANCE
                        .getNode("de.vogella.preferences.test");
                Preferences sub1 = preferences.node("node1");
                Preferences sub2 = preferences.node("node2");
                // Delete the existing settings
                try {
                    sub1.clear();
                    sub2.clear();
                    preferences.flush();
                } catch (BackingStoreException e1) {
                    e1.printStackTrace();
                }
            }
        });
        
    }
}

Run and test your program.

7. Exercise: Contribute a preference page to the Eclipse IDE

In this exercise, you create a plug-in with a preference page that allows the user to enter certain settings.

Create a simple plug-in project named com.vogella.preferences.page.

Open the MANIFEST.MF editor and add the following plug-ins on the Dependencies tab.

  • org.eclipse.ui

  • org.eclipse.core.runtime

On the Extensions tab, add an extension for the org.eclipse.ui.preferencePages extension point. If this tab is not visible, click the Extensions link on the Overview tab.

Enter the data in plugin.xml similar to the following.

<?xml version="1.0" encoding="UTF-8"?>
<?eclipse version="3.4"?>
<plugin>
   <extension
         point="org.eclipse.ui.preferencePages">
      <page
            class="com.vogella.preferences.page.VogellaPrefPage"
            id="com.vogella.preferences.page.page1"
            name="vogella Preferences">
      </page>
   </extension>

</plugin>

Enter the following code for your VogellaPrefPage class. The init() method sets the preference store, and the createFieldEditors() method registers editors for the values.

package com.vogella.preferences.page;

import org.eclipse.core.runtime.preferences.InstanceScope;
import org.eclipse.jface.preference.BooleanFieldEditor;
import org.eclipse.jface.preference.DirectoryFieldEditor;
import org.eclipse.jface.preference.FieldEditorPreferencePage;
import org.eclipse.jface.preference.RadioGroupFieldEditor;
import org.eclipse.jface.preference.StringFieldEditor;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchPreferencePage;
import org.eclipse.ui.preferences.ScopedPreferenceStore;

public class VogellaPrefPage extends FieldEditorPreferencePage implements IWorkbenchPreferencePage {

    public VogellaPrefPage() {
        super(GRID);
    }

    public void createFieldEditors() {
        addField(new DirectoryFieldEditor("PATH", "&Directory preference:", getFieldEditorParent()));
        addField(new BooleanFieldEditor("BOOLEAN_VALUE", "&A boolean preference", getFieldEditorParent()));

        addField(new RadioGroupFieldEditor("CHOICE", "A &multiple-choice preference", 1,
                new String[][] { { "&Choice 1", "choice1" }, { "C&hoice 2", "choice2" } }, getFieldEditorParent()));
        addField(new StringFieldEditor("MySTRING1", "A &text preference:", getFieldEditorParent()));
        addField(new StringFieldEditor("MySTRING2", "A t&ext preference:", getFieldEditorParent()));
    }

    @Override
    public void init(IWorkbench workbench) {
        // second parameter is typically the plug-in id
        setPreferenceStore(new ScopedPreferenceStore(InstanceScope.INSTANCE, "com.vogella.preferences.page"));
        setDescription("A demonstration of a preference page implementation");
    }

}

7.1. Add to your feature

Add your new plug-in to your feature.

7.2. Validate

Start a runtime Eclipse IDE via your product. Open the preference dialog via Window  Preferences.

Ensure that you see your preference page in the preferences of the Eclipse IDE. Type vogella into the filter field to find it quickly.

vogella Preferences page in the Preferences dialog

Validate that the entered values are still there after you restart your application.

7.3. Create preference initializer

Create the following com.vogella.preferences.page.VogellaPrefInitializer class.

package com.vogella.preferences.page;

import org.eclipse.core.runtime.preferences.AbstractPreferenceInitializer;
import org.eclipse.core.runtime.preferences.DefaultScope;

public class VogellaPrefInitializer extends AbstractPreferenceInitializer {

    @Override
    public void initializeDefaultPreferences() {
        DefaultScope.INSTANCE.getNode("com.vogella.preferences.page").put("MySTRING1", "https://www.vogella.com/");
    }

}

To set the default values for your preferences, add an extension for the org.eclipse.core.runtime.preferences extension point. Right-click on it, select New  initializer and point its class attribute to VogellaPrefInitializer.

Optional: Press Restore Defaults on your preference page and validate that the text field now shows the default URL.

7.4. Use preference in one of your views

Ensure that org.eclipse.ui is available as a dependency in the manifest of the plug-in in which you plan to use the preferences.

Create a new part or use an existing one to show one of the preference values. Also register an IPropertyChangeListener with the preference store to get informed if the preference settings change.

package com.vogella.tasks.ui.parts;

import jakarta.annotation.PostConstruct;

import org.eclipse.core.runtime.preferences.InstanceScope;
import org.eclipse.jface.widgets.WidgetFactory;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.ui.preferences.ScopedPreferenceStore;

public class PlaygroundPart {

    private Label label;

    @PostConstruct
    public void createPartControl(Composite parent) {

        // more code
        ScopedPreferenceStore scopedPreferenceStore = new ScopedPreferenceStore(InstanceScope.INSTANCE,
                "com.vogella.preferences.page");
        String string = scopedPreferenceStore.getString("MySTRING1");
        label = WidgetFactory.label(SWT.NONE)
                .layoutData(new GridData(SWT.BEGINNING, SWT.CENTER, false, false))
                .text(string)
                .create(parent);
        // get notified when the preference changes
        scopedPreferenceStore.addPropertyChangeListener(event -> {
            if ("MySTRING1".equals(event.getProperty())) {
                label.setText(String.valueOf(event.getNewValue()));
                label.requestLayout();
            }
        });
    }
}

7.5. Validate

Open your part and validate that it shows the value of the text preference. Change the preference afterward and validate that the label updates.

Playground part showing the text preference

8. Tutorial: Secure storage of preferences

To test the secure storage of preferences, create a new plug-in named com.vogella.preferences.security. Add a new view. Add the org.eclipse.equinox.security plug-in as a dependency to it.

Change the code of your view to the following.

package de.vogella.preferences.security;

import org.eclipse.equinox.security.storage.ISecurePreferences;
import org.eclipse.equinox.security.storage.SecurePreferencesFactory;
import org.eclipse.equinox.security.storage.StorageException;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.ui.part.ViewPart;

public class View extends ViewPart {
    public void createPartControl(Composite parent) {
        Button buttonPut = new Button(parent, SWT.PUSH);
        buttonPut.setText("Save values");
        buttonPut.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                ISecurePreferences preferences = SecurePreferencesFactory
                        .getDefault();
                ISecurePreferences node = preferences.node("info");
                try {
                    node.put("user", "vogella", true);
                    node.put("password", "123", true);
                } catch (StorageException e1) {
                    e1.printStackTrace();
                }
            }
        });
        Button buttonGet = new Button(parent, SWT.PUSH);
        buttonGet.setText("Get values");
        buttonGet.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                ISecurePreferences preferences = SecurePreferencesFactory
                        .getDefault();
                if (preferences.nodeExists("info")) {
                    ISecurePreferences node = preferences.node("info");
                    try {
                        String user = node.get("user", "n/a");
                        String password = node.get("password", "n/a");
                        System.out.println(user);
                        System.out.println(password);
                    } catch (StorageException e1) {
                        e1.printStackTrace();
                    }
                }
            }
        });

    }

    /**
     * Passing the focus request to the viewer's control.
     */
    public void setFocus() {
    }
}
Home Tutorials Training Consulting Books Company Contact us


Get more...