Skip to content

Use latest Spring Framework 7.1.0-SNAPSHOT - #11351

Open
cppwfs wants to merge 5 commits into
spring-projects:mainfrom
cppwfs:GH-7-2-SNAPSHOT
Open

Use latest Spring Framework 7.1.0-SNAPSHOT#11351
cppwfs wants to merge 5 commits into
spring-projects:mainfrom
cppwfs:GH-7-2-SNAPSHOT

Conversation

@cppwfs

@cppwfs cppwfs commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

The latest snapshots have introduced some breaking changes.
Resolve the issues below

  • Treat a null result from MessageConverter.fromMessage() as a
    conversion failure across all inbound JMS paths.
  • Throw MessageConversionException from AbstractJmsChannel,
    JmsDestinationPollingSource, ChannelPublishingJmsMessageListener,
    and JmsOutboundGateway instead of silently discarding the message.
  • Remove the discard branch in SubscribableJmsChannel since a null
    conversion is no longer possible without an exception.
  • Add tests asserting MessageConversionException for each of the
    four affected components.
  • Updated core to use builder for SpelParserConfiguration as the
    constructor is now deprecated.

@cppwfs cppwfs added this to the 7.2.0-M2 milestone Aug 20, 2026
@cppwfs
cppwfs requested a review from artembilan August 20, 2026 19:16

@artembilan artembilan left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Please, repurpose this PR just for SF 7.2.0-SNAPSHOT.
Looks like this is going to take a while until it is in a good shape.
The rest of dependencies should not suffer.

Thanks

@cppwfs

cppwfs commented Aug 24, 2026

Copy link
Copy Markdown
Contributor Author

This change includes those that were in PR #11367. So if this one still needs alot of work then merge 11367 and I'll continue work on this PR.

@cppwfs
cppwfs force-pushed the GH-7-2-SNAPSHOT branch 2 times, most recently from db5bc01 to 0ecf55c Compare August 24, 2026 16:50
@cppwfs cppwfs changed the title Update release train dependencies to the current snapshots. Set Spring Dependencies back to snapshot Aug 24, 2026

@artembilan artembilan left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think this is something what deserves some docs, too.
Including whats-new.

Thanks

/**
* @author Glenn Renfro
*/
public class JmsDestinationPollingSourceTests implements TestApplicationContextAware {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think we agreed that public is redundant in tests.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Not fixed.
I see changes in the test methods, but class declaration could also benefit from not having public modifier 😄

@artembilan

Copy link
Copy Markdown
Member

I mean.
Document JMS part as it is some kind of breaking change.

@artembilan artembilan added the for: upgrade-attention Breaking change, some extra configuration etc. label Aug 24, 2026
@artembilan

Copy link
Copy Markdown
Member

Also, please, add a comment into this PR with a Attention required: hint explaining how JMS module now fails for null conversion results.
Thanks

@cppwfs
cppwfs force-pushed the GH-7-2-SNAPSHOT branch 2 times, most recently from afaa17b to 83fc3ad Compare August 25, 2026 13:03
@artembilan artembilan changed the title Set Spring Dependencies back to snapshot Use latest Spring Framework 7.1.0-SNAPSHOT Aug 25, 2026
}

/**
* Converts {@link jakarta.jms.Message} to a Spring {@link Message}.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Method Javadocs must be imperative, like commands.

}

/**
* Processes an incoming JMS message, transforms it into a Spring Integration message,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think this Javadoc was generated by AI.
Please, revise it as it is too much info.
And it is not imperative.

* @param jmsMessage the incoming {@link jakarta.jms.Message} to process
* @param session the active JMS {@link jakarta.jms.Session} associated with the listener
* @throws JMSException if a native JMS error occurs while processing, resolving destinations, or sending replies
* @throws MessageConversionException if payload extraction produces a {@code null} result when required

Copy link
Copy Markdown
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 case.
The message converter may thrown such an exception for other reason.
We probably should rephrase it somehow saying that in case of null such an exception is thrown, too.
Or what is better wording would it be from English perspective 😄

@@ -408,6 +423,9 @@ public void onMessage(jakarta.jms.Message jmsMessage, Session session) throws JM
result = this.messageConverter.fromMessage(jmsMessage);
this.logger.debug(() -> "converted JMS Message [" + jmsMessage + "] to integration Message payload ["

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

And no this debug message is suspicious with null result.
I think we need to revise logic as if..else.

* Will receive a JMS {@link jakarta.jms.Message} converting and returning it as
* a Spring Integration {@link Message}. This method will also use the current
* {@link JmsHeaderMapper} instance to map JMS properties to the MessageHeaders.
* @throws MessageConversionException if the converter returns {@code null}.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

DITTO

source.setBeanFactory(TEST_INTEGRATION_CONTEXT);
source.afterPropertiesSet();

// A JMS message converted to a null payload is a conversion failure, not a message to discard.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

DITTO

}

@Test
void payloadFromConverterIsUsed() throws Exception {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I don't see value in this test.
Or better to say: we do have such a coverage in other tests in the module.

when(session.createProducer(any())).thenReturn(mock());
MessageConsumer consumer = mock();
when(session.createConsumer(any())).thenReturn(consumer);
when(consumer.receive(anyLong())).thenReturn(mock());

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

See MockSettings instead of all of these, e.g. Answers.RETURNS_MOCKS.
More over I think this is too much just for an exception in the end.
See if StubConnection and friends can help anyhow instead of this mock nightmare.

Comment thread src/reference/antora/modules/ROOT/pages/whats-new.adoc
[[x7.2-jms-changes]]
=== JMS Support Changes
Spring Integration supports Spring Framework's ability to return `null` when converting a JMS `Message` where the payload has not been set.
This also means that if a Spring `Message` uses the payload of a JMS `Message` that is null, a `MessageConversionException` will be thrown.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think this text needs to be revised.
It is also missing a link to the target chapter.
And I don't see a change in the target chapter.

@artembilan artembilan left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Very close.
Thank you!

factoryBean.setBeanFactory(mock());
MessageConverter messageConverter = spy(new SimpleMessageConverter());
given(messageConverter.fromMessage(any())).willReturn(null);
factoryBean.setMessageConverter(messageConverter);

Copy link
Copy Markdown
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 I asked for a spy when said that same factoryBean.setMessageConverter(mock()); trick could be used here.
Why do we do it different in this class than in the next one?
Why do we need to stub willReturn(null) if mock() returns null by default?
And why is the spy() if we don't verify anything in the end.
And I agree that we must not.
Please, elaborate on this code which is not what we've agreed upon in the next class.

Message jmsMessage = new StubTextMessage("test");

MessageConverter converter = mock();
given(converter.fromMessage(any())).willReturn(null);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Again: why explicit .willReturn(null) if it is assumed by default via mock()?

given(jmsTemplate.receiveSelected(nullable(String.class))).willReturn(jmsMessage);

JmsDestinationPollingSource source = new JmsDestinationPollingSource(jmsTemplate);
source.setBeanFactory(TEST_INTEGRATION_CONTEXT);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'm not sure if we need real ApplicationContext in this test class at all since everything else are just mocks.
Cannot just mock() work here, too?

The `HeaderMappingMessageConverter` itself delegates to a target `MessageConverter` while also mapping the Spring Integration `MessageHeaders` to JMS message properties and back again.

IMPORTANT: If `MessageConverter.fromMessage()` returns `null` (for example, because the JMS `Message` has no payload), Spring Integration treats this as a conversion failure and throws a `MessageConversionException`, rather than silently discarding the message.
This applies to the inbound and outbound channel adapters, the inbound and outbound gateways, and JMS-backed message channels (see xref:jms.adoc#jms-channel[JMS-backed Message Channels]).

Copy link
Copy Markdown
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 is true for the outbound channel adapters.

I also think that we don't need full link to that jms-channel section exactly in this jms.adoc file.

Please, revise.

cppwfs added 5 commits August 26, 2026 12:03
  - The latest snapshots have introduced some breaking changes.
    Resolve the issues below
  - Treat a null result from `MessageConverter.fromMessage()` as a
  conversion failure across all inbound JMS paths.
  - Throw `MessageConversionException` from `AbstractJmsChannel`,
  `JmsDestinationPollingSource`, `ChannelPublishingJmsMessageListener`,
  and `JmsOutboundGateway` instead of silently discarding the message.
  - Remove the discard branch in `SubscribableJmsChannel` since a null
  conversion is no longer possible without an exception.
  - Add tests asserting `MessageConversionException` for each of the
  four affected components.
  - Updated core to use builder for `SpelParserConfiguration` as the
   constructor is now deprecated.
- Update docs to reflect SI's response to framewworks changes to
   Jms message conversion
- Add author tags
Fixed jms doc to remove outbound channel adapters
as being impacted by nulls being returned from converters
@@ -780,6 +798,9 @@ private AbstractIntegrationMessageBuilder<?> buildReply(jakarta.jms.Message jmsR
result = this.messageConverter.fromMessage(jmsReply);
logger.debug(() ->
"converted JMS Message [" + jmsReply + "] to integration Message payload [" + result + "]");

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Why this debug message was not fixed to if..else like in other place we have agreed?


PollableJmsChannel channel = new PollableJmsChannel(jmsTemplate);
channel.setBeanFactory(mock());
channel.afterPropertiesSet();

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

According to channel.receive() code flow for our null payload, we don't need these two lines.

factoryBean.setBeanFactory(mock());
factoryBean.afterPropertiesSet();
SubscribableJmsChannel channel = (SubscribableJmsChannel) factoryBean.getObject();
channel.afterPropertiesSet();

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This is suspicious since it has been just called for its FB.
Please, revise the setting of this test (and probably all new introduced here) to get rid of those options which are out of use and don't contribute to the test outcome.


JmsDestinationPollingSource source = new JmsDestinationPollingSource(jmsTemplate);
source.setBeanFactory(beanFactory);
source.afterPropertiesSet();

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Same here.
If we remove these two lines, we won't need to worry about SpEL at all.

Connection connection = new StubConnection("reply");
when(connectionFactory.createConnection()).thenReturn(connection);

gateway.afterPropertiesSet();

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

DITTO

Starting with version 7.1, the `AbstractJmsChannel` and its implementations use a `DefaultJmsHeaderMapper` internally to map all headers from the message-to-send to JMS message properties; and on consuming side, map all JMS message properties into message headers.
The custom header-mapping and payload conversion logic can be done by the `org.springframework.jms.support.converter.MessagingMessageConverter` injection into the `JmsTemplate` used for `AbstractJmsChannel` instances.

Starting with version 7.2, if the `MessageConverter` returns `null` when converting an incoming JMS `Message`, `AbstractJmsChannel` (and, therefore, `SubscribableJmsChannel` and `PollableJmsChannel`) treats it as a conversion failure and throws a `MessageConversionException` rather than discarding the message.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Why cannot we say here something like instead "the AbstractJmsChannel implementations..."?
What if we are going to have more than those you've just iterated?

The `HeaderMappingMessageConverter` itself delegates to a target `MessageConverter` while also mapping the Spring Integration `MessageHeaders` to JMS message properties and back again.

IMPORTANT: If `MessageConverter.fromMessage()` returns `null` (for example, because the JMS `Message` has no payload), Spring Integration treats this as a conversion failure and throws a `MessageConversionException`, rather than silently discarding the message.
This applies to the inbound channel adapters, the inbound and outbound gateways, and JMS-backed message channels.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

And why did you remove the link?
I asked just for a reference in the same chapter, similar to the one in the end of grpc.adoc:

See <<grpc-outbound-method-name-configuration>>.

@artembilan

Copy link
Copy Markdown
Member

Attention required:

Jms MessageConverters now return null when converting an incoming JMS Message with no payload.
The AbstractJmsChannel treats it as a conversion failure and throws a MessageConversionException rather than discarding the message.

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

Labels

for: upgrade-attention Breaking change, some extra configuration etc. in: jms type: task

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants