Reflection

XXML's reflection system allows runtime introspection of types, enabling frameworks for serialization, validation, and dependency injection.

Import

xxml
#import Language::Reflection;

Type Class

The Type class provides access to type metadata:

xxml
// Get type information by name
Instantiate Type^ As <type> = Type::forName(String::Constructor("MyClass"));

// Get type name
Instantiate String^ As <name> = type.getName();

// Check if class is final
Instantiate Bool^ As <isFinal> = type.isFinal();

// Get base class name
Instantiate String^ As <base> = type.getBaseClassName();

Property Introspection

xxml
// Get property count
Instantiate Integer^ As <count> = type.getPropertyCount();

// Iterate over properties
For (Integer <i> = 0 .. count) -> {
    Instantiate PropertyInfo^ As <prop> = type.getPropertyAt(i);

    Instantiate String^ As <propName> = prop.getName();
    Instantiate String^ As <propType> = prop.getTypeName();
    Instantiate String^ As <ownership> = prop.getOwnership();

    Run Console::printLine(propName);
}

Method Introspection

xxml
// Get method count
Instantiate Integer^ As <methodCount> = type.getMethodCount();

// Get method by name
Instantiate MethodInfo^ As <method> = type.getMethodByName(String::Constructor("doSomething"));

// Get method details
Instantiate String^ As <returnType> = method.getReturnTypeName();
Instantiate Integer^ As <paramCount> = method.getParameterCount();

Annotation Access

Access annotations that were marked with Retain:

xxml
// Check annotation count
Instantiate Integer^ As <annotCount> = type.getAnnotationCount();

// Get annotation by index
Instantiate AnnotationInfo^ As <annot> = type.getAnnotationAt(Integer::Constructor(0));

// Get annotation name
Instantiate String^ As <annotName> = annot.getName();

// Get annotation arguments
Instantiate AnnotationArg^ As <arg> = annot.getArgumentByName(String::Constructor("value"));
Instantiate String^ As <argValue> = arg.asString();

Note

Only annotations declared with the Retain keyword are available at runtime. Compile-time-only annotations are discarded after processing.

Complete Example

reflection-example.xxml
#import Language::Core;
#import Language::Reflection;

[ Annotation <Entity> Allows (AnnotationAllow::Classes) Retain
    Annotate (String^)(tableName);
]

@Entity(tableName = "users")
[ Class <User> Final Extends None
    [ Public <>
        Property <id> Types Integer^;
        Property <name> Types String^;
        Constructor = default;
    ]
]

[ Entrypoint
    {
        // Get type info
        Instantiate Type^ As <type> = Type::forName(String::Constructor("User"));

        // Read annotation
        Instantiate AnnotationInfo^ As <entity> = type.getAnnotationAt(Integer::Constructor(0));
        Instantiate AnnotationArg^ As <tableArg> = entity.getArgumentByName(String::Constructor("tableName"));

        Run Console::printLine(String::Constructor("Table: ").append(tableArg.asString()));
        // Output: Table: users

        // List properties
        Instantiate Integer^ As <propCount> = type.getPropertyCount();
        For (Integer <i> = 0 .. propCount) -> {
            Instantiate PropertyInfo^ As <prop> = type.getPropertyAt(i);
            Run Console::printLine(prop.getName());
        }
        // Output: id, name

        Exit(0);
    }
]

Use Cases

  • Serialization: Automatically convert objects to JSON/XML based on their structure
  • Validation: Read validation annotations and verify property values
  • Dependency Injection: Automatically wire dependencies based on annotations
  • ORM: Map classes to database tables using reflection

Next Steps

Learn about Annotations to define custom metadata for your classes.