The Checker Framework Manual:
Custom pluggable types for Java

Chapter 17 Property File Checker

The Property File Checker ensures that a property file or resource bundle (both of which act like maps from keys to values) is only accessed with valid keys. An access without a valid key does not fail in an obvious way: ResourceBundle.getString throws a MissingResourceException, and Properties.getProperty returns null or the default value supplied by the caller. This can lead to a NullPointerException or hard-to-trace behavior. The Property File Checker (Section 17.1) ensures that the keys used are found in the corresponding property file or resource bundle.

We also provide two specialized checkers. An Internationalization Checker (Section 17.2) verifies that code is properly internationalized. A Compiler Message Key Checker (Section 17.3) verifies that compiler message keys used in the Checker Framework are declared in a property file. This is an example of a simple specialization of the property file checker, and the Checker Framework source code shows how it is used.

It is easy to customize the Property Key Checker for other related purposes. Take a look at the source code of the Compiler Message Key Checker and adapt it for your purposes.

17.1 General Property File Checker

The general Property File Checker ensures that a resource key is located in a specified property file or resource bundle.

The annotation @PropertyKey indicates that the qualified CharSequence is a valid key found in the property file or resource bundle. You do not need to annotate String literals. The checker looks up every String literal in the specified property file or resource bundle, and adds annotations as appropriate.

If you pass a CharSequence (including String) variable to be eventually used as a key, you also need to annotate all these variables with @PropertyKey.

The checker can be invoked by running the following command:

    javac -processor org.checkerframework.checker.propkey.PropertyKeyChecker
          -Abundlenames=MyResource MyFile.java ...

You must specify the resources, which map keys to strings. The checker supports two types of resource: resource bundles and property files. You can specify one or both of the following two command-line options:

  • 1. -Abundlenames=resource_name

    resource_name is the name of the resource to be used with ResourceBundle.getBundle(). The checker uses the default Locale and ClassLoader in the compilation system. (For a tutorial about ResourceBundles, see https://docs.oracle.com/javase/tutorial/i18n/resbundle/concept.html.) Multiple resource bundle names are separated by colons “:”.

  • 2. -Apropfiles=prop_file

    prop_file is the name of a properties file that maps keys to values. The file format is described in the Javadoc for Properties.load(). Multiple files are separated by Java’s File.pathSeparator (semicolon “;” on Windows, colon “:” on Linux and Mac).

17.2 Internationalization Checker (I18n Checker)

The Internationalization Checker, or I18n Checker, verifies that your code is properly internationalized. Internationalization is the process of designing software so that it can be adapted to different languages and locales without needing to change the code. Localization is the process of adapting internationalized software to specific languages and locales.

Internationalization is sometimes called i18n, because the word starts with “i”, ends with “n”, and has 18 characters in between. Localization is similarly sometimes abbreviated as l10n.

The checker focuses on one aspect of internationalization: user-visible text should be presented in the user’s own language, such as English, French, or German. This is achieved by looking up keys in a localization resource, which maps keys to user-visible text. For instance, one version of a resource might map "CANCEL_STRING" to "Cancel", and another version of the same resource might map "CANCEL_STRING" to "Abbrechen".

There are other aspects to localization, such as formatting of dates (3/5 vs. 5/3 for March 5), that the checker does not check.

The Internationalization Checker verifies these two properties:

  • 1. Any user-visible text should be obtained from a localization resource. For example, String literals should not be output to the user.

  • 2. When looking up keys in a localization resource, the key should exist in that resource. This check catches incorrect or misspelled localization keys.

If you use the Internationalization Checker, you may want to also use the Internationalization Format String Checker, or I18n Format String Checker (Chapter 16). It verifies that internationalization format strings are well-formed and used with arguments of the proper type, so that MessageFormat.format does not fail at run time.

17.2.1 Internationalization annotations

The Internationalization Checker supports two type systems:

@Localized

indicates that the qualified CharSequence is a message that has been localized and/or formatted with respect to the used locale. It is a subtype of @UnknownLocalized, which is the default and which programmers do not need to write.

@LocalizableKey

indicates that the qualified CharSequence or Object is a valid key found in the localization resource. This annotation is a specialization of the @PropertyKey annotation, which gets checked by the general Property Key Checker. It is a subtype of @UnknownLocalizableKey, which is the default and which programmers do not need to write.

You may need to add the @Localized annotation to more methods in the JDK or other libraries, or in your own code.

17.2.2 Running the Internationalization Checker

The Internationalization Checker can be invoked by running the following command:

    javac -processor org.checkerframework.checker.i18n.I18nChecker -Abundlenames=MyResource MyFile.java ...

You must specify the localization resource, which maps keys to user-visible text. Like the general Property Key Checker, the Internationalization Checker supports two types of localization resource: ResourceBundles using the -Abundlenames=resource_name option or property files using the -Apropfiles=prop_file option.

17.3 Compiler Message Key Checker

The Checker Framework uses compiler message keys to output error messages. These keys are replaced by localized strings for user-visible error messages. Using keys instead of the localized strings in the source code enables easier testing, as the expected message keys can stay unchanged while the localized strings can still be modified. We use the Compiler Message Key Checker to ensure that all internal keys are correctly localized. Instead of using the Property File Checker, we use a specialized checker, giving us more precise documentation of the intended use of Strings.

The single annotation used by this checker is @CompilerMessageKey. The Checker Framework is completely annotated; for example, class org.checkerframework.framework.source.DiagMessage uses @CompilerMessageKey in its constructor and in method error. For most users of the Checker Framework, there will be no need to annotate any Strings, as the checker looks up all String literals and adds annotations as appropriate.

The Compiler Message Key Checker can be invoked by running the following command:

    javac -processor org.checkerframework.checker.compilermsgs.CompilerMessagesChecker
          -Apropfiles=messages.properties MyFile.java ...

You must specify the resource, which maps compiler message keys to user-visible text. The checker supports the same options as the general Property Key Checker. Within the Checker Framework we only use property files, so the -Apropfiles=prop_file option should be used.