Recognised Annotations

This section defines the set of annotations that are recognised by the Naked Objects Java Programming Model.

@ActionOrder

Note: The recommended mechanism for specifying the order in which actions are listed to the user is @MemberOrder (see below). @ActionOrder provides an alternative mechanism, in which the order is specified in one place in the class, with the added advantage (currently) that you can easily specify groupings (which may be rendered by the viewer as sub-menus). However, @ActionOrder is more 'brittle' to change: if you change the name of an existing action you will need to ensure that the corresponding name within the @ActionOrder annotation is also changed.

The syntax is: @ActionOrder("<comma separated list of action names>") (the action names are not case sensitive).

For example:

@ActionOrder("PlaceNewOrder, CheckCredit")
public class Customer {

    public Order placeNewOrder() {}

    public CreditRating checkCredit() {}

...
}

Actions can be grouped together by surrounding the group with brackets, and prefixing the group with name and colon. This information may be used by the viewing mechanism to render actions into sub-menus. For example:

@ActionOrder("(Account Management: PlaceOrder, CheckCredit), (Personal Details: ChangeOfAddress, AddEmail)")
public class Customer {

    public Order placeNewOrder() {}

    public CreditRating checkCredit() {}

    public void changeOfAddress() {}

    public void addEmail(String emailAddress) {}

    ...
}

@Bounded

For immutable objects where there is a bounded set of instances, the @Bounded annotation can be used. For example:

@Bounded
public class County {
    // members and actions here
}

The number of instances is expected to be small enough that all instance can be held in memory. The viewer will use this information to render all the instances of this class in a drop-down list or equivalent. (Note: Although this is not enforced, @Bounded is intended for use on final classes. Its behaviour when used on interfaces, or classes with sub-classes is not specified).

@Debug

The @Debug annotation marks an action method as available in debug mode only, and so will not normally be displayed by the user interface.

@DescribedAs

The @DescribedAs annotation is used to provide a short description of something that features on the user interface. How this description is used will depend upon the viewing mechanism - but it may be thought of as being like a 'tool tip'. Descriptions may be provided for objects, members (properties, collections and actions), and for individual parameters within an action method. @DescribedAs therefore works in a very similar manner to @Named.

Providing a description for an object

To provide a description for an object, use the @DescribedAs annotation immediately before the declaration of that object class. For example:

@DescribedAs("A Customer who may have originally become known to us via " +
             "the marketing system or who may have contacted us directly.")
public class ProspectiveSale {
   ...
}

Providing a description for a member

Any member (property, collection or action) may provide a description. To specify this description, use the @DescribedAs annotation immediately before the declaration of that member. For example:

public class Customer {
    @DescribedAs("The name that the customer has indicated that they wish to be " +
                 "addressed as (e.g. Johnny rather than Jonathan)")
    public String getFirstName() { ... }
}

Providing a description for an action parameter

To provide a description for an individual action parameter, use the @DescribedAs annotation in-line i.e. immediately before the parameter declaration. For example:

public class Customer {
    public Order placeOrder(
                      Product product,
                      @Named("Quantity")
                      @DescribedAs("The quantity of the product being ordered")
                      int quantity) {

        Order order = new Order();
        order.modifyCustomer(this);
        order.modifyProduct(product);
        order.setQuantity(quantity);        
        return order;
    }
    ...
}

@Disabled

The @Disabled annotation means that the member cannot be used in any instance of the class. When applied to the property it means that the user may not modify the value of that property (though it may still be modified programmatically). When applied to an action method, it means that the user cannot invoke that method. For example:

public class Customer {
    @Disabled
    public void assessCreditWorthiness() { ... }

    @Disabled
    public int getInitialCreditRating(){ ... }
    public void setInitialCreditRating(int initialCreditRating) { ... }
}

Note that if an action is marked as @Disabled, it will be shown on the user interface but cannot ever be invoked. One possible reason to do this is during prototyping, to indicate an action that is still to be developed. If a method is intended for programmatic use, but not intended ever to be invoked directly by a user, then it should be marked as @Hidden instead.

This annotation can also take a single parameter indicating when it is to be hidden, for example the following code would disable the action until the object has been saved.

public class Customer {
    @Disabled(When.UNTIL_PERSISTED)
    public void assessCreditWorthiness() { ... }
}

The acceptable values for the parameter are: When.ALWAYS, When.NEVER, When.ONCE_PERSISTED and When.UNTIL_PERSISTED. By default the annotated property or action is always disabled i.e. it is implicitly When.ALWAYS.

@Executed

The @Executed annotation overrides the default location where a method is executed.

Forcing a method to be executed on the client

The @Executed(Where.LOCALLY) annotation marks an action method so that it executes on the client, rather than being forwarded to the server for execution. This is useful for methods that invoke a service that must be run client-side, for example spawning off a separate process (such as a web browser or Acrobat Reader).

Forcing a method to be executed on the server

The @Executed(Where.REMOTELY) annotation marks an action method so that it executes on the server, even though it would normally be executed on the client (as methods for transient objects are). This is useful for methods that although based on transient objects need access to persistent objects.

@Exploration

The @Exploration annotation marks an action method as available in exploration mode only, and therefore not intended for use in the production system

@FieldOrder

Note: The recommended mechanism for specifying the order in which fields are listed to the user is @MemberOrder (see below). @FieldOrder provides an alternative mechanism, in which the order is specified in one place in the class. However, @FieldOrder is more 'brittle' to change: if you change the name of an existing property you will need to ensure that the corresponding name within the @FieldOrder annotation is also changed.

The syntax is: @FieldOrder("<comma separated list of field names>") (the field names are not case sensitive.).

For example:

@FieldOrder("Name, Address, DateOfBirth, RecentOrders")
public class Customer {

    public Date getDateOfBirth() {...}

    public List<Order> getRecentOrders() {...}

    public String getAddress() {...}

    public String getName() {...}

    ...
}

@Hidden

The @Hidden annotation indicates that the member (property, collection or action) to which it is applied should never be visible to the user. For example:

public class Customer {
    private int internalId;

    @Hidden
    public int getInternalId() {
        return internalId;
    }

    @Hidden
    public void updateStatus() { ... }
}

This annotation can also take a single parameter indicating when it is to be hidden, for example the following code would show the Id until the object has been saved, and then would hide it.

public class Customer {
    private int internalId;

    @Hidden(When.ONCE_PERSISTED)
    public int getInternalId() {
        return internalId;
    }
}

The acceptable values for the parameter are: When.ALWAYS, When.NEVER, When.ONCE_PERSISTED and When.UNTIL_PERSISTED. By default the annotated property or action is always hidden i.e. it is implicitly When.ALWAYS.

@Immutable

The @Immutable annotation may be applied to a class. The framework does not allow the state of such objects to be changed through the UI, and it should be considered a programmer error to do so programmatically. The ObjectStorePersistor, as used to run the in-memory and Hibernate object stores will actually fail if the programmer tries to change an object in a way that cause the persistor to try and save it. For example the following class would prevent the user from changing the object even when transient:

@Immutable
public class Country {
    ...
}

This annotation can also take a single parameter indicating when it is to become immutable, for example the following code would allow the user to create an email object and set it up, and then prevent any changes once it has been saved.

@Immutable(When.ONCE_PERSISTED)
public class Email {
    ...
}

The acceptable values for the parameter are: When.ALWAYS, When.NEVER, When.ONCE_PERSISTED and When.UNTIL_PERSISTED. By default the annotated property or action is always immutable i.e. it is implicitly When.ALWAYS.

@Mask

The @Mask annotation may be applied to any property, or to any parameter within an action method, that allows the user to type in text as input. The mask serves to validate, and potentially to normalise, the format of the input. The characters that can be used are based on Swing's MaskFormatter, and also Java's SimpleDateFormat. When applying a mask to a value property, the annotation should be applied to the 'getter'. For example:

public class Email {
    private String telNo;

    @Mask("(NNN)NNN-NNNN")
    public String getTelephoneNumber() {...}

    public void setTelephoneNumber(String telNo) {...}
    ...
}

When applying a mask to a value parameter within an action method, the annotation should be applied 'in-line' before that parameter). For example:

public void newContact(
     @Named("Contact Name")
     String contactName,
     @Named("Telephone Number")
     @Mask("(NNN)NNN-NNNN")
     String telNo) {}

@MaxLength

The @MaxLength annotation indicates the maximum number of characters that the user may enter into a String property, or a String parameter in an action. (It is ignored if applied to a property or parameter of any other type.) For example:

public class Customer {

    @MaxLength(30)
    public String getFirstName() { ... }
    public void setFirstName(String firstName) { ... }
    ...
}

If the model is being persisted on a relational database then @MaxLength should be specified for all String properties and action parameters.

@MemberOrder

@MemberOrder is the recommended mechanism for specifying the order in which fields and/or actions are presented to the user. (@ActionOrder and @FieldOrder provide alternative mechanisms).

@MemberOrder is specified at the individual member level, on a 'relative' basis. The syntax is:

@MemberOrder(sequence = "<relative order>")

where <relative order> may be any string. The actual sequence is determined by comparing all the values of the sequence specifier string, using the standard String comparator.

The simplest convention is to use numbers - 1, 2, 3 - though it is a better idea to leave gaps in the numbers - 10, 20, 30 perhaps - such that a new member may be added without having to edit existing numbers. A useful alternative is to adopt the 'dot-decimal' notation - 1, 1.1, 1.2, 2, 3, 5.1.1, 5.2.2, 5.2, 5.3 - which allows for an indefinite amount of future insertion. For example:

Public Class Customer {
    @MemberOrder(sequence="2.1")
    Public String getAddress() {...}
    Public void setAddress(value as String) {...}

    @MemberOrder(sequence="1.1")
    Public String getFirstName() {...}
    Public void setFirstName(value as String) {...}

    @MemberOrder(sequence="1.2")
    Public String getLastName() {...}
    Public void setLastName(value as String) {...}

    @MemberOrder(sequence="3")
    Public Date getDateOfBirth() {...}
    Public void setDateOfBirth(value as Date) {...}
    ...
}   

If a member does not have a specified order then it will be placed after those that are specified. Two members may have the same sequence specifier, but in such a case the relative ordering of those members will be indeterminate.

This approach is especially useful when dealing with inheritance hierarchies, as it allows sub-classes to specify where their additional members should be placed in relation to those inherited from the super-class.

Note that certain styles of user interface will lay out an object's properties and its collections separately, in which case the relative member order of properties and collections will be evaluated separately. However, since other styles of user interface may interleave properties and collections, it is safer to assume the latter.

@MultiLine

The @MultiLine annotation provides information about the carriage returns in a String property or action parameter. The annotation indicates that:

- the String property or parameter may contain carriage returns, and

- (optionally) the typical number of such carriage returns, and

- (optionally) that the text should be wrapped (the default is that text is not wrapped).

Currently the preventWrapping functionality is not fully implemented.

This may be used by the viewing mechanism to render the property as a multi-line textbox (or text-editor when changes are permitted), with appropriate wrapping and/or scrollbars. The syntax is:

@MultiLine([numberOfLines=<typicalNumberOfCRs>] [,preventWrapping=<false|true>])

For example:

public class BugReport {
    @MultiLine(numberOfLines=10)
    public String getStepsToReproduce() { ... }
    public void setStepsToReproduce(String stepsToReproduce) { ... }
    ...
}

Here the stepsToReproduce may be displayed in a text area of 10 rows, with no wrapping. A horizontal scrollbar may appear if the number of characters on any given row exceeds the width. Another example:

public class Email {
    @MultiLine(numberOfLines=20, preventWrapping=false)
    public String getBody() { ... }
    public void setBody(String body) { ... }
    ...
}

Here the body should be displayed in a text area of 20 rows, with wrapping. If this attribute is combined with the <TypicalLength>, then the expected width of the text area in the user interface will be determined by the value of the typical length divided by the number of specified lines. For example:

public class Email {
    @MultiLine(numberOfLines=20, preventWrapping=false)
    @TypicalLength(800)
    public String getBody() { ... }
    public void setBody(String body) { ... }
    ...
}

Here the body will (likely be) displayed in a text area of 20 rows, with 40 columns.

@MustSatisfy

The @MustSatisfy annotation allows validation to be applied to properties using an (implementation of a) org.nakedobjects.applib.spec.Specification object.

For example:

public class Customer {
    @MustSatisfy(StartWithCapitalLetterSpecification.class)
    public String getFirstName() { ... }

    ...
}

The Specification is consulted during validation, being passed the proposed value.

@Named

The @Named annotation is used when you want to specify the way something is named on the user interface i.e. when you do not want to use the name generated automatically by the system. It can be applied to objects, members (properties, collections, and actions) and to parameters within an action method.

Warning

Generally speaking it is better to rename the property, collection or action. The only common case where @Named is common is to rename parameters for built-in value types. Even here though a custom value type can be defined using @Value so that the value type is used as the parameter name. @Named may also be used if the name needs punctuation or other symbols in the name presented to the user.

Specifying the name of an object

By default the name of an object is derived, reflectively from the class name. To specify a different name for an object, use the @Named annotation in front of the class declaration. For example:

@Named("Customer")
public class CustomerImpl implements Customer{
   ...
}

See also: @Plural.

Specifying the name of a member

By default, the name of a member (a property, collection or action) presented to the user is derived, reflectively, from the name of the member defined in the program code. To specify a different name use the @Named annotation immediately before the member declaration. For example:

public class Customer {
    @Named("Given Name")
    public String getFirstName() { ... }

    @Named("Family Name")
    public String getSurname() { ... }

    public CreditRating getCreditRating() { ... }
}

Note that the framework provides a separate and more powerful mechanism for internationalisation.

Specifying the name for an action parameter

The most common usage of @Named will be to specify names for the parameters of an action: because, by default, the user interface will use the type of the parameter as the name. (This is because the parameter name declared in the code for the action method cannot be picked up reflectively.) To specify the name of a parameter, the @Named annotation is applied 'in-line' (i.e. preceding the individual parameter declaration). For example:

public class Customer {

    public Order placeOrder(
                      Product product,
                      @Named("Quantity")
                      int quantity) {

        Order order = new Order();
        order.modifyCustomer(this);
        order.modifyProduct(product);
        order.setQuantity(quantity);        
        return order;
    }
    ...
}

@NotPersistable

This annotation indicates that transient instances of this class may be created but may not be persisted. The framework will not provide the user with an option to 'save' the object, and attempting to persist such an object programmatically would be an error. For example:

@NotPersistable
public class InputForm {
    // members and actions here
}

This annotation can also take a single parameter indicating whether it is only the user that cannot persist the object, for example the following code would prevent the user from saving the object (via the viewer) but still allow the program to persist the object. By default the annotated object is effectively transient, e.g. it is implicitly By.USER_OR_PROGRAM.

@NotPersistable(By.USER)
public class InputForm {
    ...
}

@NotPersisted

This indicates that the property is not to be persisted. Note that in many cases the same thing could be achieved by providing the property with a 'getter' but no 'setter'. For example:

Check that this is acceptable for Hibernate

public class Order {

    private Order previousOrder;

    @NotPersisted
    public Order getPreviousOrder() {...}

    public void setPreviousOrder(Order previousOrder) {...}

    // rest of code
}

@Optional

By default, the system assumes that all properties of an object are required, and therefore will not let the user save a new object unless a value has been specified for each property. Similarly, by default, the system assumes that all parameters in an action are required and will not let the user execute that action unless values have been specified for each parameter. To indicate that either a property, or an action parameter, is optional, use the @Optional annotation.

Making a property optional

To indicate that a property is optional (i.e. that the user may save the object without necessarily specifying a value for this property), use the @Optional annotation immediately before the declaration of that property. For example:

public class Order {
    public Product getProduct() { ... }
    
    public java.util.Date getShipDate() { ... }
    public void setShipDate(Date java.util.shipDate) { ... }

    @Optional
    public String getComments() { ... }
    public void setComments(String comments) { ... }
}

Here the product and shipDate properties are both required, but the comments property is optional.

Making an action parameter optional

To indicate that an action may be invoked without having to specify a value for a particular parameter, the @Optional annotation should be used in-line i.e. immediately before the declaration of that parameter. For example:

public class Customer {
    public Order placeOrder(
              Product product,
              @Named("Quantity") int quantity, 
              @Optional @Named("Special Instructions") String instr) {
        ....
    }
    ...
}

Note that the @Optionalannotation has no meaning for a primitive property (or parameter) such as int - because primitives will always return a default value (e.g. zero). If optionality is required, then use the corresponding wrapper class (e.g. java.lang.Integer).

@Plural

Where Naked Objects displays a collection of several objects it may use the plural form of the object type in the title. By default the plural name will be created by adding an 's' to the end of the singular name (whether that is the class name or another name specified using @Named). Where the single name ends in 'y' then the default plural name will end in 'ies' - for example a collection of Country objects will be titled 'Countries'. Where these conventions do not work, the programmer may specify the plural form of the name using @Plural. For example:

@Plural("Children")
public class Child {
    // members and actions here
}

@RegEx

The @RegEx annotation may be applied to any property, or to any parameter within an action method, that is a value type (i.e. that allows the user to type in text as input). It serves both to validate and potentially to normalise the format of the input. @Regex is therefore similar in use to @Mask but provides more flexibility. The syntax is:

@RegEx(validation = <regEx string>, format = <regEx string>, caseSensitive = <true|false>)

The first parameter is required; the format defaults to 'no formatting'; caseSensitive defaults to false. When applying Regex to a value property, the annotation should be applied to the 'getter'. For example:

    private String email;

    @RegEx(validation = "(\\w+\\.)*\\w+@(\\w+\\.)+[A-Za-z]+")
    public String getEmail() {}

    public void setEmail(String email) {}

When applying a RegEx expression to a value parameter within an action method, the annotation should precede that parameter:

    public void newContact(
        @Named("Contact Name")
        String contactName,
        @Named("Email")
        @RegEx(validation = "(\\w+\\.)*\\w+@(\\w+\\.)+[A-Za-z]+")
        String email) {}

@TypeOf

The @TypeOf annotation is used to specify the type of elements in a collection, when it is not possible to use generics - for example when invoking an external method that does not use generics.

@TypeOf(Customer.class)
public List allNewCustomers() {
    return CustomerDatabase.allNewCustomers();
}

@TypicalLength

The @TypicalLength annotation indicates the typical length of a String property or String parameter in an action. This may be used by the viewing mechanism to determine the space that should be given to that property or parameter in the appropriate view. For example:

public class Customer {
    @MaxLength(30)
    @TypicalLength(20)
    public String getFirstName() { ... }
    public void setFirstName(String firstName) { ... }
}

If the typical length is the same as the <MaxLength> then there is no need to specify <TypicalLength> as well. If the value specified is zero or negative then it will be ignored.

@Value

The @Value annotation indicates that a class should be treated as a value type rather than as a reference (or entity) type. It does this providing an implementation of a org.nakedobjects.applib.adapters.ValueSemanticsProvider.

For example:

@Value(semanticsProviderClass=ComplexNumberValueSemanticsProvider.class)
public class ComplexNumber {
    ...
}

The ValueSemanticsProvider allows the framework to interact with the value, parsing strings and displaying as text, and encoding/decoding (for serialization).