1

I'd like to create a shared-durable subscriber with spring-boot and IBM MQ. I have done to make a durable subscriber, but fail for the shared subscription.

When I debug the program, I found null pointer exception issue

java.lang.NoSuchMethodError: javax.jms.Session.createSharedDurableConsumer(Ljavax/jms/Topic;Ljava/lang/String;Ljava/lang/String;)Ljavax/jms/MessageConsumer;

inside class AbstractMessageListenerContainer, method createConsumer. It is because it try to invoke session.createSharedDurableConsumerMethod where the session object is of javax.jms.Session and IntelliJ point it to library geronimo-jms_1.1_spec-1.1.1.jar

My pom.xml is using JMS 2.0:

<dependency>
   <groupId>javax.jms</groupId>
   <artifactId>javax.jms-api</artifactId>
   <version>2.0.1</version>
</dependency>

Here is the java code:

import com.ibm.mq.jms.*;

...

public class JmsConfig {

...

@Bean
public MQTopicConnectionFactory mqTopicConnectionFactory(){
    MQTopicConnectionFactory factory = new MQTopicConnectionFactory();
    try{
        factory.setHostName(mqHostname);
        factory.setChannel(mqChannel);
        factory.setPort(Integer.parseInt(mqPort));
        factory.setQueueManager(mqQManager);
        factory.setTransportType(WMQConstants.WMQ_CM_CLIENT);
        factory.setClientReconnectTimeout(0);
    } catch (Exception e) {
        e.printStackTrace();
    }
    return factory;
}

@Bean
@Primary
UserCredentialsConnectionFactoryAdapter userCredentialsConnectionFactoryAdapter(MQTopicConnectionFactory mqTopicConnectionFactory) {
    UserCredentialsConnectionFactoryAdapter userCredentialsConnectionFactoryAdapter = new UserCredentialsConnectionFactoryAdapter();
    userCredentialsConnectionFactoryAdapter.setTargetConnectionFactory(mqTopicConnectionFactory);
    userCredentialsConnectionFactoryAdapter.setUsername(mqUsername);
    if(!mqPassword.equals("")) {
        userCredentialsConnectionFactoryAdapter.setPassword(mqPassword);
    }
    return userCredentialsConnectionFactoryAdapter;
}

@Bean
public CachingConnectionFactory cachingConnectionFactory(UserCredentialsConnectionFactoryAdapter userCredentialsConnectionFactoryAdapter) {
    CachingConnectionFactory cachingConnectionFactory = new CachingConnectionFactory();
    cachingConnectionFactory.setTargetConnectionFactory(userCredentialsConnectionFactoryAdapter);
    cachingConnectionFactory.setSessionCacheSize(1000);
    cachingConnectionFactory.setReconnectOnException(true);
    return cachingConnectionFactory;
}


@Bean
public JmsOperations jmsOperations(CachingConnectionFactory cachingConnectionFactory) {
    JmsTemplate jmsTemplate = new JmsTemplate(cachingConnectionFactory);
    jmsTemplate.setPubSubDomain(true);
    jmsTemplate.setReceiveTimeout(2000);
    return jmsTemplate;
}

@Bean
public JmsListenerContainerFactory<?> topicListenerFactory(ConnectionFactory connectionFactory, DefaultJmsListenerContainerFactoryConfigurer configurer) {

    DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
    configurer.configure(factory, connectionFactory);
    factory.setPubSubDomain(true);//must follow the configurer.configure(), because it will set the factory as default as connectionFactory
    factory.setConcurrency("1");
    factory.setSubscriptionShared(true);
    factory.setSubscriptionDurable(true);
    factory.setSessionAcknowledgeMode(Session.CLIENT_ACKNOWLEDGE);
    factory.setClientId(mqClientID);
    return factory;
}
}

Is any missing config, or need to override the method to manage the Session object so that it can create shared-durable connection?

JoshMc
  • 10,239
  • 2
  • 19
  • 38
Vinci
  • 11
  • 2
  • 1
    You are using JMS 2 features with a JMS 1.1 provider that isn't going to work. Afaik IBM MQ is JMS 1.1 so trying to use JMS 2 features simply won't work. – M. Deinum Jul 31 '18 at 06:41
  • MQ has supported JMS 2.0 since V8 – Mark Taylor Jul 31 '18 at 15:35
  • Yes, I think IBM MQ support JMS2.0 now. However, it is not exception throw when connecting to server, but it error in java runtime. I am curious why the maven loaded jms1.1 lib as dependency even I did not define in pom. – Vinci Jul 31 '18 at 17:13

1 Answers1

0

Finally I figured out why the program uses JMS1.1. It is because another part of the program load the AWS SQS library from pom, and this library is using JMS1.1(geronimo-jms_1.1_spec-1.1.1.jar) for ActiveMQ.

Therefore, I add exclusion in pom for the AWS SQS library to prevent it override the JMS2.0 library.

Vinci
  • 11
  • 2