Skip to content

Conversation

@adutra
Copy link
Contributor

@adutra adutra commented Sep 19, 2025

Summary of changes:

  • Turned PolarisEventListener into an interface to facilitate implementation / mocking
  • Added missing implements PolarisEvent to many event records
  • Removed unused method overrides
  • Added missing method overrides to TestPolarisEventListener

@adutra
Copy link
Contributor Author

adutra commented Sep 19, 2025

cc @adnanhemani

* Event details are documented under the event objects themselves.
*/
public abstract class PolarisEventListener {
public interface PolarisEventListener {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was extensively debated at the time, but see this comment and related ones for why this is an ABC rather than an interface.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for flagging it, @eric-maynard. I still hold my point, that this should be ABC, not interface.

Copy link
Contributor Author

@adutra adutra Sep 22, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you both for reviving this discussion. I've re-read the old thread carefully, and I still do not understand what the problem is with using an interface rather than an abstract class.

Can you please summarize your concerns here for clarity?

If it's about binary compatibility when adding more methods to the API, I'm afraid an interface and an ABC provide roughly the same linkage risks. From JLS 13.4.16 (emphasis mine):

adding a default method is a binary-compatible change because it does not introduce errors at link time, even if it introduces errors at compile time or invocation time. In practice, the risk of accidental clashes occurring by introducing a default method are similar to those associated with adding a new method to a non-final class.

In contrast, the advantages of using interfaces rather than abstract classes in public APIs are abundantly documented. From Effective Java, 3rd Edition (J. Bloch, 2017) (emphasis mine):

Item 20: Prefer interfaces to abstract classes
Java has two mechanisms to define a type that permits multiple implementations: interfaces and abstract classes. Since the introduction of default methods for interfaces in Java 8 [JLS 9.4.3], both mechanisms allow you to provide implementations for some instance methods. A major difference is that to implement the type defined by an abstract class, a class must be a subclass of the abstract class. Because Java permits only single inheritance, this restriction on abstract classes severely constrains their use as type definitions. Any class that defines all the required methods and obeys the general contract is permitted to implement an interface, regardless of where the class resides in the class hierarchy.

Copy link
Contributor

@flyrain flyrain Sep 22, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, binary compatibility is the concern. The upstream changes shouldn't break downstream event listeners. However, looking over the PR, it looks like all methods are now default methods, which is fine. Let's also ensure that any new methods added in the future are default as well.

Could we add a test to enforce this? It might also be helpful to include a comment on the class to explicitly state that all new methods should be default.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @flyrain thanks for your flexibility 🙂

I will add the comment and the test as suggested.

I'd note that this kind of check would be a good fit for the revapi plugin – the same one we use in Iceberg to track API breaking changes. But I think Polaris is still a young project, and revapi would flag too many API changes that would be otherwise permitted by our current evolution rules:

Changes in Java class should be expected at any time regardless of the module name or
whether the class / method is `public` or not.

So, let's stick with a small test for now 👍

Copy link
Contributor Author

@adutra adutra Sep 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a comment and tests as suggested.

I also re-organized the interface methods into "sections" for clarity, I hope that's OK.

The tests check that all methods are default and well-formed, and also that all events have corresponding methods in the interface.

I added a similar check to TestPolarisEventListener (it was lacking many methods).

Summary of changes:

- Turned `PolarisEventListener` into an interface to facilitate implementation / mocking
- Added missing `implements PolarisEvent` to many event records
- Removed unused method overrides
- Added missing method overrides to `TestPolarisEventListener`
@adutra adutra force-pushed the event-listener-interface branch from 8f674f4 to 1c50978 Compare September 22, 2025 09:23
@Override
public Response listCatalogs(RealmContext realmContext, SecurityContext securityContext) {
polarisEventListener.onBeforeListCatalog(new CatalogsServiceEvents.BeforeListCatalogEvent());
polarisEventListener.onBeforeListCatalogs(new CatalogsServiceEvents.BeforeListCatalogsEvent());
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When I added tests for method compliance I noticed that this event was different from other "list" events because the object type being listed wasn't in the plural.

@adutra
Copy link
Contributor Author

adutra commented Sep 25, 2025

@flyrain @eric-maynard is the code looking better now?

Copy link
Contributor

@flyrain flyrain left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 Thanks @adutra for the PR!

@github-project-automation github-project-automation bot moved this from PRs In Progress to Ready to merge in Basic Kanban Board Sep 26, 2025
@adutra adutra merged commit 19742cc into apache:main Sep 26, 2025
14 checks passed
@github-project-automation github-project-automation bot moved this from Ready to merge to Done in Basic Kanban Board Sep 26, 2025
@adutra adutra deleted the event-listener-interface branch September 26, 2025 08:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants