Hi Adnan,

I agree that Java records lack some flexibility but I think we can
achieve a nice layout. Here is a tentative design:

public interface PolarisEvent {
  UUID id();
  Instant timestamp();
  PolarisPrincipal user();
  static UUID createEventId() { return UUID.randomUUID(); }
}

Here is a typical event record:

public record BeforeSomethingEvent(
    UUID id,
    Instant timestamp,
    PolarisPrincipal user,
    String someOtherParameter)
    implements PolarisEvent {}

And here is a typical event instantiation idiom:

@Inject SecurityContext securityContext;
@Inject Clock clock;

new BeforeSomethingEvent(
    PolarisEvent.createEventId(),
    clock.instant(),
    (PolarisPrincipal) securityContext.getUserPrincipal(),
    "someParameter");

What do you think of the above?

Thanks,
Alex

On Fri, Oct 24, 2025 at 10:15 AM Adnan Hemani
<[email protected]> wrote:
>
> Hi Alex,
>
> I had thought about this earlier and abandoned the idea due to implementation 
> concerns. So, my question is how exactly will these methods be implemented 
> and used?
>
> Let’s take id() as the talking point, but similar points can be applied to 
> timestamp(). PolarisEvent is an interface and all implementations of this 
> interface are Java records - as a result, neither PolarisEvent nor its 
> implementations can contain non-static instance fields. So if a PolarisEvent 
> cannot save its ID through a non-static instance field, how do we guarantee 
> idempotency if id() is called twice on an instance of PolarisEvent?
>
> The other way I see is we instead include id, timestamp, and user as named 
> arguments of every record signature along with a custom constructor which 
> will generate the new ID and timestamp - which makes the code extremely messy 
> IMO (and was one of the original reasons why we stuck to using an Interface 
> for PolarisEvent rather than switching over to an ABC, which I had proposed 
> earlier). Or we go towards using an intermediate ABC with PolarisEvent 
> re-written as a Sealed Interface, with each record extending the intermediate 
> ABC. I’m not sure I understand the ramifications of doing this yet, so cannot 
> endorse this approach either.
>
> Did I miss some other way to make this work? Or were you thinking of 
> something completely different?
>
> Best,
> Adnan Hemani
>
> > On Oct 23, 2025, at 10:18 AM, Alexandre Dutra <[email protected]> wrote:
> >
> > Hi all,
> >
> > Just to be clear, and sorry for the confusion: the idea was to add
> > those methods to the PolarisEvent interface, not PolarisEventListener.
> >
> > I agree with Mike that PolrisEventListener shouldn't deal with context
> > data. In my mind, each PolarisEvent instance would carry its own ID,
> > timestamp (at creation time) and user (the principal that triggered
> > the event).
> >
> > Thanks,
> > Alex
> >
> > On Thu, Oct 23, 2025 at 7:08 PM Michael Collado <[email protected]> 
> > wrote:
> >>
> >> +1 on adding the described fields to the PolarisEvent.
> >>
> >> I don't think the PolarisEventListener is really the right place to add any
> >> default methods about context, though. I'm not sure if you meant adding
> >> those to the PolarisEvent interface so that existing records have a default
> >> value?
> >>
> >> Mike
> >>
> >> On Wed, Oct 22, 2025 at 10:26 PM Jean-Baptiste Onofré <[email protected]>
> >> wrote:
> >>
> >>> Hi Alex
> >>>
> >>> It makes sense to me.
> >>>
> >>> Are you also proposing to have default methods in the interface ?
> >>>
> >>> interface PolarisEventListener {
> >>>
> >>>  default UUID id() { ... }
> >>>
> >>>  default Instant timestamp() { ... }
> >>>
> >>>  default PolarisPrincipal user() { ... }
> >>>
> >>> }
> >>>
> >>> Maybe we can have a default behavior that implementations can
> >>> "override" if needed.
> >>>
> >>> Regards
> >>> JB
> >>>
> >>> On Wed, Oct 22, 2025 at 5:08 PM Alexandre Dutra <[email protected]> wrote:
> >>>>
> >>>> Hi all,
> >>>>
> >>>> We have two (albeit incomplete) PolarisEventListener implementations
> >>>> today: one for JDBC and one for AWS CloudWatch.
> >>>>
> >>>> Both enhance event payloads internally by adding a timestamp and user
> >>>> data. These two attributes are indeed very common in event-oriented
> >>>> systems.
> >>>>
> >>>> The JDBC implementation also generates unique IDs internally. That's
> >>>> because the PolarisEvent interface lacks an id() method, despite the
> >>>> common need for event disambiguation.
> >>>>
> >>>> Therefore, I propose promoting these three attributes (ID, timestamp,
> >>>> user) to the PolarisEvent interface, by adding the following methods:
> >>>>
> >>>> UUID id();
> >>>> Instant timestamp();
> >>>> PolarisPrincipal user();
> >>>>
> >>>> This information is readily available at event instantiation sites,
> >>>> and can be provided via CDI injection without hassle.
> >>>>
> >>>> Let me know your thoughts.
> >>>>
> >>>> Thanks,
> >>>> Alex
> >>>
>

Reply via email to