Skip to content

Semantic (Composed) Annotations

A semantic annotation is a domain annotation of your own that bundles one or more Mateu annotations. Instead of repeating the same configuration on every field, you declare it once and reuse a meaningful name.

For example, a string field that holds a supplier id is normally a @Lookup with an options supplier and a label supplier:

@Lookup(search = ProveedorOptionsSupplier.class, label = ProveedorLabelSupplier.class)
String proveedorId;

Define it once as a semantic annotation:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@Lookup(search = ProveedorOptionsSupplier.class, label = ProveedorLabelSupplier.class)
public @interface ProveedorId {}

…and use the meaningful name everywhere:

@ProveedorId String proveedorId;

Mateu treats the field exactly as if it carried the underlying @Lookup (with its attributes). It renders as a lookup combo backed by the suppliers.

When Mateu looks for an annotation A on a field, method or class, it considers A present if it sits there directly or transitively through another annotation that is itself meta-annotated with A. This is resolved by MetaAnnotations and behaves like Spring’s findMergedAnnotation (minimal — it returns the first matching meta-annotation; there is no attribute overriding / @AliasFor).

A single semantic annotation can meta-annotate several Mateu annotations; each one is resolved independently:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@Stereotype(FieldStereotype.money)
@Label("Importe total (€)")
@Help("Importe total del pedido, IVA incluido")
public @interface ImporteTotal {}
@ImporteTotal BigDecimal granTotal; // money stereotype + label + helper text

Composition works at every level.

Method — bundle action annotations:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Toolbar
@Label("Guardar")
public @interface AccionGuardar {}
// usage
@AccionGuardar
Object guardar(HttpRequest httpRequest) { return Message.success("Guardado"); }

Class — bundle screen-level configuration:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Compact
public @interface PantallaCompacta {}
// usage
@UI("/pedidos")
@PantallaCompacta
public class Pedidos { /* … */ }

Every Mateu field, method and class annotation can be used as a meta-annotation — @Stereotype, @Status, @Style, @Label, @Help, @ColumnWidth, @PlainText, @Multiline, @ReadOnly, @Lookup, @Searchable, @Toolbar, @Button, @Banner, @Fab, @Compact, @Zones, @Title, … — and they can be combined freely on one domain annotation.

If you add a new Mateu-style field/method/class annotation and want it to be usable as a meta-annotation:

  1. Add ElementType.ANNOTATION_TYPE to its @Target (so it can be placed on an annotation type).
  2. Read it with MetaAnnotations.find(element, X.class) / MetaAnnotations.isPresent( element, X.class) rather than element.getAnnotation(X.class).

All built-in Mateu annotations already satisfy (1) and are read through (2).