The Preferences API in Java

We end this chapter with a discussion of the java.utit.prefs API. In a desktop program, you will often want to store user preferences, such as the last file that the user worked on, the last window location, and so on.

As you have seen in Chapter 9, the Properties class makes it simple to load and save configuration information of a program. However, using property files has these disadvantages:

  • Some operating systems have no concept of a home directory, making it difficult to find a uniform location for configuration files.
  • There is no standard convention for naming configuration files, increasing the likelihood of name clashes as users install multiple Java applications.

Some operating systems have a central repository for configuration informa­tion. The best-known example is the registry in Microsoft Windows. The Preferences class provides such a central repository in a platform-independent manner. In Windows, the Preferences class uses the registry for storage; on Linux, the information is stored in the local file system instead. Of course, the repository implementation is transparent to the programmer using the Preferences class.

The Preferences repository has a tree structure, with node path names such as /com/mycompany/myapp. As with package names, name clashes are avoided as long as programmers start the paths with reversed domain names. In fact, the de­signers of the API suggest that the configuration node paths match the package names in your program.

Each node in the repository has a separate table of key/value pairs that you can use to store numbers, strings, or byte arrays. No provision is made for storing serializable objects. The API designers felt that the serialization format is too fragile for long-term storage. Of course, if you disagree, you can save serialized objects in byte arrays.

For additional flexibility, there are multiple parallel trees. Each program user has one tree; an additional tree, called the system tree, is available for settings that are common to all users. The Preferences class uses the operating system’s notion of the “current user” for accessing the appropriate user tree.

To access a node in the tree, start with the user or system root:

Preferences root = Preferences.userRoot();

or

Preferences root = Preferences.systemRoot();

Then access the node. You can simply provide a node path name:

Preferences node = root.node(“/com/mycompany/myapp”);

A convenient shortcut gets a node whose path name equals the package name of a class. Simply take an object of that class and call

Preferences node = Preferences.userNodeForPackage(obj.getCtass());

or

Preferences node = Preferences.systemNodeForPackage(obj.getCtass());

Typically, obj will be the this reference.

Once you have a node, you can access the key/value table with methods

String get(String key, String defvat)

int getInt(String key, int defvat)

long getLong(String key, tong defvat)

float getFtoat(String key, float defvat)

double getDoubte(String key, doubte defvat)

bootean getBootean(String key, bootean defvat)\

byte[] getByteArray(String key, byte[] defvat)

Note that you must specify a default value when reading the information, in case the repository data is not available. Defaults are required for several reasons. The data might be missing because the user never specified a pref­erence. Certain resource-constrained platforms might not have a repository, and mobile devices might be temporarily disconnected from the repository.

Conversely, you can write data to the repository with put methods such as

put(String key, String vatue)

putInt(String key, int vatue)

and so on.

You can enumerate all keys stored in a node with the method

String[] keys()

There is currently no way to find out the type of the value of a particular key.

Central repositories such as the Windows registry traditionally suffer from two problems:

  • They turn into a “dumping ground” filled with obsolete information.
  • Configuration data gets entangled into the repository, making it difficult to move preferences to a new platform.

The Preferences class has a solution for the second problem. You can export the preferences of a subtree (or, less commonly, a single node) by calling the methods

void exportSubtree(OutputStream out)

void exportNode(OutputStream out)

The data are saved in XML format. You can import them into another repository by calling

void importPreferences(InputStream in)

Here is a sample file:

<?xmt version=”1.0″ encoding=”UTF-8″?>

<!DOCTYPE preferences SYSTEM “http://java.sun.com/dtd/preferences.dtd”>

preferences EXTERNAL_XML_VERSION=”1.0″>

<root type=”user”>

<map/>

<node name=”com”>

<map/>

<node name=”horstmann”>

<map/>

<node name=”corejava”>

<map>

<entry key=”height” vatue=”200.0″/>

<entry key=”teft” vatue=”1027.0″/>

<entrykey=”fitename”value=”/home/cay/books/cjn/code/v1ch11/raven.html”/>

<entry key=”top” vatue=”380.0″/>

<entry key=”width” vatue=”300.0″/>

</map>

</node>

</root>

</preferences>

If your program uses preferences, you should give your users the opportunity of exporting and importing them, so they can easily migrate their settings from one computer to another. The program in Listing 10.7 demonstrates this technique. The program simply saves the window location and the last loaded filename. Try resizing the window, then export your preferences, move the window, exit, and restart the application. The window will be just like you left it when you exited. Import your preferences, and the window reverts to its prior location.

Source: Horstmann Cay S. (2019), Core Java. Volume I – Fundamentals, Pearson; 11th edition.

Leave a Reply

Your email address will not be published. Required fields are marked *