General Purpose Converters

The following interpolating converters create objects that are widely used in general-purpose code.

Atomic Converters

These converters create objects based on a single string literal or resource bundle key. They are singleton instance fields of com.taco.text.AtomConverter. The converter for each field is named from the type created, in all capital letters, suffixed with _CONVERTER. For example, the converter to type Boolean is AtomConverter.BOOLEAN_CONVERTER.

Type Created
String Syntax
Note
Boolean
true, false, t, f, yes, no, y, or n

Character
Any single quoted Java character literal, e.g. 'x', '\n', or '\u3215'
The single quotes are optional for ASCII characters, e.g. a.
If the string input is an escaped sequence, the converter will create a Character representing the intended character.
Integer
Same as for Integer.decode(), e.g. 236.

Long
Same as for Long.decode(), e.g. 23333772116.
The "L" suffix is not supported.
Float
Same as for Float.valueOf(), e.g. 236.0. The "f" suffix is not supported.
Double
Same as for Double.valueOf(), e.g. 72e62.
Class
The fully qualified name of a class, e.g. foo.bar.Shape.

Locale
xx
or
xx_YY
or
xx_YY_zzzz
where
xx represents the language code, YY represents the country code, and zzzz represents the variant.


If an AtomicConverter fails to parse a string, it sees if the string is enclosed by { and }. If so, it returns the result of evaluating the contents of the string by the BeanShell interpreter. Otherwise, it throws a ParseException.


String Converters

Because strings are so pervasive, the com.taco.text package offers two kinds of converters to strings.

(Unformatted) String

com.taco.text.StringConverter.instance converts any string to itself. No formatting or unescaping of the string is performed. Double quotes surrounding the string will not be removed. If converting from a resource bundle key, the string value mapped to the key is directly used.

Quoted String

com.taco.text.QuotedStringConverter.instance has the capability to do formatting as well as unescaping. It supports two syntaxes:
  1. A double quoted literal string. The double quotes are optional, and removed. The contents are unescaped as a Java literal string, so they may contain characters such as \n and \u3821. If converting from a resource bundle key, the string value mapped to the key is unquoted and unescaped.
  2. A message format and an array of arguments for the formatter.

    The string syntax is:

    { messageFormat [, args] }

    where messageFormat denotes a string convertible to a MessageFormat using com.taco.text.MessageFormatConverter, and args (optional) denotes a string convertible to a collection of objects using com.taco.text.CollectionConverter.INSTANCE_COLLECTION_CONVERTER (it may also resolve to an instance of Object[]).

    As an example, the quoted string converter converts

    {"I like {0} eggs and {1} ham", ["green", "blood-red"]}

    to

    I like green eggs and blood-red ham!

    The resource bundle key converter uses com.taco.text.MessageFormatConverter to convert the "format" subkey to a MessageFormat. It also uses com.taco.text.CollectionConverter.INSTANCE_COLLECTION_CONVERTER to converts the "args" subkey to a collection of arguments to passed to the formatter. The "args" subkey is optional; if not defined, no arguments will be passed to the formatter.

    As an example, given a resource bundle with the following lines:

    confirm.label.text.format=Delete all mail from {0}?
    confirm.label.text.args.0=$spammer

    conversion of the confirm.label key, with "spammer" mapped to "viagra@xxx.com" in the argument map, will result in the string "Delete all mail from viagra@xxx.com?".
If the quoted string converter is used to convert a resource bundle key which is defined, the first syntax will be used. Only if the resource bundle key is undefined will the converter read the "format" and "args" subkeys.

MessageFormat Converter

Since one of the goals of the text2gui project is to make international application programming easier, a special converter to instances of java.text.MessageFormat is vital. It is the singleton com.taco.text.MessageFormatConverter.instance. Actually, even without internationalization concerns, strings formatted by MessageFormat are useful for dialog messages. See the Javadoc for MessageFormat for more information.

The string syntax is:

{ patternString [ , localeString ] }

where patternString denotes a pattern string converted by QuotedStringConverter.instance, and localeString (optional) denotes a string convertible to a Locale using AtomConverter.LOCALE_CONVERTER. Both the pattern string and the locale are also passed to the constructor MessageFormat. If no locale is specified, the default locale will be used.
The opening and closing braces around the entire string are optional.

Examples:

{ "The file you are attempting to write, {0}, already exists. It was last written on {1, date}.", en }

creates a MessageFormat with English as the locale.

"{0} is my favorite cartoon. It's on at {1, time, long}!"

creates a MessageFormat with the default locale. The quotes are not optional because without them, the first character would be a '{' which is interpreted as the optional '{' that starts a message format string.

Instance Converter

com.taco.text.InstanceConverter.DEFAULT_INSTANCE is used to convert strings and resource bundle keys to objects when the target object's type is unknown, may vary, or has no specialized converter. There are several supported string syntaxes which resemble Java literals:

Syntax
Examples
Created Object
Note
Java boolean literal
true, false
Boolean

Java character (single quoted) 'b', '\t', '\u2151' Character
Java integer literal (without suffix)
93, -3621
Integer

Java long literal (with L suffix) 293726L, -692L
Long

Java float literal (with f or F suffix)
0.332f, 62.2E6F
Float

Java double literal 283.0, -321E-3
Double
Must contain a decimal point or power of 10 to distinguish it from an integer literal.
Java null literal
null
null

Java string (double quoted)
"",
"hello\nmy name is Jeff"

String
Escape sequences are resolved.
Fully qualified class name
java.text.SimpleDateFormat
An instance of the class.
This uses reflection, so it may not be available to applets. The class must be a top-level, public class.
If the class has a public, static field named instance, the value of the field will be returned. Otherwise, default (no argument) constructor of the class is used to created the returned object.
Braced BeanShell Expression
{
  TimeZone.getDefault()
}
An object created by the BeanShell interpreter.
See Integration with BeanShell.

If used to convert resource bundle keys, the value mapped to the key is retrieved. If the value is a String, it will be converted as above. Otherwise, the value is returned immediately.

Collection Converters

String Conversion

A string can be converted to a collection of objects with an instance of com.taco.text.CollectionConverter. The constructor, CollectionConverter(IInterpolatingConverter converter), takes an instance of an interpolating converter that is used to convert substrings representing each of the elements of the returned collection.

The string syntax for a collection is:

[ element1 , element2 , ... ]

where element1, element2, etc. are strings that can be converted by the element converter. No elements need to specified at all, i.e. [] is a legal string denoting an empty collection. Whitespace before or after each comma is optional and ignored if present. What if the string for an element contains a comma? That's ok as long as the comma is enclosed in some kind of Java quoted or braced context. For example, consider converting the string

[ { foolish, brilliant }, "what's up, doc?" ]

The two strings sent to the element converter are { foolish, brilliant } and "what's up, doc?" since the comma between foolish and brilliant appears inside braces, and the comma in "what's up, doc?" is inside double quotes.

Example:

CollectionConverter converter = new CollectionConverter(AtomConverter.CLASS_CONVERTER);
String s = "[java.lang.String, java.util.Date]";
Collection classes = null;

try {
    classes = (Collection) converter.toObject(s, null, null, null);
} catch (Exception e) {
    assert false: "I always write perfect code so this is impossible";
}

At the end of this code, classes contains the class objects for String and Date.

Resource Bundle Key Conversion

Collection elements can also be read from the subkeys 0, 1, 2, etc. of a resource bundle key. CollectionConverter stops at the first missing subkey. This way of defining collections is useful because resource bundles can easily add or override individual elements of their parents.

Example:

Given a resource bundle property file:

languages.0=English
languages.1=Spanish
languages.2=Japanese

then the following code will create a collection of the three language names:

CollectionConverter converter = new CollectionConverter(QuotedStringConverter.instance);
Collection languages = null;
try {
    languages = (Collection) converter.toObject(bundle, "languages", null, null);
} catch (Exception e) {
    // Try to recover
    languages = new LinkedList();
}

Collections of three types of elements are particularly common, so the corresponding instances of CollectionConverter are static fields in CollectionConverter. These fields are:

Field name
Element Converter
INTEGER_COLLECTION_CONVERTER
AtomConverter.INTEGER_CONVERTER
STRING_COLLECTION_CONVERTER
QuotedStringConverter.instance
INSTANCE_COLLECTION_CONVERTER
InstanceConverter.DEFAULT_INSTANCE

One important use of INSTANCE_COLLECTION_CONVERTER is to initialize global variables. Many applications will convert the globals resource bundle key to initialize the globals used through the resource bundle. A base bundle might have a few  lines like this:

globals.0=&defBorder:{
  new javax.swing.border.MatteBorder(2, 2, 2, 2, Color.RED)
}

globals.1=&defColor:{
  new Color(127, 0, 127)
}

panel1.border=&defBorder
panel1.color=&defColor

panel2.border=&defBorder
panel2.color=&defColor

A child bundle (one whose parentBundle property is set to the base bundle, or a localized version of the same bundle, see ResourceBundles in Depth) can override the default border, and add a default font with the following lines:

#override base .0 subkey
globals.0=&defBorder:{
  new javax.swing.border.EtchedBorder()
}
#add new element
globals.2=&defFont:{

  new Font("Serif", Font.BOLD, 12)
}

panel1.font=&defFont

panel2.font=&defFont