Skip to content

Conversation

@yybmion
Copy link
Contributor

@yybmion yybmion commented Oct 18, 2025

Fixes : #9312

JSON serialization as an alternative to Java serialization, enabling text-based message storage with type information preservation.

  • Add JacksonChannelMessageStorePreparedStatementSetter for serialization
  • Add JacksonMessageRowMapper for deserialization
  • Include JSON-compatible schemas for PostgreSQL (JSONB), MySQL (JSON), and H2 (CLOB)
  • Add comprehensive test coverage with database-specific tests
  • Add documentation for JSON serialization support

@yybmion
Copy link
Contributor Author

yybmion commented Oct 18, 2025

Hi, I'd like your input on two decisions

1. Column naming: MESSAGE_BYTES or MESSAGE_CONTENT.

I kept MESSAGE_BYTES to avoid creating custom QueryProviders for each database. While semantically it should be MESSAGE_CONTENT (since it's now JSON, not binary), renaming would require:

  • Custom PostgresJsonChannelMessageStoreQueryProvider
  • Custom MySqlJsonChannelMessageStoreQueryProvider
  • Custom H2JsonChannelMessageStoreQueryProvider
  • Maintaining separate query implementations

The current approach works as a drop-in replacement - users just change the schema file. Is this acceptable, or should I implement the custom QueryProviders for better naming?

2. Database coverage: PostgreSQL, MySQL, H2 only

I've implemented and tested these three databases. Should I:

  • Add untested schemas for Oracle/SQL Server/Derby/DB2 based on documentation?
  • Keep only tested databases and add others in follow-up PRs?

I lean toward starting with tested databases only.

What do you think?

Copy link
Member

@artembilan artembilan left a comment

Choose a reason for hiding this comment

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

Please, add your legal name to the sign-off of the commit.
You can change your Git client config on the matter.

@yybmion
Copy link
Contributor Author

yybmion commented Oct 21, 2025

Thanks for the feedback @artembilan! Two questions:

Yes, I agree that it can be renamed to the MESSAGE_CONTENT, but do we really always going to have it as String? Are you anticipating it as a CLOB in standard DBs and some custom type in specific, but that still would not be byte[]?

1. Column Naming

You mentioned MESSAGE_CONTENT is more semantic. Should I rename(schema-(db).sql file) it?

Is it okay with a breaking change for better naming? Or keep MESSAGE_BYTES?

2. Type-Safe Reading

Current getString() works for PostgreSQL/MySQL/H2. Do you mean we should add defensive handling for cases like:

  • java.sql.Clob (Oracle, large data)
  • PGobject (PostgreSQL specifics)
  • byte[] fallback

@artembilan
Copy link
Member

I wonder if that could be kept as MESSAGE_BYTES and suggest any other name instead for JSON handling .
Might be the case that we would need to adjust our queries to avoid hard-coded name.
I believe with modern RDBMS drivers the getString() works well with CLOB.
We do have a Testcontainet for Oracle to check how JSON could be handled over there .

it is unfortunate that you are contributing this too late in the current 7.0 generation.
We do RC1 today which means we don’t have enough time to make your contribution as great. After that it is a code freeze and we won’t be able to rename column until version 8.0.
Either way I think MESSAGE_BYTES still makes sense and for JSON it could be anything else . We just need to double check the code for that naming usage.

Copy link
Member

@artembilan artembilan left a comment

Choose a reason for hiding this comment

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

OK. I think we are on the right track, but still need dedicate more thinking on this.
I will aim this for the next 7.1.
Meanwhile I'll make a small (well, it is going to be big by the amount of code affected 😉 ) breaking change for the today's 7.0.0-RC1 - the last chance where we can do that.
The change would be from MESSAGE_BYTES to MESSAGE_CONTENT.
This will be a good foundation for your work over here.

Thank you!

@artembilan
Copy link
Member

Here you are: #10524!

@yybmion
Copy link
Contributor Author

yybmion commented Oct 22, 2025

@artembilan Thanks for the detailed explanation and for taking on the naming change PR.

I’m updating the PR per your review.

I think we should drop all of these extra schema scripts and just document how to change the target RDBMS to support JSON serialization instead.

I understand your point about simplifying the schemas and documenting JSON serialization setup instead.
However, for testing purposes, I still think having a dedicated table or script for verifying JSON results would be helpful.

What do you think about keeping a lightweight schema just for the tests (under src/test/resources)?

@artembilan
Copy link
Member

What do you think about keeping a lightweight schema just for the tests (under src/test/resources)?

That totally makes sense.
And exactly this one could go to the doc as an example what exactly has to be done in the target RDBMS to support JSON.

@yybmion yybmion force-pushed the gh-9312 branch 2 times, most recently from 38f850d to c1d0b32 Compare October 23, 2025 14:54
@yybmion
Copy link
Contributor Author

yybmion commented Oct 23, 2025

Thanks for feedback @artembilan!

I’ve updated the code based on the review for c1d0b32.

@artembilan
Copy link
Member

I’ve updated the code based on the review

Thank you @yybmion !

But as I said before: we cannot accept a new code into the current 7.0.0 milestone since at this moment it is called "code freeze" .
The we would have one more month of 7.0.1 patch release fixing bugs.
And only after that we are going to switch to 7.1.0 where we can accept new features.

Does that make sense to you?

@yybmion
Copy link
Contributor Author

yybmion commented Oct 23, 2025

Thank you for the explanation @artembilan !

Yes, I completely understand the release schedule.

Please let me know if there are any updates or changes needed before the merge.

Thanks again for your guidance throughout the review process!

@yybmion
Copy link
Contributor Author

yybmion commented Nov 4, 2025

Thanks for feedback @artembilan.

Improved as requested in 1e0dfcb

Copy link
Member

@artembilan artembilan left a comment

Choose a reason for hiding this comment

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

Mostly this is great.
Just couple nit-picks and desired clean up.
Let me know if you can make until this end of the day when we are going to perform release.

Thanks

* and Java classes. Custom payload types will require their package to be
* specified using {@link #JsonMessageRowMapper(String...)}.
*/
public JsonMessageRowMapper() {
Copy link
Member

Choose a reason for hiding this comment

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

I think we don't need this ctor.
And another one could be like String @Nullable ... trustedPackages

* A {@link ChannelMessageStorePreparedStatementSetter} implementation that uses JSON
* serialization for {@link Message} objects instead of Java serialization.
* <p>
* This implementation stores the entire message (including headers and payload) as JSON,
Copy link
Member

Choose a reason for hiding this comment

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

We have to say By default, since there is no guarantee that provided JsonObjectMapper is always for Jackson.

throw new SQLException(
"Failed to deserialize message from JSON at row " + rowNum + ". "
+ "Ensure the JSON was created by JsonChannelMessageStorePreparedStatementSetter "
+ "and contains proper @class type information.",
Copy link
Member

Choose a reason for hiding this comment

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

I don't think this is only a reason of an error.
Plus some other JSON serializers might not provide that @class information and can (de)serialize some other way.


== JSON Structure

Messages are stored with the following JSON structure:
Copy link
Member

Choose a reason for hiding this comment

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

I think we need to emphasize here that this is a result of Jackson polymorphic serialization.


The `MESSAGE_CONTENT` column must be changed to a text-based type that can store JSON.

=== PostgreSQL
Copy link
Member

Choose a reason for hiding this comment

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

Can we consider to make these 3 samples as tabs?
As well as the following for the whole table schema.

@yybmion
Copy link
Contributor Author

yybmion commented Nov 4, 2025

Sure @artembilan, I’ll address the nits today before release.

- Add JacksonChannelMessageStorePreparedStatementSetter for serialization
- Add JacksonMessageRowMapper for deserialization with trusted package validation
- Support PostgreSQL (JSONB), MySQL (JSON), and H2 (CLOB) databases
- Add comprehensive test coverage and documentation

Fixes: spring-projectsgh-9312

Signed-off-by: Yoobin Yoon <[email protected]>
@yybmion
Copy link
Contributor Author

yybmion commented Nov 4, 2025

Thanks @artembilan , Improved as requested in a432da5

*
* @author Yoobin Yoon
*/
public record TestMailMessage(
Copy link
Member

Choose a reason for hiding this comment

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

@since 7.0 and not public.
I don't want test data classes to leak from one package to another.

Copy link
Member

@artembilan artembilan left a comment

Choose a reason for hiding this comment

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

OK. I'm taking this locally for final review, clean up and merge.

Thank you again!

@yybmion
Copy link
Contributor Author

yybmion commented Nov 4, 2025

OK. I'm taking this locally for final review, clean up and merge.

Thanks @artembilan!
Please let me know if there’s anything else I can help with.

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.

JSON serialization for JDBC channel message store

2 participants