@Column (jdo)

The JDO @javax.jdo.annotation.Column provides metadata describing how JDO/DataNucleus should persist the property to a database RDBMS table column (or equivalent concept for other persistence stores).

Apache Causeway also parses and interprets this annotation in order to build up aspects of its metamodel.

Apache Causeway parses the @Column annotation from the Java source code; it does not query the JDO metamodel. This means that it the @Column annotation must be used rather than the equivalent <column> XML metadata.

Moreover, while JDO/DataNucleus will recognize annotations on either the field or the getter method, Apache Causeway (currently) only inspects the getter method. Therefore ensure that the annotation is placed there.

This section identifies which attributes of @Column are recognized and used by Apache Causeway.

Nullability

The allowsNull attribute is used to specify if a property is mandatory or is optional.

For example:

public class Customer {
    @javax.jdo.annotations.Column(allowsNull="true")
    public String getMiddleInitial() { /* ... */ }
    public void setMiddleInitial(String middleInitial) { /* ... */ }

Causeway also provides @Property#optionality attribute. If both are specified, Apache Causeway will check when it initializes for any contradictions, and will fail-fast with an appropriate error message in the log if there are.

You should also be aware that in the lack of either the @Column#allowsNull or the @Property#optionality attributes, that the JDO and Apache Causeway defaults differ. Apache Causeway rule is straight-forward: properties are assumed to be required. JDO on the other hand specifies that only primitive types are mandatory; everything else is assumed to be optional. Therefore a lack of either annotation can also trigger the fail-fast validation check.

In the vast majority of cases you should be fine just to add the @Column#allowsNull attribute to the getter. But see the documentation for @Property#optionality attribute for discussion on one or two minor edge cases.

Length for Strings

The length attribute is used to specify the length of java.lang.String property types as they map to varchar(n) columns.

For example:

public class Customer {
    @javax.jdo.annotations.Column(length=20)
    public String getFirstName() { /* ... */ }
    public void setFirstName(String firstName) { /* ... */ }
    @javax.jdo.annotations.Column(allowsNull="true", length=1)
    public String getMiddleInitial() { /* ... */ }
    public void setMiddleInitial(String middleInitial) { /* ... */ }
    @javax.jdo.annotations.Column(length=30)
    public String getLastName() { /* ... */ }
    public void setLastName(String lastName) { /* ... */ }

Apache Causeway also provides @Property#maxLength attribute. If both are specified, Apache Causeway will check when it initializes for any contradictions, and will fail-fast with an appropriate error message in the log if there are.

Length/scale for BigDecimals

The length() and scale attributes are used to infer the precision/scale of java.math.BigDecimal property types as they map to decimal(n,p) columns.

For example:

public class Customer {
    @javax.jdo.annotations.Column(length=10, scale=2)
    public BigDecimal getTotalOrdersToDate() { /* ... */ }
    public void setTotalOrdersToDate(BigDecimal totalOrdersToDate) { /* ... */ }

For BigDecimals it is also possible to specify the @Digits annotation, whose form is @Digits(integer, fraction). There is a subtle difference here: while @Column#scale() corresponds to @Digits#fraction(), the value of @Column#length() (ie the precision) is actually the sum of the @Digits’ `integer() and fraction() parts.

If both are specified, Apache Causeway will check when it initializes for any contradictions, and will fail-fast with an appropriate error message in the log if there are.

Hints and Tips

This seems to be a good place to describe some additional common mappings that use @Column. Unlike the sections above, the attributes specified in these hints and tips aren’t actually part of Apache Causeway metamodel.

Mapping foreign keys

The name attribute can be used to override the name of the column. References to other objects are generally mapped as foreign key columns. If there are multiple references to a given type, then you will want to override the name that JDO/DataNucleus would otherwise default.

For example:

public class PartyRelationship {
    @Column(name = "fromPartyId", allowsNull = "false")
    public Party getFrom() { /* ... */ }
    public void setFrom(Party from) { /* ... */ }
    @Column(name = "toPartyId", allowsNull = "false")
    public Party getTo() { /* ... */ }
    public void setTo(Party to) { /* ... */ }
    ...
}

Mapping Blobs and Clobs

Causeway provides custom value types for Blobs and Clobs. These value types have multiple internal fields, meaning that they corresponding to multiple columns in the database. Mapping this correctly requires using @Column within JDO’s @Persistent annotation.

For example, here’s how to map a Blob:

private Blob attachment;
@javax.jdo.annotations.Persistent(defaultFetchGroup="false", columns = {
        @javax.jdo.annotations.Column(name = "attachment_name"),
        @javax.jdo.annotations.Column(name = "attachment_mimetype"),
        @javax.jdo.annotations.Column(name = "attachment_bytes", jdbcType = "BLOB", sqlType = "LONGVARBINARY")
})
@Property(
        domainEvent = AttachmentDomainEvent.class,
        optionality = Optionality.OPTIONAL
)
public Blob getAttachment() { /* ... */ }
public void setAttachment(Blob attachment) { /* ... */ }

And here’s how to map a Clob (also taken from the todoapp):

private Clob doc;
@javax.jdo.annotations.Persistent(defaultFetchGroup="false", columns = {
        @javax.jdo.annotations.Column(name = "doc_name"),
        @javax.jdo.annotations.Column(name = "doc_mimetype"),
        @javax.jdo.annotations.Column(name = "doc_chars", jdbcType = "CLOB", sqlType = "LONGVARCHAR")
})
@Property(
        optionality = Optionality.OPTIONAL
)
public Clob getDoc() { /* ... */ }
public void setDoc(final Clob doc) { /* ... */ }