Search code examples
javaspring-bootjmsibm-mqspring-jms

Exception Caused by: java.lang.ClassNotFoundException: jakarta.jms.ConnectionFactory


I want to use a Spring Boot Apache Camel application to get a message on IBM MQ. I am currently setting up the JMS connection, but I receive an error about a class not found. I thought it had something to do with dependencies so I tried a lot of different things, but the error stays the same.

import com.ibm.mq.MQEnvironment;
import com.ibm.msg.client.wmq.common.CommonConstants;
//import org.apache.camel.component.jms.JmsComponent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import com.ibm.mq.jms.MQQueueConnectionFactory;
import org.springframework.jms.annotation.EnableJms;
import com.ibm.msg.client.wmq.WMQConstants;

import javax.net.ssl.*;
import java.security.KeyStore;


@EnableJms
@Configuration
public class JmsConfiguration {

    private static final Logger LOG = LoggerFactory.getLogger(JmsComponent.class);
    private String host = "xxx";
    private int port = 4510;
    private String queueManager = "xxx";
    private String channel = "xxx";
    //private String username = "";
    //private String password = "";
    private String sslCipherSuite = "TLS_RSA_WITH_AES_256_CBC_SHA256";

    @Value("${keyStore}")
    private String keyStore;

    @Value("${keyStorePassword}")
    private String keyStorePassword;

    @Value("${trustStore}")
    private String trustStore;

    @Value("${trustStorepassword}")
    private String trustStorePassword;


    @Bean
    public JmsComponent mq() {
        JmsComponent jmsComponent = new JmsComponent();
        jmsComponent.setConnectionFactory(mqQueueConnectionFactory());
        return jmsComponent;
    }

    @Bean
    public MQQueueConnectionFactory mqQueueConnectionFactory() {
        MQQueueConnectionFactory mqQueueConnectionFactory = new MQQueueConnectionFactory();
        mqQueueConnectionFactory.setHostName(host);
        try {
            //Load trust store
            //System.setProperty("javax.net.ssl.trustStore", trustStore);
            //System.setProperty("javax.net.ssl.trustStorePassword", trustStorePassword);
            //Load keystore
            //System.setProperty("javax.net.ssl.keyStore", keyStore);
            //System.setProperty("javax.net.ssl.keyStorePassword", keyStorePassword);

            //keystore fetch
            String keystoreKey = "${keyStorePassword}";
            KeyStore keyStore = KeyStore.getInstance("JKS");
            keyStore.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("${keyStore}"),
                    keystoreKey.toCharArray());

            // Create key manager
            KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("SunX509");
            keyManagerFactory.init(keyStore, keystoreKey.toCharArray());
            KeyManager[] km = keyManagerFactory.getKeyManagers();

            // Create trust manager
            TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance("SunX509");
            trustManagerFactory.init(keyStore);
            TrustManager[] tm = trustManagerFactory.getTrustManagers();

            // Initialize SSLContext
            SSLContext sslContext = SSLContext.getInstance("TLSv1");
            sslContext.init(km, tm, null);
            SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();

            mqQueueConnectionFactory.setPort(port);
            mqQueueConnectionFactory.setChannel(channel);
            mqQueueConnectionFactory.setTransportType(WMQConstants.WMQ_CM_CLIENT);
            mqQueueConnectionFactory.setObjectProperty(WMQConstants.WMQ_SSL_SOCKET_FACTORY, sslSocketFactory);
            mqQueueConnectionFactory.setSSLCipherSuite(sslCipherSuite);
            mqQueueConnectionFactory.setIntProperty(CommonConstants.WMQ_CONNECTION_MODE, CommonConstants.WMQ_CM_CLIENT);
            mqQueueConnectionFactory.setTransportType(CommonConstants.WMQ_CM_BINDINGS);

            MQEnvironment.sslSocketFactory = sslSocketFactory;

        } catch (Exception e) {
            e.printStackTrace();
        }
        return  mqQueueConnectionFactory;
    }
}
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.0.8</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>nl.test</groupId>
    <artifactId>Testapp</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>Testapp</name>
    <description>Testapp</description>
    <properties>
        <java.version>17</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.apache.camel.springboot</groupId>
            <artifactId>camel-spring-boot-starter</artifactId>
            <version>4.0.0-M3</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jms</artifactId>
            <version>4.3.3.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.apache.camel.springboot</groupId>
            <artifactId>camel-jms-starter</artifactId>
            <version>4.0.0-M3</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>com.ibm.mq</groupId>
            <artifactId>com.ibm.mq.allclient</artifactId>
            <version>9.1.0.5</version>
        </dependency>
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-api</artifactId>
            <version>2.20.0</version>
        </dependency>
        <dependency>
            <groupId>jakarta.jms</groupId>
            <artifactId>jakarta.jms-api</artifactId>
            <version>3.0.0</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

This is the stacktrace:

java.lang.NoClassDefFoundError: jakarta/jms/ConnectionFactory
    at java.base/java.lang.Class.getDeclaredFields0(Native Method) ~[na:na]
    at java.base/java.lang.Class.privateGetDeclaredFields(Class.java:3353) ~[na:na]
    at java.base/java.lang.Class.getDeclaredField(Class.java:2661) ~[na:na]
    at org.springframework.boot.context.properties.bind.DefaultBindConstructorProvider$Constructors.isInnerClass(DefaultBindConstructorProvider.java:145) ~[spring-boot-3.0.8.jar:3.0.8] 
    at org.springframework.boot.context.properties.bind.DefaultBindConstructorProvider$Constructors.getCandidateConstructors(DefaultBindConstructorProvider.java:135) ~[spring-boot-3.0.8.jar:3.0.8] 
    at org.springframework.boot.context.properties.bind.DefaultBindConstructorProvider$Constructors.getConstructors(DefaultBindConstructorProvider.java:103) ~[spring-boot-3.0.8.jar:3.0.8] 
    at org.springframework.boot.context.properties.bind.DefaultBindConstructorProvider.getBindConstructor(DefaultBindConstructorProvider.java:55) ~[spring-boot-3.0.8.jar:3.0.8] 
    at org.springframework.boot.context.properties.ConfigurationPropertiesBean.deduceBindMethod(ConfigurationPropertiesBean.java:328) ~[spring-boot-3.0.8.jar:3.0.8] 
    at org.springframework.boot.context.properties.ConfigurationPropertiesBeanRegistrar.createBeanDefinition(ConfigurationPropertiesBeanRegistrar.java:93) ~[spring-boot-3.0.8.jar:3.0.8] 
    at org.springframework.boot.context.properties.ConfigurationPropertiesBeanRegistrar.registerBeanDefinition(ConfigurationPropertiesBeanRegistrar.java:89) ~[spring-boot-3.0.8.jar:3.0.8] 
    at org.springframework.boot.context.properties.ConfigurationPropertiesBeanRegistrar.register(ConfigurationPropertiesBeanRegistrar.java:61) ~[spring-boot-3.0.8.jar:3.0.8] 
    at org.springframework.boot.context.properties.ConfigurationPropertiesBeanRegistrar.register(ConfigurationPropertiesBeanRegistrar.java:55) ~[spring-boot-3.0.8.jar:3.0.8] 
    at java.base/java.lang.Iterable.forEach(Iterable.java:75) ~[na:na] 
    at org.springframework.boot.context.properties.EnableConfigurationPropertiesRegistrar.registerBeanDefinitions(EnableConfigurationPropertiesRegistrar.java:49) ~[spring-boot-3.0.8.jar:3.0.8] 
    at org.springframework.context.annotation.ImportBeanDefinitionRegistrar.registerBeanDefinitions(ImportBeanDefinitionRegistrar.java:86) ~[spring-context-6.0.10.jar:6.0.10] 
    at org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.lambda$loadBeanDefinitionsFromRegistrars$1(ConfigurationClassBeanDefinitionReader.java:373) ~[spring-context-6.0.10.jar:6.0.10] 
    at java.base/java.util.LinkedHashMap.forEach(LinkedHashMap.java:729) ~[na:na] 
    at org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.loadBeanDefinitionsFromRegistrars(ConfigurationClassBeanDefinitionReader.java:372) ~[spring-context-6.0.10.jar:6.0.10] 
    at org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.loadBeanDefinitionsForConfigurationClass(ConfigurationClassBeanDefinitionReader.java:148) ~[spring-context-6.0.10.jar:6.0.10] 
    at org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.loadBeanDefinitions(ConfigurationClassBeanDefinitionReader.java:120) ~[spring-context-6.0.10.jar:6.0.10] 
    at org.springframework.context.annotation.ConfigurationClassPostProcessor.processConfigBeanDefinitions(ConfigurationClassPostProcessor.java:427) ~[spring-context-6.0.10.jar:6.0.10] 
    at org.springframework.context.annotation.ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry(ConfigurationClassPostProcessor.java:287) ~[spring-context-6.0.10.jar:6.0.10] 
    at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanDefinitionRegistryPostProcessors(PostProcessorRegistrationDelegate.java:344) ~[spring-context-6.0.10.jar:6.0.10] 
    at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:115) ~[spring-context-6.0.10.jar:6.0.10] 
    at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:771) ~[spring-context-6.0.10.jar:6.0.10] 
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:589) ~[spring-context-6.0.10.jar:6.0.10] 
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:732) ~[spring-boot-3.0.8.jar:3.0.8] 
    at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:434) ~[spring-boot-3.0.8.jar:3.0.8] 
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:310) ~[spring-boot-3.0.8.jar:3.0.8] 
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1304) ~[spring-boot-3.0.8.jar:3.0.8] 
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1293) ~[spring-boot-3.0.8.jar:3.0.8]   
    at nl.rabobank.mqputter.MqPutterApplication.main(MqPutterApplication.java:10) ~[classes/:na] 
    at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104) ~[na:na] 
    at java.base/java.lang.reflect.Method.invoke(Method.java:578) ~[na:na]
    at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:50) ~[spring-boot-devtools-3.0.8.jar:3.0.8] 
Caused by: java.lang.ClassNotFoundException: jakarta.jms.ConnectionFactory 
    at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:641) ~[na:na] 
    at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188) ~[na:na] 
    at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521) ~[na:na] 
    ... 35 common frames omitted

Solution

  • At the very least you need to include the Jakarta Messaging API jar in your application's classpath.

    You may also need to upgrade your IBM MQ client to 9.3 as it supports Jakarta Messaging (i.e. classes in jakarta.jms.*).