Skip to content

Conversation

@tanjialiang
Copy link
Contributor

@tanjialiang tanjialiang commented Oct 29, 2025

Description

Allow JSON serialization to TableWriteNode.WriterTarget.

== NO RELEASE NOTE ==

@prestodb-ci prestodb-ci added the from:Meta PR from Meta label Oct 29, 2025
@sourcery-ai
Copy link
Contributor

sourcery-ai bot commented Oct 29, 2025

Reviewer's Guide

Enable JSON serialization support for TableWriterNode.WriterTarget and its subclasses by adding Jackson annotations, adjust planner classes for serialization, update test dependencies, and add comprehensive serialization tests.

Class diagram for updated TableWriterNode.WriterTarget JSON serialization

classDiagram
    TableWriterNode <|-- WriterTarget
    WriterTarget <|-- CreateName
    WriterTarget <|-- InsertReference
    WriterTarget <|-- DeleteHandle
    WriterTarget <|-- RefreshMaterializedViewReference
    WriterTarget <|-- UpdateTarget
    WriterTarget <|-- CanonicalWriterTarget

    class WriterTarget {
        <<abstract>>
        +ConnectorId getConnectorId()
        +SchemaTableName getSchemaTableName()
        +Optional<List<OutputColumnMetadata>> getOutputColumns()
    }
    class CreateName {
        +ConnectorId connectorId
        +ConnectorTableMetadata tableMetadata
        +Optional<NewTableLayout> layout
        +Optional<List<OutputColumnMetadata>> columns
        +CreateName(connectorId, tableMetadata, layout, columns)
        +getConnectorId()
        +getTableMetadata()
        +getLayout()
        +getSchemaTableName()
        +getOutputColumns()
        +toString()
    }
    class InsertReference {
        +TableHandle handle
        +SchemaTableName schemaTableName
        +Optional<List<OutputColumnMetadata>> columns
        +InsertReference(handle, schemaTableName, columns)
        +getHandle()
        +getSchemaTableName()
        +getConnectorId()
        +getOutputColumns()
    }
    class DeleteHandle {
        +TableHandle handle
        +SchemaTableName schemaTableName
        +DeleteHandle(handle, schemaTableName)
        +getHandle()
        +getSchemaTableName()
        +getConnectorId()
        +getOutputColumns()
    }
    class RefreshMaterializedViewReference {
        +TableHandle handle
        +SchemaTableName schemaTableName
        +RefreshMaterializedViewReference(handle, schemaTableName)
        +getHandle()
        +getSchemaTableName()
        +getConnectorId()
        +getOutputColumns()
    }
    class UpdateTarget {
        +TableHandle handle
        +SchemaTableName schemaTableName
        +List<String> updatedColumns
        +List<ColumnHandle> updatedColumnHandles
        +UpdateTarget(handle, schemaTableName, updatedColumns, updatedColumnHandles)
        +getHandle()
        +getSchemaTableName()
        +getConnectorId()
        +getOutputColumns()
        +getUpdatedColumns()
        +getUpdatedColumnHandles()
    }
    class CanonicalWriterTarget {
        +ConnectorId connectorId
        +String writerTargetType
        +CanonicalWriterTarget(connectorId, writerTargetType)
        +getConnectorId()
        +getSchemaTableName()
        +getOutputColumns()
    }
Loading

Class diagram for CanonicalPlan and CanonicalWriterTarget serialization changes

classDiagram
    CanonicalPlan o-- PlanNode
    CanonicalPlan o-- PlanCanonicalizationStrategy
    CanonicalPlan ..> CanonicalWriterTarget : uses
    class CanonicalPlan {
        -PlanNode plan
        -PlanCanonicalizationStrategy strategy
        +toString(ObjectMapper)
    }
    class CanonicalWriterTarget {
        +ConnectorId connectorId
        +String writerTargetType
        +getConnectorId()
        +getSchemaTableName()
        +getOutputColumns()
    }
Loading

File-Level Changes

Change Details Files
Add Jackson annotations to WriterTarget hierarchy for JSON serialization
  • Annotate WriterTarget with @JsonTypeInfo and @JsonSubTypes
  • Mark getTarget() with @JsonProperty instead of @JsonIgnore
  • Add @JsonCreator constructors to all WriterTarget subclasses
  • Use @JsonProperty on serializable getters and @JsonIgnore on non-serialized methods
presto-spi/src/main/java/com/facebook/presto/spi/plan/TableWriterNode.java
Adjust planner components to support or ignore JSON serialization
  • Make CanonicalWriterTarget public and annotate serialization methods with @JsonIgnore
  • Add a logger and info-level logging in CanonicalPlan.toString on JSON errors
  • Minor formatting update in ColumnMetadata
presto-main-base/src/main/java/com/facebook/presto/sql/planner/CanonicalPlanGenerator.java
presto-main-base/src/main/java/com/facebook/presto/sql/planner/CanonicalPlan.java
presto-spi/src/main/java/com/facebook/presto/spi/ColumnMetadata.java
Add javax.inject test dependency
  • Include javax.inject artifact in test scope
presto-spi/pom.xml
Introduce TestTableWriterNode with comprehensive JSON serialization tests
  • Implement setup with JsonCodecFactory and custom modules
  • Add tests for CreateName, InsertReference, DeleteHandle, RefreshMaterializedViewReference, UpdateTarget
  • Add full serialization test for TableWriterNode including nested PlanNode and Target
  • Define mock connector and column handle classes with @JsonCreator/@JsonProperty
presto-spi/src/test/java/com/facebook/presto/spi/plan/TestTableWriterNode.java

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@tanjialiang tanjialiang force-pushed the tw_json branch 2 times, most recently from 3c0ca5e to 0303808 Compare October 30, 2025 08:01
@tanjialiang tanjialiang marked this pull request as ready for review October 30, 2025 08:05
Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

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

Hey there - I've reviewed your changes - here's some feedback:

  • The catch block in CanonicalPlan.toString logs serialization errors at INFO level, which could be too verbose; consider lowering it to DEBUG or WARN to avoid log noise.
  • The WriterTarget subclasses include a lot of repetitive @JsonCreator, @JsonProperty, and @JsonIgnore annotations; consider using Jackson mixins or a shared configuration to reduce boilerplate.
  • The test-scope 'javax.inject' dependency added to pom.xml doesn’t appear to be used; please remove it or clarify why it is needed.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The catch block in CanonicalPlan.toString logs serialization errors at INFO level, which could be too verbose; consider lowering it to DEBUG or WARN to avoid log noise.
- The WriterTarget subclasses include a lot of repetitive @JsonCreator, @JsonProperty, and @JsonIgnore annotations; consider using Jackson mixins or a shared configuration to reduce boilerplate.
- The test-scope 'javax.inject' dependency added to pom.xml doesn’t appear to be used; please remove it or clarify why it is needed.

## Individual Comments

### Comment 1
<location> `presto-spi/src/main/java/com/facebook/presto/spi/plan/TableWriterNode.java:309-313` </location>
<code_context>
         private final Optional<List<OutputColumnMetadata>> columns;

-        public CreateName(ConnectorId connectorId, ConnectorTableMetadata tableMetadata, Optional<NewTableLayout> layout, Optional<List<OutputColumnMetadata>> columns)
+        @JsonCreator
+        public CreateName(ConnectorId connectorId,
+                ConnectorTableMetadata tableMetadata,
+                Optional<NewTableLayout> layout,
</code_context>

<issue_to_address>
**suggestion:** Inconsistent use of @JsonProperty on CreateName constructor parameters.

Adding @JsonProperty to each constructor parameter will help prevent deserialization errors and maintain consistency with other WriterTarget subclasses.

```suggestion
        @JsonCreator
        public CreateName(
                @JsonProperty("connectorId") ConnectorId connectorId,
                @JsonProperty("tableMetadata") ConnectorTableMetadata tableMetadata,
                @JsonProperty("layout") Optional<NewTableLayout> layout,
                @JsonProperty("columns") Optional<List<OutputColumnMetadata>> columns)
```
</issue_to_address>

### Comment 2
<location> `presto-spi/src/test/java/com/facebook/presto/spi/plan/TestTableWriterNode.java:77-78` </location>
<code_context>
+        writerTargetCodec = codecFactory.jsonCodec(TableWriterNode.WriterTarget.class);
+    }
+
+    @Test
+    public void testCreateNameTargetSerialization()
+    {
+        ConnectorId connectorId = new ConnectorId("test_catalog");
</code_context>

<issue_to_address>
**suggestion (testing):** Missing deserialization round-trip assertion for CreateName target.

Please add an assertion to deserialize the JSON and verify the resulting object equals the original CreateName instance, as done in similar tests.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment on lines 309 to 365
@JsonCreator
public CreateName(ConnectorId connectorId,
ConnectorTableMetadata tableMetadata,
Optional<NewTableLayout> layout,
Optional<List<OutputColumnMetadata>> columns)
Copy link
Contributor

Choose a reason for hiding this comment

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

suggestion: Inconsistent use of @JsonProperty on CreateName constructor parameters.

Adding @JsonProperty to each constructor parameter will help prevent deserialization errors and maintain consistency with other WriterTarget subclasses.

Suggested change
@JsonCreator
public CreateName(ConnectorId connectorId,
ConnectorTableMetadata tableMetadata,
Optional<NewTableLayout> layout,
Optional<List<OutputColumnMetadata>> columns)
@JsonCreator
public CreateName(
@JsonProperty("connectorId") ConnectorId connectorId,
@JsonProperty("tableMetadata") ConnectorTableMetadata tableMetadata,
@JsonProperty("layout") Optional<NewTableLayout> layout,
@JsonProperty("columns") Optional<List<OutputColumnMetadata>> columns)

Comment on lines 77 to 120
@Test
public void testCreateNameTargetSerialization()
Copy link
Contributor

Choose a reason for hiding this comment

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

suggestion (testing): Missing deserialization round-trip assertion for CreateName target.

Please add an assertion to deserialize the JSON and verify the resulting object equals the original CreateName instance, as done in similar tests.

Copy link
Member

@hantangwangd hantangwangd left a comment

Choose a reason for hiding this comment

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

A quick question: is there any scenarios we need to serialize the subclasses of WriteTarget? From what I understand, they seem to be used only during planning and wouldn't need to be sent to workers.

xiaoxmeng
xiaoxmeng previously approved these changes Oct 30, 2025
@tanjialiang
Copy link
Contributor Author

A quick question: is there any scenarios we need to serialize the subclasses of WriteTarget? From what I understand, they seem to be used only during planning and wouldn't need to be sent to workers.

Hi @hantangwangd , we have a use case in presto-on-spark that uses the serialized WriterTarget to extract table information (schema, table name, path) in a context of a different classloader (cross spark driver-executor boundary). We could not rely on cast of the class to get the needed information because of the class loader issue (jvm will not allow the cast because it sees the object class type and the cast class type as two different classes). We have been relying on the same JSON way for table scan but since table writer node does not have the needed information already JSON serializable, we are hence adding them.

@hantangwangd
Copy link
Member

@tanjialiang got it! Thanks for your explanation.

@tanjialiang tanjialiang changed the title Add JSON to WriterTarget feat: Add JSON to WriterTarget Oct 31, 2025
@tanjialiang tanjialiang force-pushed the tw_json branch 3 times, most recently from f62048e to 2351780 Compare November 1, 2025 23:02
Copy link
Contributor

@aditi-pandit aditi-pandit left a comment

Choose a reason for hiding this comment

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

Thanks @tanjialiang for this code.

Please can you give more details about the motivation for this change.

Copy link
Contributor

Choose a reason for hiding this comment

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

Can you remove this diff ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I added the empty line when coming across this file seeing the lacking of the empty line. But if we don't want it in this PR I can remove.

Copy link
Contributor

Choose a reason for hiding this comment

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

@tanjialiang
Copy link
Contributor Author

Thanks @tanjialiang for this code.

Please can you give more details about the motivation for this change.

Hi @aditi-pandit, thanks for your comments. I have explained above. Let me paste here for your easier reference:

we have a use case in presto-on-spark that uses the serialized WriterTarget to extract table information (schema, table name, path) in a context of a different classloader (cross spark driver-executor boundary). We could not rely on cast of the class to get the needed information because of the class loader issue (jvm will not allow the cast because it sees the object class type and the cast class type as two different classes). We have been relying on the same JSON way for table scan but since table writer node does not have the needed information already JSON serializable, we are hence adding them.

Please let me know what more details are needed. Thanks!


public class CanonicalPlan
{
private static final Logger log = Logger.get(CanonicalPlan.class);
Copy link
Contributor

Choose a reason for hiding this comment

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

This logger is not used?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Will remove

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

from:Meta PR from Meta

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants