Meta-annotations

Apache Causeway supports the use of meta-annotations, as does Spring Boot and the ORM (JDO/DataNucleus from DN 5.x, JPA/EclipseLink from Eclipse 2.7 supporting JPA 2.2).

This allows you to define custom annotations that are more descriptive of your domain model, and meta-annotate your custom annotations with those of Apache Causeway, Spring or the ORM. In your domain model, you can just use the custom annotation.

The most common use case is to define meta-annotations for scalar types that are used in properties or parameters.

The SimpleApp starter app illustrates the usage with its @Name meta-annotation:

Name.java
@Column(length = Name.MAX_LEN, allowsNull = "false")                (1)
@Property(mustSatisfy = Name.Specification.class,                   (2)
          maxLength = Name.MAX_LEN)
@Parameter(mustSatisfy = Name.Specification.class,                  (3)
           maxLength = Name.MAX_LEN)
@ParameterLayout(named = "Name")                                    (4)
@Target({ ElementType.METHOD, ElementType.FIELD,                    (5)
          ElementType.PARAMETER, ElementType.ANNOTATION_TYPE })
@Retention(RetentionPolicy.RUNTIME)                                 (6)
public @interface Name {

    int MAX_LEN = 40;

    // ...

    class Specification extends AbstractSpecification2<String> {
        // ...
    }
}
1 ORM annotation
2 Annotations that are inferred if annotated on a property.
The @Property#mustSatisfy() allows arbitrary validation rules to be specified for the property.
3 Annotations that are inferred if annotated on a parameter
The @Parameter#mustSatisfy() allows the same validation rules to be specified for the parameter.
4 Layout annotations that are inferred if annotated on a parameter
5 The locations that the meta annotation can be applied
6 Required boilerplate to ensure that the meta annotation is part of the bytecode introspected at runtime

This annotation is used in the SimpleObject entity, for the "name" property and the "name" parameter of the "updateName()" action:

SimpleObject.java
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import lombok.ToString.Include;

@ToString(onlyExplicitlyIncluded = true)
public class SimpleObject implements Comparable<SimpleObject> {

    // ...

    @Name
    @Getter @Setter @ToString.Include
    private String name;

    // ...
    public SimpleObject updateName(
            @Name final String name) {
        setName(name);
        return this;
    }
    // ...
}

Properties vs Parameters

Since the ORM handles persistence, its annotations can only be specified for properties, not for action parameters. Using meta-annotations is a good way to unify the annotations that are required for properties vs parameters.

The table below summarises the equivalence of some of the most common cases.

Table 1. Comparing annotations of Properties vs Action Parameters
value type/semantic (JDO) property
javax.jdo.annotations
action parameter

string (length)

@Column(length=50)

@Parameter(maxLength=50)

big decimal (precision)

@Column(scale=2)

@javax.validation.constraints.Digits(fraction=2)

optionality

@Column(allowsNull="true")

@javax.annotation.Nullable or ParameterLayout(optionality=OPTIONAL)