Mandatory vs optional

By default, Apache Causeway assumes that all properties of an domain object or view model are required (mandatory). The optionality() attribute allows this to be relaxed. The attribute is also supported for parameters.

That said, properties are most commonly defined on persistent domain objects (entities), in which case the JDO @Column should be specified. Apache Causeway can infer the maxLength directly from the equivalent @Column#length() annotation.

That said, properties are most commonly defined on persistent domain objects (entities), in which case the JDO @Column will in any case need to be specified. Apache Causeway can infer the optionality semantic directly from the equivalent @Column#allowsNull() annotation/attribute.

For example:

import lombok.Getter;
import lombok.Setter;

public class Customer {

    @javax.jdo.annotations.Column(allowsNull="true")
    @Getter @Setter
    private String middleInitial;

    // ...
}

In this case there is no need for the @Property#optionality attribute.

Mismatched defaults

If the @Column#allowsNull attribute is omitted and the `@Property#optionality() attribute is also omitted, then note that Causeway' defaults and JDO’s defaults differ. Specifically, Causeway always assumes properties are mandatory, whereas JDO specifies that primitives are mandatory, but all reference types are optional.

When Apache Causeway initializes it checks for these mismatches during its metamodel validation phase, and will fail to boot ("fail-fast") if there is a mismatch. The fix is usually to add the @Column#allowsNull() annotation/attribute.

Superclass inheritance type

There is one case (at least) it may be necessary to annotate the property with both @Column#allowsNull and also @Property#optionality(). If the property is logically mandatory and is in a subclass, but the mapping of the class hierarchy is to store both the superclass and subclass(es) into a single table (ie a "roll-up" mapping using javax.jdo.annotations.InheritanceStrategy#SUPERCLASS_TABLE), then JDO requires that the property is annotated as @Column#allowsNull="true": its value will be not defined for other subclasses.

In this case we therefore require both annotations.

@javax.jdo.annotations.PersistenceCapable
@javax.jdo.annotations.Inheritance(strategy = InheritanceStrategy.NEW_TABLE)
public abstract class PaymentMethod {
    ...
}
@javax.jdo.annotations.PersistenceCapable
@javax.jdo.annotations.Inheritance(strategy = InheritanceStrategy.SUPERCLASS_TABLE)
public class CreditCardPaymentMethod extends PaymentMethod {

    private String cardNumber;
    @javax.jdo.annotations.Column(allowsNull="true")
    @Property(optionality=Optionality.MANDATORY)
    public String getCardNumber() { return this.cardNumber; }
    public void setCardNumber(String cardNumber) { this.cardNumber = cardNumber; }
    ...
}

Alternatively, you could rely on the fact that Apache Causeway never looks at fields (whereas JDO does) and move the JDO annotation to the field:

@javax.jdo.annotations.PersistenceCapable
@javax.jdo.annotations.Inheritance(strategy = InheritanceStrategy.SUPERCLASS_TABLE)
public class CreditCardPaymentMethod extends PaymentMethod {

    @javax.jdo.annotations.Column(allowsNull="true")
    private String cardNumber;

    public String getCardNumber() { return this.cardNumber; }
    public void setCardNumber(String cardNumber) { this.cardNumber = cardNumber; }

    // ...
}

However this at first glance this might be read as meaning that the property is optional whereas Apache Causeway' default (required) applies.

Non-persistent properties

Of course, not every property is persistent (it could instead be derived), and neither is every domain object an entity (it could be a view model). For these non persistable properties the optionality attribute is still required.

For example:

public class Customer {

    @javax.jdo.annotation.NotPersistent             (1)
    @Property(optionality=Optionality.OPTIONAL)
    public String getFullName() {                   (2)
        // ...
    }
    public void setFullName(String fullName) {      (3)
        // ...
    }

    // ...
}
1 a non persisted (derived) property
2 implementation would most likely derive full name from constituent parts (eg first name, middle initial, last name)
3 implementation would most likely parse the input and update the constituent parts

The attribute has no meaning for a primitive type such as int: primitives will always have a default value (e.g. zero). If optionality is required, then use the corresponding wrapper class (e.g. java.lang.Integer) and annotate with Parameter#optionality() as required.

The values for the attribute are simply OPTIONAL or MANDATORY.

It is also possible to specify optionality using @Nullable annotation.