Annotations

XXML supports a Java-style annotation system for adding metadata to code elements. Annotations can be processed at compile-time or retained for runtime reflection.

Defining Annotations

xxml
// Simple marker annotation
[ Annotation <Immutable> Allows (AnnotationAllow::Classes) ]

// Annotation with runtime retention
[ Annotation <Serializable> Allows (AnnotationAllow::Classes) Retain ]

// Annotation with parameters
[ Annotation <Range> Allows (AnnotationAllow::Properties) Retain
    Annotate (Integer^)(min);
    Annotate (Integer^)(max);
]

Annotation Targets

TargetDescription
AnnotationAllow::ClassesClass declarations
AnnotationAllow::MethodsMethod declarations
AnnotationAllow::PropertiesProperty declarations
AnnotationAllow::ParametersMethod parameters
AnnotationAllow::ConstructorsConstructor declarations
AnnotationAllow::AllAny target

Using Annotations

xxml
@Entity
@Serializable(format = "json")
[ Class <User> Final Extends None
    [ Public <>
        @Column(name = "user_id", nullable = false)
        Property <id> Types Integer^;

        @Column(name = "user_name", nullable = false)
        @MinLength(value = 1)
        Property <name> Types String^;

        @Range(min = 0, max = 150)
        Property <age> Types Integer^;
    ]
]

Default Values

Annotation parameters can have default values:

xxml
[ Annotation <Config> Allows (AnnotationAllow::Classes)
    Annotate (String^)(name);            // Required
    Annotate (Integer^)(version) = 1;    // Optional, default is 1
    Annotate (Bool^)(debug) = false;     // Optional, default is false
]

// Only required parameters need to be specified
@Config(name = "MyApp")  // version=1, debug=false by default
[ Class <App> ... ]

Inline Processors

Annotations can include inline processors that run during compilation:

xxml
[ Annotation <Review> Allows (AnnotationAllow::Classes, AnnotationAllow::Methods)
    Annotate (String^)(message);

    [ Processor
        [ Public <>
            Method <onAnnotate> Returns None Parameters (
                Parameter <reflectionContext> Types ReflectionContext&,
                Parameter <compilationContext> Types CompilationContext&
            ) -> {
                Run compilationContext.warning(
                    String::Constructor("Code is under review")
                );
            }
        ]
    ]
]

Note

Inline processors have access to ReflectionContext for inspecting the annotated element and CompilationContext for emitting messages, warnings, or errors.

Built-in Annotations

@Deprecated

xxml
@Deprecated
[ Class <OldApi> Final Extends None ... ]
// Compiler warning: class 'OldApi' is deprecated

@Deprecated(reason = "Use NewApi instead")
Method <oldMethod> Returns None Parameters () -> { ... }
// Compiler warning: method 'oldMethod' is deprecated: Use NewApi instead

@Derive

xxml
@Derive(trait = "Stringable")
@Derive(trait = "Equatable")
@Derive(trait = "Hashable")
[ Class <Point> Final Extends None ... ]

Complete Example

validation.xxml
#import Language::Core;

// Define validation annotations
[ Annotation <NotNull> Allows (AnnotationAllow::Properties) Retain ]

[ Annotation <Range> Allows (AnnotationAllow::Properties) Retain
    Annotate (Integer^)(min);
    Annotate (Integer^)(max);
]

[ Annotation <Pattern> Allows (AnnotationAllow::Properties) Retain
    Annotate (String^)(regex);
]

// Use annotations for validation metadata
[ Class <Registration> Final Extends None
    [ Public <>
        @NotNull
        @Pattern(regex = "^[a-zA-Z0-9_]+$")
        Property <username> Types String^;

        @NotNull
        @Range(min = 8, max = 128)
        Property <passwordLength> Types Integer^;

        @NotNull
        @Pattern(regex = "^[^@]+@[^@]+\\.[^@]+$")
        Property <email> Types String^;

        Constructor = default;
    ]
]

Next Steps

Learn about Derives for automatic method generation, or explore Reflection to access annotation metadata at runtime.