IBM

JavaBeans support in NetRexx - Draft

Please note: this document describes experimental features of the NetRexx compiler (NetRexxC). These features are not part of the NetRexx Language. The syntax and semantics described here are subject to change. Please send comments and suggestions to Mike Cowlishaw, mfc@uk.ibm.com.


Introduction

The JavaBeans specification describes a set of rules that define a subset of Java classes called JavaBeans. JavaBeans are intended for use as reusable software components, suitable for manipulation in builder tools.

This document describes features added to the NetRexxC compiler that make it easier to create JavaBeans, either by automating part of the process of writing a JavaBean or by providing compile-time checks that help you write correct JavaBeans.

This document is not a JavaBeans tutorial, although it does introduce some simple JavaBeans. It assumes you already understand the concepts included in the JavaBeans specification.

JavaBean properties

Almost all JavaBeans will have properties, which are data items that a user of a JavaBean is expected to be able to customize (for example, the text on a pushbutton). The names and types of the properties of a JavaBean are inferred from 'design patterns' (in this context, conventions for naming methods) or from PropertyDescriptor objects associated with the JavaBean. The JavaBean properties do not necessarily correspond to instance variables in the class - though very often they do. The JavaBean specification does not guarantee that JavaBean properties that can be set can also be inspected, nor does it describe how ambiguities of naming and method signatures are to be handled.

The NetRexxC compiler [as of 15 Feb 1997] allows a more rigorous treatment of JavaBean properties, by allowing an optional attribute of properties in a class that declares them to be indirect properties. Indirect properties are properties of a known type that are private to the class, but which are expected to be publicly accessible indirectly, though certain conventional method calls.

Declaring properties to be indirect offers the following advantages:

The next section describes the use of indirect properties in more detail.

Indirect properties

Properties are declared to be indirect using the indirect keyword on the properties instruction. For example, consider the simple JavaBean:

 class Sandwich extends Canvas implements Serializable
  properties indirect
    slices=Color.gray
    filling=Color.red

  method Sandwich
    resize(100,30)

  method paint(g=Graphics)
    g.setColor(slices)
    g.fillRect(0, 0, size.width, size.height)
    g.setColor(filling)
    g.fillRect(12, 12, size.width-12, size.height-12)

This declares the class as having two indirect properties, called slices and filling, both being of type java.awt.Color.

In the example, no access methods are provided for the properties, so the compiler will add them. By implementation-dependent convention, the names are prefixed with verbs such as 'get' and 'set', etc., and have the first character of their name uppercased to form the method names. Hence, in this Java-based example, the following four methods are added:

  method getSlices  returns java.awt.Color
    return slices
  method getFilling returns java.awt.Color
    return filling
  method setSlices($1=java.awt.Color)
    slices=$1
  method setFilling($2=java.awt.Color)
    filling=$2
(where $1 and $2 are 'hidden' names used for accessing the method arguments).

Note that the indirect attribute for a property is an alternative to the public, private, and inheritable attributes. Like private properties, indirect properties can only be accessed directly by name from within the class in which they occur; other classes can only access them using the access methods (or other methods that may use, or have a side-effect on, the properties).

Indirect properties may be constant or transient (the latter is an experimental attribute implying that the property should not be saved when an instance of the class is saved). They may not be static or volatile.

In detail, the rules used for generating automatic methods for a property whose name is xxxx are as follows:

  1. A method called getXxxx which returns the value of the property is generated. The returned value will have the same type as xxxx.
  2. If the type of xxxx is boolean then the generated method will be called isXxxx instead of getXxxx.
  3. If the property is not constant then a method for setting the property will also be generated. This will be called setXxxx, and take a single argument of the same type as xxxx. This assigns the argument to the property and returns no value.

If the property has an array type (for example, int[]), then it must only have a single dimension. Two further methods may then be generated, according to the rules:

  1. A method called getXxxx which takes a single int as an argument and which returns an item from the property array is generated. The returned value will have the same type as xxxx, without the []. The integer argument is used to index into the array.
  2. As before, if the result type of the method would be boolean then the name of the method will be isXxxx instead of getXxxx.
  3. If the property is not constant then a method for setting an item in the property array will also be generated. This will be called setXxxx, and take two arguments: the first is an int that is used to select the item to be changed, and the second is an undimensioned argument of the same type as xxxx. It assigns the second argument to the item in the property array indexed by the first argument, and returns no value.
For example, for an indirect property declared thus:
  properties indirect
    fred=foo.Bar[]
the four methods generated would be:
  method getFred returns foo.Bar[]; return fred
  method getFred($1=int) returns foo.Bar; return fred[$1]
  method setFred($2=foo.Bar[]); fred=$2
  method setFred($3=int, $4=foo.Bar); fred[$3]=$4

Note that in all cases a method will only be generated if it would not exactly override a method in a superclass or exactly match a method explicitly coded in the current class.

Explicit provision of access methods

Normally, for visible properties of a JavaBean, it is desirable to redraw the JavaBean when the property is changed (and in more complicated beans, there may be interactions between properties). These and other actions will require extra processing which will not be carried out by automatically generated methods. To add this processing the access methods will have to be coded explicitly. In the 'Sandwich' example, we only need to supply the 'set' methods, perhaps by adding the following to the example class above:

  method setSlices(col=Color)
    slices=col      -- update the property
    this.repaint    -- redraw the component

  method setFilling(col=Color)
    filling=col
    this.repaint

If we add these two methods, they will no longer be added automatically (the two 'get' methods will continue to be provided automatically, however). Further, since the names match possible access methods for properties that are declared to be indirect, the compiler will check the method declaration: the method signatures and return type (if any) must be correct, for example. Also, since the names of access methods are case-sensitive (in a Java environment), you will be warned if a method appears to be intended to be an access method but the case of one or more letters is wrong.

Specifically, the checks carried out are as follows:

  1. For methods whose names exactly match a potential access method for an indirect property (that is, start with 'is', 'get', or 'set', which is then followed by the name of an indirect property with the first character of the name uppercased):
  2. For methods whose names match a potential access method, as above, except in case:
These checks detect a wide variety of errors at compile time, hence speeding the development of classes that use indirect properties.

[ IBM home page | Search | Contact IBM | Help | Legal | Privacy ]