[#javax-jdo-annotation-Column]
= @Column (jdo)

:Notice: Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at. http://www.apache.org/licenses/LICENSE-2.0 . Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR  CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.


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 Isis also parses and interprets this annotation in order to build up aspects of its metamodel.

[NOTE]
====
Apache Isis 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>` link:http://www.datanucleus.org/products/accessplatform_4_0/jdo/orm/schema_mapping.html[XML metadata].

Moreover, while JDO/DataNucleus will recognize annotations on either the field or the getter method, Apache Isis (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 Isis.

[#nullability]
== Nullability

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

For example:

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

Isis also provides xref:refguide:applib:index/annotation/Property.adoc#optionality[@Property#optionality] attribute.
If both are specified, Apache Isis 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 Isis defaults differ.
Apache Isis 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 xref:refguide:applib:index/annotation/Property.adoc#optionality[@Property#optionality] attribute for discussion on one or two minor edge cases.

[#length-for-strings]
== Length for ``String``s

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

For example:

[source,java]
----
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 Isis also provides xref:refguide:applib:index/annotation/Property.adoc#maxLength[@Property#maxLength] attribute.
If both are specified, Apache Isis will check when it initializes for any contradictions, and will fail-fast with an appropriate error message in the log if there are.

[#lengthscale-for-bigdecimals]
== Length/scale for ``BigDecimal``s

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:

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

For ``BigDecimal``s it is also possible to specify the xref:refguide:applib-ant:Digits.adoc[@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 Isis will check when it initializes for any contradictions, and will fail-fast with an appropriate error message in the log if there are.

[[rg-ant-hints-and-tips]]
== 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 Isis 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:

[source,java]
----
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 ``Blob``s and ``Clob``s

Isis provides custom value types for xref:refguide:applib:index/value/Blob.adoc[Blob]s and xref:refguide:applib:index/value/Clob.adoc[Clob]s.
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`:

[source,java]
----
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):

[source,java]
----
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) { /* ... */ }
----
