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:
- 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.
- 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.
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.
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.
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