Skip to content

Conversation

yybmion
Copy link

@yybmion yybmion commented Oct 18, 2025

Fixes : #9312

Enable human-readable JSON storage in JdbcChannelMessageStore as an alternative to binary Java serialization.

  • Add JacksonChannelMessageStorePreparedStatementSetter for serialization
  • Add JacksonMessageRowMapper for deserialization
  • Make MessageRowMapper extensible via a new protected constructor
  • 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
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?

Enable human-readable JSON storage in JdbcChannelMessageStore as an
alternative to binary Java serialization.

- Add JacksonChannelMessageStorePreparedStatementSetter for serialization
- Add JacksonMessageRowMapper for deserialization
- Add protected constructor to MessageRowMapper for extensibility
- Add JSON schemas for PostgreSQL (JSONB), MySQL (JSON), and H2 (CLOB)
- Add comprehensive test coverage with database-specific tests
- Add documentation for JSON serialization support

Fixes: spring-projectsgh-9312

Signed-off-by: yybmion <yunyubin54@gmail.com>
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.

jmsApiVersion = '3.1.0'
jpaApiVersion = '3.2.0'
jrubyVersion = '10.0.2.0'
jsonassertVersion = '1.5.1'
Copy link
Member

Choose a reason for hiding this comment

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

Any real justification to manage an extra dependency?

* </ul>
* <p>
* <b>Note:</b> Subpackages are automatically included without wildcards.
*
Copy link
Member

Choose a reason for hiding this comment

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

No blank lines in method Javadocs, please.

*
* @param trustedPackages the additional packages to trust for deserialization
*/
public JacksonChannelMessageStorePreparedStatementSetter(String... trustedPackages) {
Copy link
Member

Choose a reason for hiding this comment

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

The security is not consulted on the serialization, therefore this option is redundant here.

* schemas from {@code schema-*-json.sql} files.
*
* @author Yoobin Yoon
* @since 7.0
Copy link
Member

Choose a reason for hiding this comment

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

Blank line after @author list.
Just to emphasize who exactly did the change.

*
* @param trustedPackages the additional packages to trust for deserialization
*/
public JacksonChannelMessageStorePreparedStatementSetter(String... trustedPackages) {
Copy link
Member

Choose a reason for hiding this comment

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

This is something what is not used on serialization. Therefore this option is redundant.

@ContextConfiguration
public class PostgresJacksonChannelMessageStoreTests extends AbstractJacksonChannelMessageStoreTests {

private static final PostgreSQLContainer<?> POSTGRES_CONTAINER =
Copy link
Member

Choose a reason for hiding this comment

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

Why doesn't PostgresContainerTest API work for this test scope?
Therefore, might be the case that this class has to go that postgres package in our tests.

*
* @author Yoobin Yoon
*/
public class TestMailMessage implements Serializable {
Copy link
Member

Choose a reason for hiding this comment

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

If we talk about JSON, then Serializable is something redundant.
I also wonder why this class is not a Java record.

See xref:jdbc/lock-registry.adoc[] for more information.

The `JdbcChannelMessageStore` now supports built-in Jackson JSON serialization as an alternative to Java serialization, enabling human-readable message storage.
New components `JacksonChannelMessageStorePreparedStatementSetter` and `JacksonMessageRowMapper` provide this functionality with JSON-specific database schemas for PostgreSQL, MySQL, and H2.
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 it has any specific value to mention those DBs.
I believe that any CLOB-supporting DB is OK to have a JSON as its value.
So, your statement about JSON-specific database schemas does not reflect reality somehow...
Maybe you meant those custom schema files?
Then, OK: since we talk about dropping them in favor of docs, then this sentence would be changed as well.

= JDBC Channel Message Store JSON Serialization

Version 7.0 introduced Jackson JSON serialization support for `JdbcChannelMessageStore`.
By default, Spring Integration uses Java serialization to store messages in the database as binary BLOB data, which is not human-readable.
Copy link
Member

Choose a reason for hiding this comment

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

The "human-readable" statement makes me think twice.
Is it really a goal to let DBA to read the content of messages?
In most cases the payload and headers contain sensitive business data.
So, expose such an info DB directly might not be very secure.
May we at least don't emphasize somehow that it is better than byte[]?
From my point of view it is even dangerous.
I know that we can encode data in DBs, but let's at least don't mention that it is human-readable!


Version 7.0 introduced Jackson JSON serialization support for `JdbcChannelMessageStore`.
By default, Spring Integration uses Java serialization to store messages in the database as binary BLOB data, which is not human-readable.
The new JSON serialization support allows messages to be stored as readable JSON, making debugging and troubleshooting significantly easier.
Copy link
Member

Choose a reason for hiding this comment

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

Yes, and this sentence also drops any data protection rules away.

@yybmion
Copy link
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
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.

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