Skip to content

CloudEvent Factory Source Generator #69

Description

@tsutomi

Emit compile-time IEventConvertible implementations from [Event]-annotated classes, eliminating the runtime reflection path in EventFactory and shifting annotation errors left to the build.

The problem today: EventFactory.CreateEventFromData() resolves [Event] metadata via Type.GetCustomAttribute<>() on every publish call, allocating attribute objects and walking type metadata at runtime even in high-throughput paths. The IEventConvertible escape hatch already exists — the benchmarks show it is measurably faster — but it requires repetitive, hand-written ToCloudEvent() boilerplate on every event class. Annotation mistakes (missing DataVersion, non-public class) surface as ArgumentException at runtime rather than at build time.

What we will build: A Deveel.Events.Generators package — a Roslyn incremental source generator (targeting netstandard2.0 as required by the analyzer SDK) that:

  • Detects every partial class decorated with [Event] in the current compilation.
  • Emits a generated partial class body that implements IEventConvertible.ToCloudEvent(): all CloudEvents envelope values (Type, DataSchema, DataContentType) are sourced from annotation values captured at compile time; the Data field is populated via System.Text.Json serialisation — zero reflection at call time.
  • Emits compile-time diagnostics:
    • DLEVT001[Event] is applied to a non-partial class (generator cannot act; reflection path is used as a silent fallback).
    • DLEVT002[Event] specifies neither a DataVersion nor an absolute DataSchema URI.
    • DLEVT003[Event]-annotated class is not public.

Benefits:

  • Zero reflection on the publish hot-path — all attribute lookup is resolved at build time, matching the performance of hand-coded IEventConvertible implementations as measured in the existing benchmarks.
  • DLEVT001 / DLEVT002 / DLEVT003 shift errors that today manifest as ArgumentException at runtime into compile-time build failures, giving developers immediate feedback.
  • No breaking change — classes not declared partial continue to work via the existing reflection path; adopting the generator is a purely opt-in, incremental migration.
  • Works correctly in trimmed and ahead-of-time (AOT) compiled deployments where GetCustomAttribute calls on user types may be stripped.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request
    No fields configured for Feature.

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions