Prior to this commit, spring.jms.listener.acknowledge-mode and spring.jms.template.acknowledge-mode accepted only a predefined set of values representing standard JMS acknowledge modes.

This commit adds support for also using arbitrary integer values to these configuration properties, which allow configuring vendor-specific JMS acknowledge modes.

Closes https://github.com/spring-projects/spring-boot/issues/37447


Note that this PR depends on https://github.com/spring-projects/spring-boot/pull/37500 (which adds support for spring.jms.template.acknowledge-mode).

This PR also wraps up efforts started in https://github.com/spring-projects/spring-boot/pull/37473 that aim to improve developer experience when working with JMS vendors such as SQS, which provides non-standard acknowledge modes and doesn't support transactions

Comment From: wilkinsona

Thanks for the PR, @vpavic. I've rebased this on the latest change in main and tried adding a test:

@Test
void testJmsListenerContainerFactoryWithNonStandardAcknowledgeMode() {
    this.contextRunner.withUserConfiguration(EnableJmsConfiguration.class)
        .withPropertyValues("spring.jms.listener.session.acknowledge-mode=9")
        .run((context) -> {
            DefaultMessageListenerContainer container = getContainer(context, "jmsListenerContainerFactory");
            assertThat(container.getSessionAcknowledgeMode()).isEqualTo(9);
        });
}

It fails:

java.lang.IllegalArgumentException: Only values of acknowledge mode constants allowed
    at org.springframework.util.Assert.isTrue(Assert.java:111)
    at org.springframework.jms.support.JmsAccessor.setSessionAcknowledgeMode(JmsAccessor.java:170)
    at org.springframework.jms.config.AbstractJmsListenerContainerFactory.createListenerContainer(AbstractJmsListenerContainerFactory.java:235)
    at org.springframework.boot.autoconfigure.jms.JmsAutoConfigurationTests.getContainer(JmsAutoConfigurationTests.java:271)
    at org.springframework.boot.autoconfigure.jms.JmsAutoConfigurationTests.lambda$9(JmsAutoConfigurationTests.java:168)
    at org.springframework.boot.test.context.runner.AbstractApplicationContextRunner.accept(AbstractApplicationContextRunner.java:434)
    at org.springframework.boot.test.context.runner.AbstractApplicationContextRunner.consumeAssertableContext(AbstractApplicationContextRunner.java:363)
    at org.springframework.boot.test.context.runner.AbstractApplicationContextRunner.lambda$1(AbstractApplicationContextRunner.java:341)
    at org.springframework.boot.test.util.TestPropertyValues.lambda$5(TestPropertyValues.java:174)
    at org.springframework.boot.test.util.TestPropertyValues.applyToSystemProperties(TestPropertyValues.java:188)
    at org.springframework.boot.test.util.TestPropertyValues.applyToSystemProperties(TestPropertyValues.java:173)
    at org.springframework.boot.test.context.runner.AbstractApplicationContextRunner.lambda$0(AbstractApplicationContextRunner.java:341)
    at org.springframework.boot.test.context.runner.AbstractApplicationContextRunner.withContextClassLoader(AbstractApplicationContextRunner.java:369)
    at org.springframework.boot.test.context.runner.AbstractApplicationContextRunner.run(AbstractApplicationContextRunner.java:340)
    at org.springframework.boot.autoconfigure.jms.JmsAutoConfigurationTests.testJmsListenerContainerFactoryWithNonStandardAcknowledgeMode(JmsAutoConfigurationTests.java:167)
    at java.base/java.lang.reflect.Method.invoke(Method.java:568)
    at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
    at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)

Apologies if I have introduced the problem while rebasing but I don't think I have. It looks to me like further Framework changes are required to support this.

Comment From: vpavic

After taking a quick look, it appears that this is caused by a regression in Spring Framework introduced in https://github.com/spring-projects/spring-framework/commit/3b8dd0a5acd9a6757d4849ccf2d5baf6c654ea57. Prior to that commit, JmsAccessor#setSessionAcknowledgeMode wasn't constrained to only standard acknowledge modes - I have several Spring Boot 3.1 based projects that are using SQSSession.UNORDERED_ACKNOWLEDGE.

I'll open an issue against Framework shortly.

Comment From: vpavic

Instead of an issue, I've opened https://github.com/spring-projects/spring-framework/pull/31328 to address the regression on the Framework side.

Comment From: vpavic

With https://github.com/spring-projects/spring-framework/pull/31328 merged, I assume this is now unblocked?

Comment From: wilkinsona

Not quite. We'll move to snapshots next week so it's blocked until then.

Comment From: vpavic

Is this expected to target 3.2? I'm asking because there's no assigned milestone.

Comment From: wilkinsona

Hopefully, yes, but we'll have to see what time permits. I'll assign it to 3.x for now and we can hopefully pull it forwards.

Comment From: wilkinsona

I've pushed my polishing: https://github.com/wilkinsona/spring-boot/tree/gh-37576.

However, I think we may need to take a different approach for a couple of reasons:

  1. By moving away from an enum, we've lost the capabilities of LenientStringToEnumConverterFactory. This means that values like dupsok will no longer work.
  2. By doing the mapping when the property is used rather than when it's bound, the diagnostics won't be so good when the configuration is invalid

I'd like to discuss this with the rest of the team.