Developing domain objects - a how-to guide

This section defines a set of conventions for writing domain objects, that are together known as the 'Naked Objects (Java) Programming Model'.

Following these conventions does not tie your domain objects to the Naked Objects Framework or any other framework: the resulting domain objects may be run within any framework or platform that supports POJOs (Plain Old Java Objects). A few of the conventions do make use of Interfaces or Annotations that are necessarily defined somewhere - in this case they are in the Naked Objects AppLib. However, the AppLib is not itself dependent upon the Naked Objects Framework (and in theory another framework implementation could support the same applib).

The conventions of the programming model are best described as 'intentional' - they convey an intention as to how domain objects, their properties and behaviours, are to be made available to users. The specific way in which those intentions are interpreted or implemented will depend upon the framework, and/or the particular components or options selected within that framework.

To pick a single example, marking up a domain class with the annotation @Bounded is an indication that the class is intended to have only a small number of instances and that the set does not change very often - such as the class Country. This is an indication to any interested framework that the whole set of instances might be offered to the user in a convenient form such as a drop-down list. The programming convention has not been defined as @DropDownList because the user interface might not support drop-down-lists - but it might provide a capability to select from an @Bounded class by typing the initial letters of the desired instance.

Object-level specifications

The first set of conventions are concerned with the capabilities or behaviour of an object as a whole.

How to specify a title for an object

A title is used to identify an object to the user in the user interface. For example, a Customer's title might be the organization's customer reference, or perhaps (more informally) their first and last names. By default, the framework will use the object's toString() method as the title. However, if a title() method (returning a String) is present, then that is used instead, thus:

public String toString()

or

public String title()

The reason for providing the option to use a title method is in case the programmer needs to make use of the toString method for other purposes, such as for debugging.

How to specify the icon for an object

By default, the framework will look for an image in the images directory (which must be on the classpath) that has the same name as the object class. So for an object of type Customer, it will look for Customer.gif or Customer.png. If it finds no such file, then it will work up the inheritance hierarchy to see if there is an icon matching the name of any of the super-classes, and use that instead. If no matching icon is found then the framework will look for an image called default in the images directory, and if this has not been specified, then the framework will use its own default image for an icon.

We strongly recommend that you adopt 'camel case' as the convention for icon file names: if you have a class called OrderLine, then call the icon OrderLine.gif or OrderLine.png (JPEG suffixes OrderLine.jpg or OrderLine.jpeg will also be recognized but generally GIF or PNG are to be preferred). Actually, the framework will also recognise orderline.gif, but some operating systems and deployment environments are case sensitive, so it is good practice to adopt an unambiguous convention.

The programmer may choose to specify, manually, which icon to use, by specifying an iconName method:

    public String iconName() {
        return "Person";
    }

This makes it easy for more than one class to use the same icon, without having to duplicate the image file.

The iconName method may also be used to specify an individual icon for each instance. For example, an instance of Product could use a photograph of the product as an icon, using:

    public String iconName() {
        return getProductName() + "-photograph";
    }

or to vary the icon according to the status of the object:

    public String iconName() {
        return "Order-" + getStatus();
    }

How to specify a name and/or description for an object

By default, the name (or type) of an object, as displayed to the user will be the class name. However, if an @Named annotation is included, then this will override the default name. This might be used to include punctuation or other characters that may not be used within a class name.

By default the framework will create a plural version of the object name by adding an 's' to singular name, or a 'ies' to names ending 'y'. For irregular nouns or other special case, the @Plural annotation may be used to specify the plural form of the name explicitly.

(Note that there is an entirely separate mechanism for dealing with Internationalisation, which is described elsewhere).

The programmer may optionally also provide a @DescribedAs annotations, containing a brief description of the object's purpose, from a user perspective. The framework will make this available to the user in a form appropriate to the user interface style - for example as 'balloon' help.

How to specify that an object should not be persisted

Use the @NotPersistable annotation.

How to specify that an object should never be modified by the user

Use the @Immutable annotation.

How to specify that a class of objects has a limited number of instances

Use the @Bounded annotation. A common way of describing this is that the whole (limited) set of instances may be rendered to the user as a drop down list - but the actual interpretation will depend upon the form of the user interface.

How to specify that an object should always be hidden from the user

Use the @Hidden annotation.

The object lifecycle

These conventions are concerned with the creation, retrieval, updating and deletion of objects.

How to create or delete objects within your code

When you create any domain object within your application code, it is important that the framework is made aware of the existence of this new object - in order that it may be persisted to the object store, and in order that any services that the new object needs are injected into it. Just specifying new Customer(), for example, will create a Customer object, but that object will not be known to the framework. However, since we do not want to tie our domain objects to a particular framework, we use the idea of a 'container' to intermediate. The application library provides an interface:

org.nakedobject.applib.DomainObjectContainer which in turn defines the following methods for managing domain objects:

<T> T newTransientInstance(final Class<T> ofClass) returns a new instance of the specified class, that is transient (unsaved). This may subsequently saved either by the user invoking the Save action (that will automatically be rendered on the object view) or programmatically by calling void makePersistent(Object transientObject)

<T> T newPersistentInstance(final Class<T> ofClass) creates a new object already persisted.

boolean isPersistent()checks whether an object has already been persisted. (Useful in controlling visibility or availability of properties or actions).

void remove(Object object) deletes a persistent object from the object store.

Any framework that recognises the Naked Objects Programming Model will provide an implementation of DomainObjectContainer and will take responsibility to inject a reference to that Container into any domain object that needs it.

A domain object specifies that it needs to have a reference to the Container injected into by including the following code:

    private DomainObjectContainer container;

    protected DomainObjectContainer getContainer() {
        return this.container;
    }
    public final void setContainer(final DomainObjectContainer container) {
        this.container = container;
    }

Creating or deleting objects is then done by invoking those methods on the Container. For example the following code would then create a new Customer object within another method:

    Customer newCust = (Customer) getContainer().newTransientInstance(Customer.class);
    newCust.setName("Charlie");
    getContainer().persist(newCust);

If you are able to make your domain object inherit from org.nakedobjects.applib.AbstractDomainObject then you have direct access to those methods, so the code would become:

    Customer newCust = (Customer) newTransientInstance(Customer.class);
    newCust.setName("Charlie");
    persist(newCust);

These methods are actually provided by the org.nakedobjects.applib.AbstractContainedObject and so are also available on org.nakedobjects.applib.AbstractService (and, hence, on org.nakedobjects.applib.AbstractFactoryAndRepository) for creating objects within a service.

It is possible to create a transient object within another transient object. When the framework persists any transient object, it will automatically persist any other transient object referenced by that object. However, if any of these transient objects are to be exposed to the user (while in their transient state), then you need to write your code very carefully - anticipating the fact that the user could elect to save any of the transient objects at any point - which could cause the graph of related objects to be persisted in an invalid state.

The recommended approach is, if possible, to mark these supplementary classes as not persistable by the user, or not to permit the user to create a new transient object that is a child of an existing transient object, but, rather, to require the user to save the parent object first.

How to insert behaviour into the object life cycle

The following is a list of methods that correspond to various events in the life-cycle of a domain object. If a domain object implements any of these methods (they are all optional) then the framework will call that method whenever the corresponding event occurs. For example, persisted is called after an object has been persisted. One reason for implementing the persisted method might be to set up a reverse association that we do not want to be set up until the new object has been persisted.

public void created() will be called by the framework at logical creation of the object

public void loading() will be called by the framework when a persistent object is about to be loaded into memory

public void loaded() will be called by the framework when a persistent object has just been loaded into memory

public void persisting() will be called by the framework just before a transient object is first persisted. (For backwards compatibility saving() is also supported).

public void persisted() will be called by the framework just after a transient object is first persisted. (For backwards compatibility saved() is also supported).

public void updating() will be called by the framework after any property on a persistent object has been changed and just before this change is persisted

public void updated() will be called by the framework just after a changed property on a persistent object has been persisted

public void removing() will be called by the framework when a persistent object is just about to be deleted from the persistent object store. (For backwards compatibility deleting() is also supported).

public void removed() will be called by the framework when a persistent object has just been deleted from the persistent object store. (For backwards compatibility deleted() is also supported).

Properties

The following conventions are concerned with specifying the properties of an object, and the way in which users can interact with those properties.

How to add a property to an object

Properties are specified using the JavaBean conventions, recognizing a standard accessor/mutator pair (get and set). The syntax is:

public <property type> get<PropertyName>() 

public void set<PropertyName>(<property type> param)

where <property type> is a primitive, a value object or an entity object.

Properties may reference either a value or another domain object. Values include Java primitives, and JDK classes with value semantics (java.lang.Strings and java.util.Dates). A property referencing another domain object is sometimes called an association.

For example, the following example contains both a value (String) property and a reference (Organisation) property:

public class Customer {
    private String firstName;
    public String getFirstName() {
        return firstName;
    }
    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    private Organisation organisation;
    public Organisation getOrganisation() {
        return organisation;
    }
    public void setOrganisation(Organisation organisation) { 
        this.organisation = organisation;
    }

    ...
}

How to prevent the user from modifying a property

Preventing the user from modifying a property value is known as 'disabling' the property.

Disabling a property always

Use the @Disabled annotation.

Disabling a property under certain conditions

A disable method can be used to disable a particular instance's member under certain conditions. The syntax is:

public String disable<PropertyName>() A non-null return value indicates the reason why the property cannot be modified. The framework is responsible for providing this feedback to the user. For example:

public class OrderLine {
    public String getQuantity() { ... }
    public void setQuantity(int quantity) { ... }

    public String disableFirstName() { 
        if (this.hasBeenSubmitted()) {
            return "Cannot alter any quantity after Order has been submitted"; 
        }
        return null;
    }
}
Disabling a property for specific users or roles

Generally it is not good practice to embed knowledge of roles and/or users into the domain classes. This is the responsibility of the framework or platform and should be specified and administered externally to the domain model.

However, in rare circumstances it might be necessary or pragmatic to implement access control within the domain model using the inherited getUser() method:

For example:

import org.nakedobjects.applib.UserMemento;

public class Employee {
    public BigDecimal getSalary() { ... }
    public void setSalary(BigDecimal salary) { ... }

    public String validateSalary(BigDecimal salary) {
        return salary.doubleValue() >= 30000 &&
              !getUser().hasRole("MODIFY_SALARY")?
              "Need MODIFY_SALARY role to increase salary above 30000": null;
    }
}

How to make a property optional (when saving an object)

By default, when a new transient (unsaved) object is presented to the user, values must be specified for all properties before the object may be saved. To specify that a particular property is optional, use the @Optional annotation.

How to specify the size of String properties

Use the @MaxLength, @TypicalLength and @MultiLine annotations.

How to validate user input to a property

A validate method is used to check that a new value for a property is valid. If the proffered value is deemed to be invalid then the property will not be changed. A non-null return String indicates the reason why the member cannot be modified/action be invoked; the framework is responsible for providing this feedback to the user.

The syntax is:

public String validate<PropertyName>(<property type> param)

For example:

public class Exam {
    public int getMark() { ... }
    public void setMark(int mark) { ... }
    public validateMark(int mark) {
        return !(mark >= 0 && mark <= 30)?
            "Mark must be in range 0 to 30"
            :null;
    }
}
Format validation

For properties that accept a text input string, such as String and Date, there are convenient mechanisms to validate and/or normalise the values typed in.

For Date and number values the @Mask annotation may be used.

For String properties the @RegEx annotation may be used.

How to specify a set of choices and or a default value for a property

The simplest way to provide the user with a set of choices for a property (possibly rendered as a drop-down list, for example) is to ensure that the type used by the property is marked up as @Bounded. However, this is not always appropriate. For example you might wish to provide the user with the choice of all the Addresses known for that Customer, with the most recently-used address as the default.

The syntax for specifying a default value is:

public <property type> default<PropertyName>()

And for specifying a list of choices is:

public <array or collection of property type> choices<PropertyName>()

The full code for our example above is:

public class Order {
    public Address getShippingAddress() { ... }
    public void setShippingAddress() { ... }
    public Address defaultShippingAddress() {
        return getCustomer().normalAddress();
    }
    public List<Address> choicesShippingAddress() {
        return getCustomer().allActiveAddresses();
    }
}

How to set up the initial value of a property programmatically

Initial values for properties may be set up programmatically within the created() method on the object. (See Object: Life Cycle).

How to trigger other behaviour when a property is changed

If you want to invoke functionality whenever a property is changed by the user, then you should create a modify <propertyName> and include the functionality within that. For example:

public int getAmount() {}
public void setAmount(int amount) {}

public void modifyAmount(int amount) {
     setAmount(amount);
     addToTotal(amount);
}

The reason for the modifyAmount method is that it would not be a good idea to include the addToTotal call within the setAmount method , because that method may be called by the persistence mechanism when an object is retrieved from storage.

You may optionally also specify a clear<PropertyName> which works the same way as modify modify <propertyName> but is called when the property is cleared by the user (i.e. the current value replaced by nothing).

These methods may also be used for setting up bidirectional relationships (using the 'mutual registration pattern'). For example:

public class Employee {
    private Department department;
    public Department getDepartment() {
        return department;
    }
    public void setDepartment(Department department) { 
        this.department = department;
    }
    public void modifyDepartment(Department department) {
        setDepartment(department);
        department.addToStaff(this);
    }
    public void clearDepartment(Department department) {
        setDepartment(null);
        department.removeFromStaff(this);
    }

    ...
}

How to control the order in which properties are displayed

Use the @MemberOrder annotation.

How to specify a name and/or description for a property

Specifying the name for a property

By default the framework will use the property name itself to label the property on the user interface. If you wish to over-ride this, use the @Named annotation on the property.

Specifying a description for a property

Use the @DescribedAs annotation on the property itself.

The framework will take responsibility to make this description available to the user, for example in the form of a 'balloon help'.

How to hide a property from the user

Hiding a property always

Use the @Hidden annotation.

Hiding a property under certain conditions

A hide method can be used to indicate that a particular instance's member should be hidden (rendered invisible to the user) under certain conditions. The syntax is:

public boolean hide<PropertyName>() A true return value indicates that the property is hidden. For example:

public class Order {
    public String getShippingInstructions() { ... }
    public void setShippingInstructions(String shippingInstructions) { ... }
    public boolean hideShippingInstructions() {
        return hasShipped();
    }
}
Hiding a property for specific users or roles

Important: see the comments under 'Disabling a property for specific users or roles'.

Session controls provide a way for the class to hide properties from specific users, or users not in specific roles. The syntax is: public boolean hide<PropertyName>(Session session) For example:

public class Employee {
    public BigDecimal getSalary() { ... }
    public void setSalary(BigDecimal salary) { ... }
    public boolean hideSalary(UserMemento user, BigDecimal salary) {
        return !user.hasRole("VIEW_SALARY");
    }
}

How to make a property non-persisted

If there is no mutator (set) method then the field is not only unmodifiable but will also not be persisted. This approach is by design and also happens to be compatible with Java Persistence Api (JPA) semantics. This may be used to derive a property from other information available to the object, for example:

public class Employee {
    public Department getDepartment() { ... }
    public void setDepartment(Department department) { ... }
    public void modifyDepartment(Department department) { ... }
    public void clearDepartment(Department department) { ... }

    // this is the derived property
    public Employee getManager() {
        if (getDepartment() == null) { return null; }
        return getDepartment().getManager();
    }

    ...
}

If you need to have a get and set method for the property but do not wish to have that property persisted, use the @NotPersisted annotation.

Actions

An 'action' is a method that we expect the user to be able to invoke via the user interface, though it may also be invoked programmatically within the object model. The following conventions are used to determine when and how methods are made available to the user as actions.

How to add an action to an object

By default, any public instance method that you add to a class will be treated as a user action, unless it represents a property, collection, or another reserved method defined in this manual.

If you have a method that you don't want to be made available as a user-action you should either make it protected or private or use the @Hidden annotation. Note also that static methods are ignored: such functionality should reside in a service, such as a Repository or Factory.

We refer to all methods that are intended to be invoked by users as 'action methods'.

The syntax is:

public void <actionName>([<value or entity type> param]...)

or

public <return type> <actionName>([<value or entity type> param]...)

When a method returns a reference the viewer will attempt to display that object. If the return value is null then nothing is displayed.

How to specify parameters for an action

If an action method takes parameters, the viewing mechanism will automatically require the user to specify these parameters (for example, in the form of a dialog box) - and ensure that they are of the correct type.

Specifying parameter names and/or descriptions

Unlike with properties, the framework cannot pick up the names of parameters that you use within the domain code. By default parameters will be labelled only with the type of the object required (e.g. 'String:' or 'Customer:) If you want a parameter to have a different name (such as 'First Name', 'Last Name') then that parameter should be marked up with an @Named annotation - very often taking the same form as the parameter name used in the code. (This is one of the few forms of duplication that we cannot eliminate; the parameter name is not available in the class' bytecode and so cannot be inferred automatically. Alternatively though, you could create a user-defined value type, using @Value).

Similarly, any parameter may be given a short user-description using the @DescribedAs annotation. The framework takes responsibility to make this available to the user.

How to make a parameter optional

By default, the framework assumes that when an action method is to be invoked, all the parameters are mandatory. You may over-ride this behaviour by marking up one or more of the paramaters with the @Optional annotation.

How to specify default values for parameters

When an action is about to be invoked, then default values can be provided for any or all of its parameters.

There are two different ways to specify parameters; either per parameter, or for all parameters. The per-parameter form is simpler and probably preferred; the syntax is:

public <parameter type> defaultN<ActionName>()

where N indicates the 0-based parameter number. For example:

public class Customer {
    public Order placeOrder(
                      Product product,
                      @Named("Quantity") 
                      int quantity) {
        ...
    }
    public Product default0PlaceOrder() {
        return productMostRecentlyOrderedBy(this.getCustomer());
    }
}

The syntax for specifying all the parameter default values in one go is:

public Object[] default<ActionName>([<parameter type> param]...)

returning an array (which must have one element per parameter in the action method signature) of corresponding default values. For example:

public class Customer {
    public Order placeOrder(
                      Product product,
                      @Named("Quantity") 
                      int quantity) {y
        ...
    }
    public Object[] defaultPlaceOrder(
                      Product product,
                      int quantity) {
        return new Object[] {productMostRecentlyOrderedBy(this.getCustomer()), 1};
    }
}
How to specify a set of choices for parameter values

The programmer may provide a set of choices for the value of any or all of the parameters of an action. These will be made available to the user - for example as a drop-down list.

As for defaults, there are two different ways to specify parameters; either per parameter, or for all parameters. The per-parameter form is simpler and probably preferred; the syntax is:

public List<parameter type> choicesN<ActionName>()

where N indicates the 0-based parameter number. For example:

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

    public List<Product> choices0PlaceOrder() {
        return lastFiveProductsOrderedBy(this.getCustomer());
    }
}

The alternative mechanism is to supply all the parameter choices in one go:

public Object[] choices<ActionName>([<parameter type> param]...)

returning an array, which must have one element per parameter in the method signature. Each element of the array should itself either be an array or a list, containing the set of values representing the choices for that parameter, or null if there are no choices to be specified for that parameter.

For example:

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

    public Object[] choicesPlaceOrder(
                      Product product,
                      int quantity) {
        return new Object[] {lastFiveProductsOrderedBy(this.getCustomer()).toArray(), null};
    }
}

(Note that if the type of the property is annotated with @Bounded, then it is not necessary to specify the choices for that parameter, as the user will automatically be offered the full set to choose from.)

How to specify the length or format for text-input parameters

Use the @MaxLength, @TypicalLength, @MultiLine, @Mask or @RegEx annotations.

How to validate parameter values

A validate method is used to check that the set of arguments used by an action method is valid. If the arguments are invalid then the framework will not invoke the action. A non-null return String indicates the reason why the member cannot be modified/action be invoked, and the viewing mechanism will display this feedback to the user.

The syntax is:

public String validate<ActionName>([<parameter type> param]...)

For example:

public class Customer {
    public Order placeOrder(Product p, int quantity) { ... }
    public String validatePlaceOrder(Product p, int quantity) {
        if (p.isOutOfStock()) { return "Product is out of stock"; }
        if (quantity <= 0) { return "Quantity must be a positive value"; }
        return null;
    }

How to specify conditions for invoking an action

Disabling an action based on the state of the object

There may be circumstances in which we do not want the user to be able to initiate the action at all - for example because that action is not appropriate to the current state of the object on which the action resides. Such rules are enforced by means of a disable method.

The syntax is:

public String disable<ActionName>([<parameter type> param]...)

A non-null return String indicates the reason why the action may not be invoked. The framework takes responsibility to provide this feedback to the user. For example:

public class Customer {
    public Order placeOrder(Product p, int quantity) { ... }
    public String disablePlaceOrder(Product p, int quantity) { 
        return isBlackListed()?
            "Blacklisted customers cannot place orders"
            :null;
    }

It is also possible to permanently disable an action using the @Disabled annotation. One possible reason for doing this might be during prototyping - to indicate to the user that an action is planned, but has not yet been implemented.

Disabling an action for certain users or roles

See 'Properties: Disabling a property for specific users or roles'. The same technique can be applied to actions. However, the caveats apply.

How to control the order in which actions appear on the menu

Use the @MemberOrder annotation.

How to hide actions

Hiding an action always

Use the @Hidden annotation. (This is generally used where a public method on an object is not intended to be a user action).

Hiding an action under certain conditions

A hide method can be used to indicate that an action should be hidden under certain conditions. The syntax is:

public boolean hide<ActionName>([<parameter type> param]...)

A true return value indicates that the action should not be shown. For example:

public class Order {
    
    public void applyDiscount(int percentage) { ... }
    
    public boolean hideApplyDiscount() {
        return isWholesaleOrder();
    }
}
Hiding an action for certain users or roles

See 'Properties: Hiding a property for specific users or roles'. The same technique can be applied to actions. However, the caveats apply.

How to pass a message back to the user

Sometimes, within an action it is necessary or desirable to pass a message to the user, for example to inform them of the results of their action ('5 payments have been issued') or that the action was not successful ('No Customer found with name John Smith'). DomainObjectContainer defines two methods for this purpose:

void informUser(String message)

void warnUser(String message)

These two methods provide different ways to send a message to the user, representing increasing levels of severity. How each of these messages is rendered visible to the user is determined by the framework.

These two methods are also available on AbstractDomainObject as a shortcut.

Collections

A collection is a list of references to several entity objects that have a common type.

How to add a collection to an object

A collection is recognized via an accessor/mutator method pair (get and set) for any type of collection provided by the programming language. The syntax is:

public <collection type> get<CollectionName>()

private void set<CollectionName>(<collection type> param)

It is recommended that the collections be specified using generics (for example: List<Customer> ). That way the framework will be able to display the collection based on that type definition. (Generics are also required by some persistence mechanisms). For example the viewer might display the collection as a table, with the columns defined by the visible properties of that type. The viewer will then automatically prevent the user from adding objects not of that type. If generics are not used then the type may be inferred from the addTo / removeFrom methods, if specified (see below).

For example:

public class Employee { ... }

public class Department {
    private List<Employee> employees = new ArrayList<Employee>();
    public List <Employee> getEmployees() {
        return employees;
    }
    private void setEmployees(List<Employee> employees) { 
        this.employees = employees;
    }
    ...
}

How to trigger other behaviour when an object is added or removed

A collection may have a corresponding addTo and/or removeFrom method. This is equivalent to the modify and clear methods for properties. The syntax is:

public void addTo<CollectionName>(<entity type> param)

public void removeFrom<CollectionName>(<entity type> param)

where <entity type> is the same type as the generic collection type. For example:

public class Employee { ... }

public class Department {
    private List<Employee> employees = new ArrayList<Employee>();
    public List <Employee> getEmployees() {
        return employees;
    }
    private void setEmployees(List<Employee> employees) { 
        this.employees = employees;
    }
    public void addToEmployees(Employee employee) {
        employees.add(employee);
    }
    public void removeFromEmployees(Employee employee) {
        employees.remove(employee);
    }

    ...
}

The addTo / removeFrom and modify / clear methods are particularly useful in setting up bidirectional relationships using the 'mutual registration pattern'; for a write-up of this pattern, see http://www.two-sdg.demon.co.uk/curbralan/papers/MutualRegistration.pdf.

How to prevent the user from modifying a collection

Preventing the user from adding to or removing from a collection is known as 'disabling' the collection.

Disabling a collection permanently

Use the @Disabled annotation.

Disabling a collection under certain conditions

A disable method can be used to disable a particular instance's collection under certain conditions: The syntax is:

public String disable<CollectionName>() For example:

public class Department {
    public List<Employee> getEmployees() { ... }
    public void addToEmployees(Employee employee) { ... }
    public void removeFromEmployees(Employee employee) { ... }
    public void disableEmployees() {
        return isClosed()? "This department is closed" : null;
    }
}
Disabling a collection for specific users or roles

See Properties: Disabling a property for specific users or roles'. The same technique can be applied to collections, with the same caveats applying.

How to validate an object to be added or removed

A validate method is used to check that an object to be added or removed from a collection is valid. A non-null return String indicates the reason why the object cannot be added/removed, and the viewing mechanism will display this to the user. The syntax is:

public String validateAddTo<CollectionName>(<property type> param) 

public String validateRemoveFrom<CollectionName>(<property type> param)

For example:

public class Department {
    private List<Employee> employees = new ArrayList<Employee>();
    public List<Employee> getEmployees() { ... }
    private void setEmployees(List<Employee> employees) { ... }
    public String validateAddToEmployee(Employee employee) {
        return employee.isRetired()?
            "Cannot add retired employees to department"
            :null;
}

How to control the order in which collections are displayed

Use the @MemberOrder annotation.

How to specify a name and/or description for a collection

Use the @Named and/or @DescribedAs annotations.

How to hide a collection

See 'Properties: How to hide a property'. The same approaches work for collections.

How to create a derived collection

Collections can be derived, in the same way as properties. These are not persisted, but are represented as read only collections. For example:

public class Department {
    // Standard collection
    List<Employee> employees = new ArrayList<Employee>();
    public List<Employee> getEmployees() { ... }
    private void setEmployees(List<Employee>) { ... }
    void addToEmployees(final Employee employee) { ... }
    void removeFromEmployees(final Employee employee) { ... }

    // Derived collection
    public List<Employee> getTerminatedEmployees() {
        List<Employee> terminatedEmployees = new ArrayListt<Employee>();
        for(Employee e: employees) {
            if (e.isTerminated()) {
                addTo(terminatedEmployees, e);
            }
        }
        return terminatedEmployees;
    }
}

Repositories and Factories

The Naked Objects application library provides a class

org.nakedobjects.applib.AbstractFactoryAndRepository

that makes it easy to write a Repository and/or Factory to work entirely in memory. This is very useful during prototyping, as you can quickly get your system up and running without having to deal with a database. Refer to the JavaDoc documentation for that class for a full list of methods available. However, the following describes some of the most commonly-used methods:

<T> T newTransientInstance(final Class<T> ofClass) returns a new instance of the specified class, that is transient (unsaved). This may subsequently be saved either by the user invoking the Save action (that will automatically be rendered on the object view) or programmatically by calling . . .

void makePersistent(Object transientObject)

<T> T newPersistentInstance(final Class<T> ofClass) creates a new object already persisted.

void disposeInstance(Object persistentObject)

<T> List<T> allInstances(final Class<T> cls, final boolean includeSubclasses) these may be iterated through for a specific match.

<T> T firstMatch(final Class<T> cls, final String title, final boolean includeSubclasses)looks for an object with the title specified.

There are a number of useful matching and filtering methods in AbstractFactoryAndRepository.

Finding by pattern

TODO: Complete this section to cover pattern-based searching, including the fact that this works for both InMemory and Hibernate repositories.

@MustSatisfy specification

The @MustSatisfy annotation is an alternative to using imperative validation, allowing validation rules to be captured in an (implementation of a) org.nakedobjects.applib.spec.Specification.

For example:

public class DomainObjectWithMustSatisfyAnnotations extends AbstractDomainObject {

    private String lastName;
    @MustSatisfy(SpecificationRequiresFirstLetterToBeUpperCase.class)
    public String getLastName() {
        resolve(lastName);
        return lastName;
    }
    public void setLastName(String lastName) {
        this.lastName = lastName;
        objectChanged();
    }

    public void changeLastName(
            @MustSatisfy(SpecificationRequiresFirstLetterToBeUpperCase.class)
            String lastName
            ) {
        setLastName(lastName);
    }

}

TODO: @MustSatisfy may not work for action parameters; see http://development.nakedobjects.org/trac/ticket/669.

Value Types

In addition to the built-in value types it is also possible to define user-defined value types. This is typically done using the @Value annotation.

The @Value annotation is used to provide an implementation of the ValueSemanticsProvider interface. In turn this provides objects that allow the framework to interact with the value, in particular for parsing (parsing strings into values and display values as strings), and for encoding/decoding (for serialization for client/server and used by some persistors).

For more details, explore the built-in types within the applib, for example org.nakedobjects.applib.value.Money.

@Value(semanticsProviderName = "org.nakedobjects.metamodel.value.MoneyValueSemanticsProvider")
public class Money extends Magnitude {
    ...
}

where MoneyValueSemanticsProvider is the implementation of ValueSemanticsProvider described above.

Using value types generally removes the need for using @MustSatisfy annotation; the rules can instead move down into a validate method on the value type itself.

TODO: need to beef up this discussion. Also, note that it is possible to register value types using nakedobjects.properties rather than the @Value annotation; this is particularly useful for third-party value types.

Resolve and ObjectChanged

In previous versions of the framework it was necessary to call the inherited resolve() method within every property or collection's getter, and objectChanged() within every property's setter and every collection's addTo or removeFrom.

These methods still exist in AbstractDomainObject, but no longer need to be called explicitly. Instead Naked Objects 4.0 uses bytecode enhancement (using either cglib or javassist) to automatically call these methods. This bytecode enhancement can be disabled in nakedobjects.properties file; if it is then the methods must be called manually as they were in Naked Objects 3.0.