Skip to content

[Feature]: Support Concrete JFR Event Classes in Typed API #89

Description

@diegolovison

Problem Statement

Problem

Currently, Jafar's typed API requires users to define interfaces annotated with @JfrType to parse JFR events. This creates friction when working with existing JFR event classes that extend jdk.jfr.Event.

Current limitation:

// This fails with: "JFR type handler must be an interface"
@Name("com.example.MyCustomEvent")
public class MyCustomEvent extends Event {
    @Label("Request ID")
    public String requestId;
    
    @Label("Duration")
    public long duration;
}

// User must create a separate interface
@JfrType("com.example.MyCustomEvent")
public interface MyCustomEventHandler {
    @JfrField("requestId") String requestId();
    @JfrField("duration") long duration();
}

Proposed Solution

Allow the typed API to accept concrete JFR event classes directly by:

  1. Detecting JFR event classes: Check if the class extends jdk.jfr.Event and has @Name annotation
  2. Automatic field mapping: Map public fields annotated with @Label to JFR field names
  3. Fallback to interface requirement: Maintain current behavior for non-JFR classes

Example usage:

@Name("com.example.MyCustomEvent")
public class MyCustomEvent extends Event {
    @Label("Request ID")
    public String requestId;
    
    @Label("Duration")
    public long duration;
}

// Direct usage without interface
try (TypedJafarParser p = JafarParser.newTypedParser(path)) {
    p.handle(MyCustomEvent.class, (e, ctl) -> {
        System.out.println("Request: " + e.requestId);
        System.out.println("Duration: " + e.duration);
    });
    p.run();
}

Benefits

  • Reduced boilerplate: No need to duplicate event structure as interfaces
  • Better integration: Works seamlessly with existing JFR instrumentation code
  • Consistency: Event definition and parsing use the same class
  • Backward compatible: Existing interface-based code continues to work

Workarounds (Current)

Users must use the untyped API or EventIterator for concrete event classes:

// Untyped API
try (UntypedJafarParser p = JafarParser.newUntypedParser(path)) {
    p.handle((type, event, ctl) -> {
        if ("com.example.MyCustomEvent".equals(type.getName())) {
            String requestId = (String) event.get("requestId");
        }
    });
    p.run();
}

Proposed Solution

TBD

Alternatives Considered

No response

API Example

Breaking Change?

No - Additive change only

Priority

Important

Additional Context

No response

Checklist

  • I have searched existing issues and this feature hasn't been requested
  • I have checked LIMITATIONS.md to see if this is a known limitation
  • I would be willing to contribute this feature

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions