Troubleshooting / Frequently Asked Questions

General

What are the overhead costs of using the text2gui library?

There is some overhead memory and execution time cost of initializing the text2gui library, then using it to construct a component hierarchy by parsing a resource bundle. However, it is not as pronounced as other products that convert text into component hierarchies for the following reasons:
Of course, if a BeanShell script are embedded in a description, there is an additional cost of initializing BeanShell, and using it to interpret the script. As the number of these scripts is usually not large, the cost of using BeanShell is modest.

Once a component hierarchy is created, the components behave just as fast as they would if constructed manually. This is because instances of the actual Swing components are created, not proxies for Swing components. The cost of communicating with a component hierarchy through an argument map after construction is not noticeable to the user, because so few map keys are updated per time period.

Listeners implemented by BeanShell scripts embedded in a resource bundle description do run slower than comparable listeners implemented with compiled Java code. Again, this is typically not noticable since listeners are notified infrequently and they don't do much besides making a few calls to other objects. (If a listener calls a method implemented with compiled Java code, the method runs just as fast as if it were called by compiled code.)

I have not found the startup and response times to be significantly more than if components were created with Java code, and all listeners were implemented with Java code.

Why doesn't text2gui use XML to describe component hierarchies, like other products?

XML has the advantage that its general syntax is well-known, and that specializations of the syntax can be specified with a simple text file, the Document Type Declaration (DTD). However, XML has the following disadvantages compared to the text2gui syntax:
The text2gui syntax was designed specifically for describing component hierarchies, so it is no surprise that it is more suitable for this purpose than XML.

How big are the library files I need to ship with my application so it can use the text2gui library?

The text2gui library is about 600 KB. In order for BeanShell to work, you also need to ship the BeanShell library, which is about 300 KB. (It is possible to reduce the size by getting a subset of the BeanShell functionality, see the BeanShell homepage for details.) If you already use log4j, there's no need to account for the size of the log4j library, but if you don't, you can just ship the facade version of the log4j library which is only 1 KB. So the total extra size, under ordinary circumstances, would be about 900 KB.

Can I use the text2gui library for applets?

Yes! But be aware that BeanShell won't work in most applet environments, due to its reliance on reflection which is a security risk. You can circumvent this problem by signing your applet, then having the user grant all privileges to it.

Since BeanShell scripts won't work, you'll have to perform all code using ordinary Java code. This includes implementing all listeners and all from and to map converters. It would probably be wise just put the value needed by the component converters directly in the map, without relying on any conversion routines. This may breakdown some of the separation between the model and view/controller, but it's a good compromise.

Remember you can always just use the text2gui library to perform component construction, then pick out the components you want to control from the global variable space. You aren't forced to use the MVC architecture if it's too painful.

What IDE's can I use with text2gui?

Unlike other tools which aid Swing development, the text2gui library and development kit is IDE independent. You can use any IDE to edit the Java code that calls the text2gui library or text2gui descriptions of component hierarchies. After all, these are just text files!

For testing components described with text2gui code, the text2gui development kit supplies the GUI Editor application which makes testing a breeze! But you are in no way forced to use it.

After describing your component hierarchies with text2gui code, and testing them immediately with the GUI Editor, you'll find other GUI construction tools very clumsy. No mouse dragging, resizing, searching for the right property to change, etc. is required. Contrary to the adage, "A picture is worth a thousand words", editing text is still the easiest way of programming.

How do I use text2gui to create my own subclass of a component class?

You might want to create your own subclass of Component so that others can easily use your class in their component hierarchies. But using text2gui to manually create each of the individual child component and property values would be a pain. The solution is to use text2gui to configure your subclass of Component. Configuration can set the contents and some of the property values of your component, but it obviously can't handle the new property values specific to your subclass. The management of these properties must be done with your subclass.

See
Composite Configuration with a Dispatching Converter for details on how to configure an instance of a composite object -- in this case you would be configuring the this pointer.

If you have the development kit already, the source code for com.taco.swinger.FontChooser provides an example of doing this.

Can I use the text2gui infrastructure to create instances of a custom type?

Yes! There are a variety of reasons to do this. You may simply want to convert keys in resource bundles to objects directly used by your application. Or you may want to install your own kind of component/border/layout converter so that your component hierarchy descriptions can use them.

Sometimes the conversion process doesn't require any parameters, for example, when you need to create an object used as a single property value. If the object created by conversion is identical each time the conversion process runs, you can simply use the instance converter, and specify an object created by a BeanShell script.

If you want the conversion process to be able to accept parameters, you can still use the text2gui library to help you, but you'll have to write some of your own Java code. text2gui can handle the details of resolving references, assigning to globals, etc. for you. If you want to create an atomic converter (a converter that creates objects with no properties), create a class, say StringToX, that implements com.taco.text.IStringToObjectConverter. All you need to do is specify how a literal string (not a reference) is converted to an object. Then pass an instance of StringToX to the constructor of
com.taco.text.AtomicConverter. You now have an interpolating converter to instances of class X.

To create a composite converter, the easiest way is to implement com.taco.text.BracedPropertyCompositeConverter. It converts resource bundle keys and strings with the braced property syntax. Then override the following methods:
  1. Object _createComposite(Map propertyMap, ResourceBundle bundle, INoReturnMap argMap): create a new instance of the object, using the creation properties in property map.
  2. Collection _getCreationPropertyNames(): return a collection of names of the creation properties of the composite. The order of the names is the order in which the values will be created.
  3. Collection _getPropertyNames(): return a collection of names of the ordinary properties of the composite. The order of the names is the order in which the values will be created.
  4. IInterpolatingConverter _getConverterForProperty(String propertyName, Object composite): return the converter used to convert strings and resource bundle keys to values for the (possibly creation) property with the argument name.
  5. CompositeConverter.ISetPropertyAction _getActionForProperty(String propertyName): Return a strategy for setting the property with the argument name. If you can afford the runtime cost of reflection, you can return CompositeConverter.ReflectionSetPropertyAction.instance. If no action is to be taken, return null.
  6. (Advanced) void _addMapConsistencyListener(Object composite, String propertyName, IObjectMapper toMapValueConverter, INoReturnMap argMap, Object mapKey, Method addListenerMethod):  Add a listener to the composite that ensures map consistency on the argument map key mapKey, for the property named propertyName. If your composite object notifies property change listeners when its propertyName property is changed, you can just use the superclass's implementation. Otherwise, you will need to add a listener to your composite that updates the argument map when the propertyName property is changed.

    If your listener extends CompositeConverter.AbstractMapConsistencyListener, you can just use the _put(Object value) method to put the new property value into the argument map. It takes care of delayed values and to map conversion using toMapConverter.

    If no map consistency is possible or required, just return null.
It's also possible to leverage the composite converter class for a subclass of the class you are trying to create. Let's say a converter for class X exists in the text2gui library. Then it would have the name XConverter. Now let's say you want to create a converter for class Y, which extends X. Then you should create a converter class YConverter that extends the class XConverter. You would still need to implement the methods above, but the implementations would only need to handle the properties that Y has but X does not. For the methods 4-6, you can use the superclass's method by calling super.XXX() to handle the X's properties.

If you want your component/layout/border converter to be used by the default component/layout/border dispatching converters, you need to install them in the DEFAULT_INSTANCE field of the corresponding class. See Installing Types in a Dispatching Converter for details.

If you want to use a custom string syntax, you can extend com.taco.text.CompositeConverter instead. You'll need to implement the methods 1-6 above, and also implement the method
Object _literalToObject(String s, ResourceBundle bundle, 
INoReturnMap argMap, String globalName)
The nextValue() methods in com.taco.text.StringConverterUtilities may help you in your implementation.

Setup & Distribution Issues

Must I use log4j? Must I ship it with my application that uses text2gui?

The text2gui library does make calls to the log4j library, but only the most basic calls. All of the calls can be handled by the tiny facade library lib/facade/log4jfacade.jar. The facade library simply redirects logging requests to the java.util.logging package so you will still get log output. You may ship log4jfacade.jar with your application. Of course, you can always use and ship the full version too.

To run the GUI Editor, the full log4j library is required to be in the class path.

Conversion Issues

When I try to convert a resource bundle key, an error occurs. Why?

Remember that if a value is mapped directly to the resource bundle key, that value will be used as the result of conversion, regardless of the subkeys that are set. Check that a parent resource bundle doesn't set the key directly.

At least one subkey of a resource bundle key must be set if no value is mapped directly to the resource bundle key. If no properties need be set right away, you may need to set a "dummy" property like name, which has no effect:

textfield.name=Dummy
#text is set later by Java code

If the object you're trying to convert is a component, layout, or border, be sure to set the dispatchType subkey so the dispatching converter knows what specific type of component, layout, or border converter to use.

I can't seem to be able to set a property of a composite object using a subkey of a base resource bundle key.

Are you sure the base key isn't defined, possibly in a parent bundle? If so, the subkeys will be ignored. See Composite Converters.

How are types handled by the text2gui library?

Notice that the result of argument map interpolation, global variable interpolation, and BeanShell scripts may be any instance of Object. This means, for example, the string converter might return an instance of Integer! This normally indicates a bug, but sometimes this is a good thing. Even though the Image Icon converter normally returns an instance of ImageIcon, by using it to convert an argument map key, it can return an instance of Icon instead, which is all that is needed for the icon property of a label. Many of the properties of components are documented with the note: "May also be set with an instance of X". This means if the property value comes from an argument map reference or a BeanShell script, the value can also be an instance of X in addition to the type ordinarily created by the property value converter.

text2gui does very little type checking. If you attempt to set a property with the wrong type, the exception usually occurs at the setXXX() method of the component. These kinds of exceptions will be caught, a warning will be logged, and conversion will continue.

Argument Map Issues


Map consistency doesn't seem to be working.

Be sure that the property that you want to be map consistent can actually be made map consistent -- only properties of composite objects can be map consistent, and not all composite properties can be made map consistent either. Check the converter table for the object type you are trying to convert.

Remember that for a property to be map consistent, a w must appear after a colon (':') after the argument map key name, e.g. name:w.

Isn't there an infinite recursion if a map key is both updatable and consistent?

Excellent question! You'd think there would be in the following situation: a property p of of a composite object is updated when the value associated with argument map key key is changed, and key is kept consistent with p. Then the following sequence of events unfolds:
  1. The programmer updates the value mapped to key in the argument map.
  2. The updater listener installed in the argument map updates the property value for property p of the composite.
  3. The map consistency listener installed in the composite updates the value mapped to key in the argument map.
Notice steps 1 & 3 are the same! We have an infinite recursion, at least that's what you'd think. But this doesn't really occur. Map consistency listeners are careful only to notify listeners that are not updater listeners. Thus no infinite recursion occurs. If you implement your own map consistency listeners, you must be sure to do the same thing. The easiest way to do this is to have your map consistency listener extend CompositeConverter.AbstractMapConsistencyListener. Then use the _put(Object value) method to put the new value in the argument map. _put() is careful only to notify the non-updater listeners of the argument map.

So in summary, it's perfectly acceptable for an argument map key to be both updatable and consistent.

Can a property be updated based on more than one argument map key?

At the moment, no. We are thinking about implementing this feature in a future release. If you think this feature would be useful for your application, please let us know by e-mailing suggest@tacosoftware.com.

Which properties use delayed values?

This information is intentionally hidden from the user to allow freedom in implementation, but I will say that the values property of JTable does use delayed values, so you might want to use an instance of DelayedResultObservableMap if you listen for changes to table values.

BeanShell Issues

My BeanShell scripts aren't working! Why not?

First of all, ensure that the real BeanShell library (not the facade version) is in your classpath during execution. To test for this, you can try java bsh.Interpreter from the command-line.

Are you having trouble with particular scripts? BeanShell is sensitive to the current directory when importing classes. It might not be able to import a class if you run the application in a directory containing .class files with the same name. Therefore you should debug and run your application either from the root of the classpath for your project, or in a directory that contains no .class files in it or any of its subdirectories.

If you're running an applet, unless your applet is signed and the user accepts weaker security, all BeanShell scripts are pretty much doomed to fail. Avoid BeanShell when developing applets. You should use the facade version of the BeanShell library, which simply throws exceptions when requests are made to interpret BeanShell scripts, because you won't be able to use BeanShell scripts anyway, and the facade version is much smaller.