Jestr (Version 1.1)

JESTR:a Java Extensible Stringifier

See:
          Description

Packages
jestr This package contains the public API to Jestr.
jestr.conf.props Contains classes pertaining to property-file configuration of Jestr.
jestr.core Contains default implementations of the interfaces declcared in the "jestr" package.
jestr.examples.example1 This example illustrates default stringification.
jestr.examples.example2 This example shows how to override an existing toString() method.
jestr.examples.example3 This example illustrates enumeration stringification.
jestr.examples.example4 This example illustrates child filtering.
jestr.examples.example5 This example illustrates more advanced usage of the "standard" predicate.
jestr.examples.example6 This example illustrates initializer classes.
jestr.examples.example99 This is an example covering every feature including some experimental features.
jestr.generic.collection Contains general-purpose Collection-related utilities not specific to Jestr.
jestr.generic.exception Contains general-purpose Exception-related utilities not specific to Jestr.
jestr.generic.functor Contains general-purpose Functor-related utilities not specific to Jestr.
jestr.generic.io Contains general-purpose IO-related utilities not specific to Jestr.
jestr.generic.io.core Contains implementations of interfaces declared in jestr.generic.io.
jestr.generic.object Contains general-purpose Object-related utilities not specific to Jestr.
jestr.generic.oro.text.regex Contains general-purpose ORO-related utilities not specific to Jestr.
jestr.generic.reflect Contains general-purpose Reflection-related utilities not specific to Jestr.
jestr.generic.string Contains general-purpose string-related utilities not specific to Jestr.
jestr.generic.type Contains general-purpose type-related utilities not specific to Jestr.
jestr.multiLine Contains stringifiers for the multiline format, which lists an object's fields or a collection's elements in a manner akin to Java source code listings.
jestr.multiLine.collection Multiline Collection stringifiers.
jestr.multiLine.noncollection Multiline Non-Collection stringifiers.
jestr.singleLine Contains stringifiers for the single-line format, which places all of an object's attributes on one line in a manner suitable for input to text processing tools like awk, sed, and grep.
jestr.singleLine.collection Single-Line Collection stringifiers.
jestr.singleLine.noncollection Single-Line Non-Collection stringifiers.
jestr.test  
jestr.xml
jestr.xml.collection XML Collection stringifiers.
jestr.xml.noncollection XML Non-Collection stringifiers.
jestr.xml.test  

 

JESTR:a Java Extensible Stringifier

somers Jestr is an extensible, Open Source framework for converting arbitrary Java objects into strings for display or logging. The style of string conversion can be adjusted at runtime, either in a blanket fashion or just for individual classes, class hierarchies, and package hierarchies. Jestr is configurable using a properties file called "jestr.properties", which models "log4j.properties" and should look reasonably familiar to those accustomed to Log4J.

Below is a partial feature list:


To use Jestr, you just substitute Jestr.str(x) anywhere you are using x.toString() to create a string representation of object x for a call to the logger. For instance, assuming we are using Jakarta Commons Logging, we would just replace this:


    Account account = ...;
    if ( log.isDebugEnabled() ) {
        log.debug( "Here is my account: " + account );
    }

with this:


    import jestr.*;

    // ...

    Account account = ...;
    if ( log.isDebugEnabled() ) {
        log.debug( "Here is my account: " + Jestr.str(account) );
    }

or alternatively, you could modify the toString() method of Account to return Jestr.str(this) and leave the logging statement alone. The two approaches are functionally equivalent and the choice between them is a matter of style.

If Account is declared as follows:


    public class Account {
        private double currentBalance = 100.0;
        private double endingBalance = 62.44;
        private double ledgerBalance = 89.75;
        private String currencyCd = "USD";
        private String id = "123";
    }

then the above logging statement would log the following:


    Here is my account: Account(
        double currentBalance = 100.0
        double endingBalance = 62.44
        double ledgerBalance = 89.75
        String currencyCd = "USD"
        String id = "123"
    )

If the default configuration is acceptable, then this is all you need to do. However, Jestr accepts an optional properties file that lets the user define specific stringifiers for individual classes, class hierarchies, packages, or package hierarchies, as well as to declare custom stringifiers and other objects for unique circumstances.

Motivation

It is common practice in Java programming to override the toString() method of a class to return a listing of the class' attributes so that they may be logged. However, suppose your class needs to be integrated into a larger enterprise application that may define its own logging standards. In this case your hand-coded toString() method will likely not conform to those standards. It is preferable to defer the determination of logging format to the developers, and ultimately to the administrators, of this larger application. Jestr supports this approach by making it possible to strategize the stringification procedure so that different stringifiers can be selected at runtime based on the particular needs of the application and circumstances at hand.

This deferral of selection of a stringification format can be done for any classes, even those that were never designed to work with Jestr, and for which source may or may not be available. If you log such objects using "Jestr.str(x)" instead of "x.toString()", then the current configuration will dictate whether the legacy toString() should be called, or the class' attributes are to be listed individually, or that perhaps some other disposition should be chosen.

Configuration

System properties

The behavior of Jestr is influenced by the following system properties:

Name Required Default Description
jestr.configuration No "jestr.properties", first in the current directory and then in the CLASSPATH Explicitly defines the path to the Jestr configuration file. If this file is unreadable, Jestr will log a warning and continue with the default configuration.
jestr.configuration.reread.interval No 5000 Defines the interval in milliseconds at which the configuration file will be examined to see if its modification timestamp has changed; if the timestamp has changed, Jestr will reread it. To disable rereading of the configuration file, set this to 0.

Configuration File

The following tables list all the properties that may appear in the Jestr configuration file. Note Jestr only considers properties starting with "jestr." and ignores all others.

Stringifier Configuration

Property Syntax Required Applies to Description Examples
jestr.stringifier.name=(className|clone-of-sourceName) Yes All stringifiers Declares a stringifier. If a className is given, this class' no-arg constructor is invoked, while if sourceName is given, the named stringifier is cloned. In either case the new stringifier is called name, and may be referenced by this name in other directives. A library of builtin stringifiers is included with Jestr, and can be referenced by either class or name; or you can write your own custom stringifiers. All stringifiers must implement jestr.Stringifier. Example 3,
Example 4,
Example 5
jestr.stringifier.name.priority=priority No All stringifiers Sets the priority of stringifier name to priority. The priority can be an integer from Integer.MIN_VALUE to Integer.MAX_VALUE. Lower priority stringifiers are given preference to higher priority ones. If omitted, the priority defaults to zero. None
jestr.stringifier.name.predicates=predicateName{,predicateName}* No All stringifiers Sets stringifier name to use the given list of predicates. For each predicateName listed, a predicate should be registered with this name, either as a builtin or via the "jestr.predicate" directive, or Jestr will emit a warning and ignore the predicate reference. At runtime the predicates will be evaluated in the order listed, and a logical OR performed among their values, such that the associated stringifier will be selected if and only if at least one of the predicates evaluates to true. Example 5
jestr.stringifier.name.childFilter=childFilterName No All stringifiers Sets stringifier name to use Child Filter childFilterName. A Child Filter with this name should be registered via a "jestr.childFilter" directive or Jestr will emit a warning and ignore this directive. Example 4
jestr.stringifier.name.maxDepth=maxDepth No All stringifiers Sets the depth limit of stringifier name to maxDepth. The listing of the object graph will go no further than this depth. If omitted, no depth limit is imposed, though the stringification will never infinitely recurse because cycles in the object graph are automatically detected and result in limiting the depth at the point where the cycle is detected. None
jestr.stringifier.name.classDeclaringConstants=className No enum Defines the name of the class that declares constants assigning mnemonic codes to the values of an enumerated type. The "enum" stringifier will look for fields that are declared static and final, and will compare their values to the value of the enumerated object it is stringifying. If no match can be found, enum will substitute the string "<<unmapped>>" for the mnemonic. Example 3
jestr.stringifier.name.constants=constant=value{,constant=value}* No enum Explicitly defines the name/value pairs to use for mapping of an enumerated type's value to its corresponding constant name. This property overrides the "classDeclaringConstants" property if both are present. Example 3
jestr.stringifier.name.format=msgFormat No enum Specifies a java.text.MessageFormat style format string that dictates how the enumerated type should print. Two parameters will be supplied to this format: the mnemonic at position 0, and the value at position 1. If omitted, the format is effectively "{0} ({1})". If, when the enumerated value is printed, no matching mnemonic can be found, enum will pass the string "<<unmapped>>" for argument {0}. None
jestr.stringifier.name.dateFormat=dateFormat No date Specifies a java.text.SimpleDateFormat style date format string that dictates how a java.util.Date instance will be stringified. If omitted, java.util.Date's toString() method is called, which in turn applies a locale-specific default. Example 5
jestr.stringifier.name.format=msgFormat No stringLiteral,
character,
silence,
boolean,
integer,
double,
long,
singleLineNull,
charArray,
byteArray
and multiLineNull
Specifies a java.text.MessageFormat style format string that dictates how the object should print. The parameter passed as "{0}" is the object to be formatted. If omitted, the default is as indicated in the "Builtin Objects" table. None
jestr.category.categoryName=stringifierName[@priority]{,stringifierName[@priority]}* No All stringifiers Associates the named stringifier(s) with category categoryName. This means that any object whose full class name begins with categoryName, or any of whose ancestors' full class names begin with categoryName, will be matched by the stringifier(s) predicate(s). A stringifier with this name should exist, either as a builtin stringifier or as a result of registration via a "jestr.stringifier" directive, or Jestr will ignore the "jestr.category" directive and log a warning.

You can specify the priority at which the stringifier is to be registered with the "@priority" syntax. This will override the priority you may have assigned in the "jestr.stringifier" directive via the priority property.

Any stringifier you list here may have a predicate already assigned in its "jestr.stringifier" directive via the "predicate" property. If so, then the category condition will be AND'ed in with the existing predicate, such that the stringifier will match if and only if both the category and any previously defined predicate must hold for the stringifier to be selected.

Example 2,
Example 4

JestrPredicate Configuration

A stringifier's predicate is evaluated to determine if it should be used to stringify a given object. A predicate is an expression that evaluates to true or false. A predicate class must implement the interface JestrPredicate. You can write your own predicates of arbitrary complexity, but in most cases you will find the standard predicate "standard" is all you need in the vast majority of cases.

Property Syntax Required Applies to Description
jestr.predicate.name=(className|clone-of-sourcePredicateName) Yes All predicates Declares a predicate. If a className is given, this class' no-arg constructor is invoked, while if sourcePredicateName is given, the named predicate is cloned. In either case the new predicate is called name and may be referenced by this name elsewhere. A standard predicate is included with Jestr, or you can write your own custom predicates. The predicate "standard", whose class is "jestr.core.DefaultStandardPredicate" provides reasonable default behavior and can be used in most cases.
jestr.predicate.name.name=objectName No standard Specifies that the object's "name" must exactly match objectName.

If omitted, then the name portion of the predicate is inactive and plays no part in determining the predicate's final result.

jestr.predicate.name.nameIncludes=pattern{,pattern}* No standard Defines a set of one or more Perl 5 regular expressions, at least one of which the object's name must match in order to satisfy the predicate. If omitted, then the nameIncludes portion of the predicate is inactive and plays no part in determining the predicate's final result.
jestr.predicate.name.nameExcludes=pattern{,pattern}* No standard Defines a set of one or more Perl 5 regular expressions, none of which the object's name can match if the predicate is to be satisfied. If omitted, then the nameExcludes portion of the predicate is inactive and plays no part in determining the predicate's final result.
jestr.predicate.name.classes=classname{,classname}* No standard Defines a set of one or more classes or interfaces, at least one of which an object must extend or implement in order to satisfy the predicate. If omitted, then the classes portion of the predicate is inactive and plays no part in determining the predicate's final result.
jestr.predicate.name.parentClasses=className{,className}* No standard Defines a set of one or more classes or interfaces, at least one of which an object's "parent" must extend or implement in order to satisfy the predicate. An object's parent is the object that aggregates it, either as a field or as an element in a collection. If omitted, then the parentClasses portion of the predicate is inactive and plays no part in determining the predicate's final result.
jestr.predicate.name.isRoot=isRoot No standard Specifies that the object must either have a parent (if isRoot is "false") or not (if isRoot is "true") in order to satisfy the predicate. If omitted, then the isRoot portion of the predicate is inactive and plays no part in determining the predicate's final result.

NOTES:


Child Filter Configuration

Child filters are used for defining which of an object's fields, or of a collection's elements, should be included in the stringified form. By default all nonstatic fields are included, as are all elements of a collection, map, or array. A standard Child Filter is included with Jestr, or you can write your own custom Child Filters. The Child Filter "regex", whose class is "jestr.core.DefaultRegexChildFilter" provides Perl 5 regular expression filtering with name substitution.


Property Syntax Required Applies to Description Examples
jestr.childFilter.childFilterName=(className|clone-of-sourceChildFilterName) Yes All Child Filters Declares a Child Filter. If a className is given, this class' no-arg constructor is invoked, while if sourceChildFilterName is given, the named Child Filter is cloned. In either case the new Child Filter is called childFilterName and may be referenced by this name elsewhere. All child filters must implement the interface jestr.ChildFilter. Example 4
jestr.childFilter.childFilterName.substitutions=pattern=replacement{,pattern=replacement}* No regex Defines a list of substitutions to perform on the name of each child. Each substitution consists of a Perl 5 regular expression coupled with a Perl 5 substitition. Substitutions will be applied in the order listed. Example 4
jestr.childFilter.childFilterName.nameExcludes=pattern{,pattern}* No regex Defines a set of one or more Perl 5 regular expressions, such that if the child's name matches any of these expressions, it will be excluded from the stringification processing. Note that processing of "nameExcludes" is done after processing of "substitutions", so the child names considered for exclusion are the names after all substitutions have been processed. Example 4

Initializer Configuration

An initializer is a class that can be registered to perform custom initialization tasks not possible through the property file interface. All initializers implement the interface jestr.conf.props.Initializer and declare a public no-arg constructor. Initializers are registered via the following properties:

Property Syntax Description
jestr.preInitializers=className{,className}* Defines a list of one or more initializer classes. Before any properties have been processed, the framework will instantiate each using its no-arg constructor and then call Initializer.preInitialize(). Initializers are processed in the order listed.
jestr.postInitializers=className{,className}* Defines a list of one or more initializer classes. After all properties have been processed, the framework will instantiate each class using its no-arg constructor and then call Initializer.postInitialize(). Initializers are processed in the order listed.

Builtin Objects

Jestr includes various builtin stringifiers and other objects that you can use either as-is or through extension.
Type Name Aliases Class Description
Stringifier default None jestr.core.DefaultStringifier A "blank" stringifier that you can clone and add attributes to. Provides only empty stringification in its own right.
Stringifier enum None jestr.core.EnumStringifier Formats values of enumerated types so that they show as their corresponding names.
Stringifier singleLineNull null jestr.singleLine.SingleLineNullObjectStringifier Stringifies object references that are null (i.e., don't reference anything) in the single-line format. The default format is "<<null>>" but you can change this via the "format" property.
Stringifier multiLineNull None jestr.multiLine.MultiLineNullObjectStringifier Stringifies object references that are null (i.e., don't reference anything) in the multi-line format. The default format is "null" but you can change this via the "format" property.
Stringifier xmlNull null jestr.xml.XMLNullObjectStringifier Stringifies object references that are null (i.e., don't reference anything) in the xml format. The default format is "<<null>>" but you can change this via the "format" property.
Stringifier character char jestr.core.CharacterStringifier Formats character literals. The default format is "''{0}''" but you can change this via the "format" property.
Stringifier boolean None jestr.core.BooleanStringifier Formats booleans. The default format is "{0}" but you can change this via the "format" property.
Stringifier integer int jestr.core.IntegerStringifier Formats integers. The default format is "{0}", but with special logic for Integer.MIN_VALUE and Integer.MAX_VALUE so that these print as these constants instead of the actual numbers. You can change this behavior via the "format" property.
Stringifier long None jestr.core.LongStringifier Formats longs. The default format is "{0}", but with special logic for Long.MIN_VALUE and Long.MAX_VALUE so that these print as these constants instead of the actual numbers. You can change this behavior via the "format" property.
Stringifier double None jestr.core.DoubleStringifier Formats doubles. The default format is "{0}", but with special logic for Double.MIN_VALUE and Double.MAX_VALUE so that these print as these constants instead of the actual numbers. You can change this behavior via the "format" property.
Stringifier stringLiteral string jestr.core.StringLiteralStringifier Formats string literals. The default format is ""{0}"" but you can change this via the "format" property.
Stringifier date None jestr.core.DateStringifier Formats java.util.Date instances according to a date format you can specify.
Stringifier cycle None jestr.core.DefaultCycleStringifier Generates a description of a cyclic reference in the object graph. These references cannot actually be followed, but this stringifier, or any stringifier implementing the special tagging interface jestr.CycleStringifier, is called upon to print an indication that a cycle was encountered. The default implementation prints the string "<<cycle>>".
Stringifier byteArray None jestr.core.ByteArrayStringifier Stringifies a byte[]. By default the first 10 bytes in the array are listed in decimal form separated by commas, but you can change this via the "format" property.
Stringifier charArray None jestr.core.CharArrayStringifier Stringifies a char[]. The default format prints char arrays just like strings, but you can change this via the "format" property, which is invoked with a java.lang.String equivalent of the char array as argument {0}.
Stringifier silence None jestr.core.SilenceStringifier Omits stringification of any matching object. The default format is "<<omitted>>", but you can change this via the "format" property.
Stringifier tsDefault None jestr.core.TSDefaultStringifier Defines the default approach to choosing between a class' builtin toString() method and Jestr framework stringification. This default dictates that toString() should be called if and only if it is overridden by the class itself, or by any superclass besides java.lang.Object.
Stringifier tsNotPreferred None jestr.core.TSNotPreferredStringifier Causes any matching object to be stringified without using its builtin toString() method even if one exists.
Stringifier tsPreferred None jestr.core.TSPreferredStringifier Causes any matching object to be stringified using its builtin toString() method.
Stringifier nonCollectionSingleLine singleLine jestr.singleLine.noncollection.Noncollection-
SingleLineStringifier
Causes any matching object to be stringified by listing its fields all on one line, separated by '|' characters, in a manner suitable for input to text processing tools. Intended to be used for non-collections.
Stringifier collectionSingleLine None jestr.singleLine.collection.Collection-
SingleLineStringifier
Causes any matching collection to be stringified by listing its elements all on one line, separated by '|' characters, in a manner suitable for input to text processing tools. Intended to be used for arrays and objects that implement Collection or Map. If used for other objects, fields will be ignored.
Stringifier nonCollectionXML xml jestr.xml.noncollection.Noncollection-
XMLStringifier
Causes any matching object to be stringified to XML format. Intended to be used for non-collections.
Stringifier collectionXML None jestr.xml.collection.Collection-
XMLStringifier
Causes any matching collection to be stringified to XML format. Intended to be used for arrays and objects that implement Collection or Map. If used for other objects, fields will be ignored.
Stringifier nonCollectionMultiLine multiLine jestr.multiLine.noncollection.Noncollection-
MultiLineStringifier
Causes any matching object to be stringified by listing its fields vertically similarly to a Java program listing. Multiline is the default stringification format. Intended to be used for non-collections.
Stringifier collectionMultiLine None jestr.multiLine.collection.Collection-
MultiLineStringifier
Causes any matching collection to be stringified by listing its elements vertically similarly to a Java program listing. Multiline is the default stringification format. Intended to be used for arrays and objects that implement Collection or Map. If used for other objects, fields will be ignored.
Child Filter regex default jestr.core.DefaultRegexChildFilter Supports filtering based on Perl 5 regular expressions.
JestrPredicate standard default jestr.core.DefaultStandardPredicate General-purpose predicate; see "standard" predicate above for information on properties supported.
JestrPredicate isCollection None jestr.core.IsCollectionPredicate Tests whether the object is a Collection, Map or array.
JestrPredicate isNonCollection None jestr.core.IsNonCollectionPredicate Evaluates to the opposite of "isCollection".

Examples

Various examples are included in the package "jestr.examples". You will also find a shell script in the root directory of the distribution for running each example.

Follow these links for example details:

Example 1 - Default stringification.

Example 2 - Overriding an existing toString() method.

Example 3 - Enumerated types.

Example 4 - Child filtering.

Example 5 - "standard" predicate.

Example 6 - Initializers.

Downloading

Jestr is part of the Java Foundry on SourceForge.net. Its project page is www.sourceforge.net/projects/jestr, and its home page is jestr.sf.net. The latest tarballs are:

Installation

To install Jestr, add the jestr-1.1.jar file, included with the distribution, to your CLASSPATH. You will also need all the jars that Jestr uses in your CLASSPATH. Jestr depends heavily on the Jakarta components, specifically the following: The above jars are included in the distribution under the jars directory.

You will also need any logger implementation compatible with Commons Logging. Log4J is the most commonly used such logger, and can be downloaded from the Log4J site. A recent copy is also included in the jars directory.

Jestr is compatible with Java 1.4.2 or higher.

Documentation

Javadoc's are available online here, and are included in the docs/api directory under the root of the distribution.

Building from Source

To build Jestr from source, download and extract the source tarball and run "ant" in the root of the source distribution. This will build the binary distribution complete with Javadoc's and place it in the dist directory.

License

Jestr is Open Source software released under the Apache Software License.

Contributing, Bug Reports, Feature Requests

To contribute to Jestr, or to submit a bug report or feature request, contact the Jestr Project Administrator.




Copyright (c) 2001-2003 - Apache Software Foundation