Skip to main content

Annotations

An annotation attaches information to a declaration without changing its behaviour: the address of a model, the label of a parameter, the table a concept is stored in. Annotations are written before the element they describe, and they are how FML carries everything that is not structure.

Four shapes​

An annotation is @ and a name, followed by nothing, a value, named values, or other annotations:

@Marker
@Note("hello")
@Owner(name="Ann", team="core")
@Groups(
@Member("a")
@Member("b")
)
  • @Marker is a flag: it says something by being there.
  • @Note("hello") has a value.
  • @Owner(name="Ann", team="core") has named values.
  • @Groups(…) contains annotations, which is how a group of related annotations is written.

A value is an expression: a string, a number, or a path such as name.

Where they go​

Annotations go before a model, a concept, an event, a property or a behaviour:

@URI("http://openflexo.org/test/TestResourceCenter/Tagged.fml")
@Version("2")
@Marker
@Note("hello")
@Owner(name="Ann", team="core")
@Groups(
@Member("a")
@Member("b")
)
public model Tagged {
@Renderer(name + "!")
public concept Card {

@Hint("on a property")
String name;

create(String name) {
name = parameters.name;
}

@Hint("on a behaviour")
public String greet() {
return "hi";
}
}

Kept, whatever the name​

The platform keeps every annotation it reads on the element it precedes, and writes it back as it was written, whether it knows the name or not. Here @Marker, @Note, @Owner, @Groups, @Member and @Hint mean nothing to the platform, and are all kept:

assert virtualModel.hasMetaData("Marker");
assert virtualModel.hasMetaData("Note");
assert virtualModel.hasMetaData("Owner");
assert virtualModel.hasMetaData("Groups");
assert virtualModel.hasMetaData("Nope") == false;
card = virtualModel.getFlexoConcept("Card");
assert card.hasMetaData("Renderer");
assert card.getDeclaredProperty("name").hasMetaData("Hint");

This makes annotations a way to carry your own information: a tool that reads the model can look for its annotations. The other side is that a misspelled annotation is not an error: @Discription is kept like any other, and does nothing.

Annotations the platform reads​

AnnotationOnWhat it does
@URI("…")a modelgives the address of the model
@Version("…")a modelgives its version
@Description("…")a modela short text
@Renderer(expression)a conceptgives the string representation of its instances
@UI(…)a behaviourdescribes how the application asks for its arguments

@URI, @Version and @Description. They are read back when the model is loaded. A version is normalised: @Version("2") gives the version 2.0.

assert virtualModel.version.toString() == "2.0";

@Renderer. The expression is evaluated on each instance of the concept to give its string representation, the text obtained when the instance is concatenated to a string. It follows the properties it reads, and it applies to the concepts that extend the concept:

first = "" + c1;
assert first == "x!";
c1.name = "y";
second = "" + c1;
assert second == "y!";
public concept Gold extends Card {

create(String name) {
super(parameters.name);
}
}
g1 = tagged.newGold("z");
third = "" + g1;
assert third == "z!";

@UI. It holds one annotation per argument of a behaviour, to choose the widget the application uses in the dialog that asks for the arguments. value names the argument and label gives the label of the widget:

@UI(
@TextField(value="title", label="book_title")
)
public Book newBook(required String title) {

The dialog exists only in the application: the examples of this guide check that the annotation is loaded, not the dialog.

Annotations of a technology adapter​

A technology adapter defines annotations for its own needs. The JDBC adapter maps the concepts of a model onto a relational schema with @Table on a concept and @Property on its properties:

@Table("CLIENT")
public concept Client {
@Property(column="ID", id="true")
int id;
@Property(column="NAME")
String name;
@Property(column="SALESMAN", fk="ID")
Salesman salesman with ConceptInstance();
}

@Table names the table, and @Property gives the column (column), marks the identifier (id) and describes a reference to another table (fk, or mappedBy for the other side). The adapters document their own annotations. The model above is loaded by the tests of the JDBC adapter, in the openflexo-jdbc repository.

What you have seen​

An annotation is @Name, @Name(value), @Name(key=value, …) or @Name(other annotations), placed before a model, a concept, a property or a behaviour. The platform keeps every one and prints it back; it interprets @URI, @Version, @Description, @Renderer and @UI, and the technology adapters interpret theirs. Nothing checks the name of an annotation, so a misspelling passes silently.

The model and script (Tagged.fml and TestTagged.fmlscript, and Library.fml for @UI) are tests of the platform, in the openflexo-core repository.