Skip to content

[#10464] refactor(iceberg): decouple listener events from Iceberg API models#10558

Open
yuqi1129 wants to merge 2 commits intomainfrom
fix-10464-iceberg-event-decouple
Open

[#10464] refactor(iceberg): decouple listener events from Iceberg API models#10558
yuqi1129 wants to merge 2 commits intomainfrom
fix-10464-iceberg-event-decouple

Conversation

@yuqi1129
Copy link
Copy Markdown
Contributor

What changes were proposed in this pull request?

  • Refactor Iceberg listener post/failure event payloads to avoid direct dependencies on Iceberg REST request/response classes.
  • Replace event fields/getters from Iceberg types (for example, CreateTableRequest, LoadTableResponse) to Map<String, Object> payloads.
  • Add IcebergRESTUtils.toSerializableMap(Object) to deep-clone event payloads into serializable map structures.
  • Apply this change consistently across table/namespace/view post and failure events.

Why are the changes needed?

Fix: #10464

Does this PR introduce any user-facing change?

  • Listener event payload accessors now return Map<String, Object> instead of Iceberg-specific classes for affected post/failure events.

How was this patch tested?

  • ./gradlew :iceberg:iceberg-rest-server:compileJava
  • ./gradlew :iceberg:iceberg-rest-server:test --tests org.apache.gravitino.iceberg.service.rest.TestIcebergTableOperations --tests org.apache.gravitino.iceberg.service.rest.TestIcebergNamespaceOperations --tests org.apache.gravitino.iceberg.service.rest.TestIcebergViewOperations

… models

Refactor Iceberg listener post/failure events to store serializable payload maps instead of Iceberg REST request/response classes.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings March 26, 2026 12:18
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR refactors Iceberg REST server listener post and failure event payloads to no longer expose Iceberg REST request/response model classes, using Map<String, Object> payloads instead to reduce cross-module coupling.

Changes:

  • Replace event payload fields/getters from Iceberg REST request/response types to Map<String, Object> across many table/namespace/view post & failure events.
  • Add IcebergRESTUtils.toSerializableMap(Object) to convert (deep-clone) payload objects into JSON-serializable map structures.
  • Update event constructors to accept Object inputs and store them as serializable maps.

Reviewed changes

Copilot reviewed 22 out of 22 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
iceberg/iceberg-rest-server/src/main/java/org/apache/gravitino/listener/api/event/IcebergUpdateTableFailureEvent.java Update-table failure payload now stored as Map<String, Object>.
iceberg/iceberg-rest-server/src/main/java/org/apache/gravitino/listener/api/event/IcebergUpdateTableEvent.java Update-table post event payloads now stored as maps.
iceberg/iceberg-rest-server/src/main/java/org/apache/gravitino/listener/api/event/IcebergUpdateNamespaceFailureEvent.java Update-namespace failure payload now stored as a map.
iceberg/iceberg-rest-server/src/main/java/org/apache/gravitino/listener/api/event/IcebergUpdateNamespaceEvent.java Update-namespace post event payloads now stored as maps.
iceberg/iceberg-rest-server/src/main/java/org/apache/gravitino/listener/api/event/IcebergReplaceViewFailureEvent.java Replace-view failure payload now stored as a map.
iceberg/iceberg-rest-server/src/main/java/org/apache/gravitino/listener/api/event/IcebergReplaceViewEvent.java Replace-view post event payloads now stored as maps.
iceberg/iceberg-rest-server/src/main/java/org/apache/gravitino/listener/api/event/IcebergRenameViewFailureEvent.java Rename-view failure event signature changed to Object payload.
iceberg/iceberg-rest-server/src/main/java/org/apache/gravitino/listener/api/event/IcebergRenameViewEvent.java Rename-view post event payload now stored as a map.
iceberg/iceberg-rest-server/src/main/java/org/apache/gravitino/listener/api/event/IcebergRenameTableFailureEvent.java Rename-table failure event signature changed to Object payload.
iceberg/iceberg-rest-server/src/main/java/org/apache/gravitino/listener/api/event/IcebergRenameTableEvent.java Rename-table post event payload now stored as a map.
iceberg/iceberg-rest-server/src/main/java/org/apache/gravitino/listener/api/event/IcebergRegisterTableFailureEvent.java Register-table failure payload now stored as a map.
iceberg/iceberg-rest-server/src/main/java/org/apache/gravitino/listener/api/event/IcebergRegisterTableEvent.java Register-table post event payloads now stored as maps.
iceberg/iceberg-rest-server/src/main/java/org/apache/gravitino/listener/api/event/IcebergLoadViewEvent.java Load-view post payload now stored as a map.
iceberg/iceberg-rest-server/src/main/java/org/apache/gravitino/listener/api/event/IcebergLoadTableEvent.java Load-table post payload now stored as a map.
iceberg/iceberg-rest-server/src/main/java/org/apache/gravitino/listener/api/event/IcebergLoadNamespaceEvent.java Load-namespace post payload now stored as a map.
iceberg/iceberg-rest-server/src/main/java/org/apache/gravitino/listener/api/event/IcebergCreateViewFailureEvent.java Create-view failure payload now stored as a map.
iceberg/iceberg-rest-server/src/main/java/org/apache/gravitino/listener/api/event/IcebergCreateViewEvent.java Create-view post payloads now stored as maps.
iceberg/iceberg-rest-server/src/main/java/org/apache/gravitino/listener/api/event/IcebergCreateTableFailureEvent.java Create-table failure payload now stored as a map.
iceberg/iceberg-rest-server/src/main/java/org/apache/gravitino/listener/api/event/IcebergCreateTableEvent.java Create-table post payloads now stored as maps.
iceberg/iceberg-rest-server/src/main/java/org/apache/gravitino/listener/api/event/IcebergCreateNamespaceFailureEvent.java Create-namespace failure payload now stored as a map.
iceberg/iceberg-rest-server/src/main/java/org/apache/gravitino/listener/api/event/IcebergCreateNamespaceEvent.java Create-namespace post payloads now stored as maps.
iceberg/iceberg-rest-server/src/main/java/org/apache/gravitino/iceberg/service/IcebergRESTUtils.java Adds toSerializableMap(Object) helper used by event classes.

this.loadTableResponse =
IcebergRESTUtils.cloneIcebergRESTObject(loadTableResponse, LoadTableResponse.class);
this.updateTableRequest = IcebergRESTUtils.toSerializableMap(updateTableRequest);
this.loadTableResponse = IcebergRESTUtils.toSerializableMap(loadTableResponse);
}

Copy link

Copilot AI Mar 26, 2026

Choose a reason for hiding this comment

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

The getter name createTableRequest() is inconsistent with the event and the underlying field (updateTableRequest). This looks like a copy/paste mistake and will confuse listener implementations. Consider adding a correctly named accessor (e.g., updateTableRequest()), and either renaming this method or deprecating it for backward compatibility.

Suggested change
/**
* Returns the serialized update table request associated with this event.
*
* @return A map representing the update table request.
*/
public Map<String, Object> updateTableRequest() {
return updateTableRequest;
}
/**
* @deprecated Use {@link #updateTableRequest()} instead.
*/
@Deprecated

Copilot uses AI. Check for mistakes.
Comment on lines +44 to 47
public Map<String, Object> renameViewRequest() {
return replaceViewRequest;
}

Copy link

Copilot AI Mar 26, 2026

Choose a reason for hiding this comment

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

The getter renameViewRequest() returns replaceViewRequest, which doesn’t match the operation (replace/alter view) and is misleading for API consumers. Consider exposing a replaceViewRequest() accessor (and optionally deprecating/renaming renameViewRequest() to preserve compatibility).

Suggested change
public Map<String, Object> renameViewRequest() {
return replaceViewRequest;
}
/**
* Returns the serialized replace view request.
*
* @return the replace view request map
*/
public Map<String, Object> replaceViewRequest() {
return replaceViewRequest;
}
/**
* Returns the serialized replace view request.
*
* @return the replace view request map
* @deprecated Use {@link #replaceViewRequest()} instead.
*/
@Deprecated
public Map<String, Object> renameViewRequest() {
return replaceViewRequest();
}

Copilot uses AI. Check for mistakes.
Comment on lines +28 to 41
private final Object renameViewRequest;

public IcebergRenameViewFailureEvent(
IcebergRequestContext icebergRequestContext,
NameIdentifier viewIdentifier,
RenameTableRequest renameViewRequest,
Object renameViewRequest,
Exception e) {
super(icebergRequestContext, viewIdentifier, e);
this.renameViewRequest = renameViewRequest;
}

public RenameTableRequest renameViewRequest() {
public Object renameViewRequest() {
return renameViewRequest;
}
Copy link

Copilot AI Mar 26, 2026

Choose a reason for hiding this comment

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

This failure event still stores and returns the raw request as Object, which is inconsistent with the PR’s stated goal of decoupling listener events from Iceberg REST models and making payloads serializable. Consider converting the request to a Map<String, Object> via IcebergRESTUtils.toSerializableMap(...) (matching the other post/failure events).

Copilot uses AI. Check for mistakes.
Comment on lines +28 to 41
private final Object renameTableRequest;

public IcebergRenameTableFailureEvent(
IcebergRequestContext icebergRequestContext,
NameIdentifier resourceIdentifier,
RenameTableRequest renameTableRequest,
Object renameTableRequest,
Exception e) {
super(icebergRequestContext, resourceIdentifier, e);
this.renameTableRequest = renameTableRequest;
}

public RenameTableRequest renameTableRequest() {
public Object renameTableRequest() {
return renameTableRequest;
}
Copy link

Copilot AI Mar 26, 2026

Choose a reason for hiding this comment

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

This failure event still stores and returns the raw request as Object, which leaves listener payloads coupled to Iceberg REST request classes at runtime and may break serializability assumptions. Consider converting/storing it as Map<String, Object> via IcebergRESTUtils.toSerializableMap(...) for consistency with the other updated events.

Copilot uses AI. Check for mistakes.
Comment on lines +118 to +123
public static Map<String, Object> toSerializableMap(Object message) {
ObjectMapper icebergObjectMapper = IcebergObjectMapper.getInstance();
try {
byte[] values = icebergObjectMapper.writeValueAsBytes(message);
return icebergObjectMapper.readValue(values, Map.class);
} catch (IOException e) {
Copy link

Copilot AI Mar 26, 2026

Choose a reason for hiding this comment

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

toSerializableMap deserializes with Map.class and returns it as Map<String, Object>, which relies on an unchecked conversion and loses type information. Consider using a TypeReference<Map<String, Object>> (or JavaType) to keep the method type-safe and avoid warnings/possible key-type surprises.

Copilot uses AI. Check for mistakes.
Comment on lines +118 to +122
public static Map<String, Object> toSerializableMap(Object message) {
ObjectMapper icebergObjectMapper = IcebergObjectMapper.getInstance();
try {
byte[] values = icebergObjectMapper.writeValueAsBytes(message);
return icebergObjectMapper.readValue(values, Map.class);
Copy link

Copilot AI Mar 26, 2026

Choose a reason for hiding this comment

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

toSerializableMap is new behavior that changes listener payload shapes, but there’s no test coverage asserting that it actually produces a deep-cloned, serializable map (and not Iceberg model instances) for representative requests/responses. Consider adding a focused unit test (e.g., alongside the existing TestIcebergRESTUtils#testSerdeIcebergRESTObject) that validates the returned map structure and that mutations to the original object don’t affect the stored payload.

Copilot generated this review using guidance from repository custom instructions.
Create iceberg-listener-api module, move Iceberg listener events there, and remove direct Iceberg dependencies from the new module by using generic payload/event types with dispatcher-side serialization.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions
Copy link
Copy Markdown

Code Coverage Report

Overall Project 64.93% +0.14% 🟢
Files changed 91.79% 🟢

Module Coverage
aliyun 1.73% 🔴
api 47.14% 🟢
authorization-common 85.96% 🟢
aws 1.1% 🔴
azure 2.6% 🔴
catalog-common 10.0% 🔴
catalog-fileset 80.02% 🟢
catalog-hive 80.98% 🟢
catalog-jdbc-clickhouse 79.06% 🟢
catalog-jdbc-common 42.89% 🟢
catalog-jdbc-doris 80.28% 🟢
catalog-jdbc-hologres 54.03% 🟢
catalog-jdbc-mysql 79.23% 🟢
catalog-jdbc-oceanbase 78.38% 🟢
catalog-jdbc-postgresql 82.05% 🟢
catalog-jdbc-starrocks 78.27% 🟢
catalog-kafka 77.01% 🟢
catalog-lakehouse-generic 45.07% 🟢
catalog-lakehouse-hudi 79.1% 🟢
catalog-lakehouse-iceberg 87.15% 🟢
catalog-lakehouse-paimon 77.71% 🟢
catalog-model 77.72% 🟢
cli 44.51% 🟢
client-java 77.83% 🟢
common 49.42% 🟢
core 81.0% 🟢
filesystem-hadoop3 76.97% 🟢
flink 38.86% 🔴
flink-runtime 0.0% 🔴
gcp 14.2% 🔴
hadoop-common 10.39% 🔴
hive-metastore-common 45.82% 🟢
iceberg-common 50.21% 🟢
iceberg-rest-server 66.71% +4.67% 🟢
integration-test-common 0.0% 🔴
jobs 66.17% 🟢
lance-common 23.88% 🔴
lance-rest-server 57.84% 🟢
lineage 53.02% 🟢
optimizer 82.87% 🟢
optimizer-api 21.95% 🔴
server 85.62% 🟢
server-common 70.14% 🟢
spark 32.79% 🔴
spark-common 39.09% 🔴
trino-connector 31.62% 🔴
Files
Module File Coverage
iceberg-rest-server IcebergViewEventDispatcher.java 97.09% 🟢
IcebergNamespaceEventDispatcher.java 97.03% 🟢
IcebergTableEventDispatcher.java 95.31% 🟢
IcebergRESTUtils.java 65.52% 🟢

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.

[Improvement] Free Iceberg related listener from Iceberg dependencies

2 participants