0

I'm trying to set up Spring boot (2.7.2) on JDK 18 with exposing Web service endpoints alongside of normal REST endpoints.

The application boots up without any errors and can server my REST endpoints without any problems but the moment it receives a SOAP request it fails with the following error message:

: Servlet.init() for servlet [messageDispatcherServlet] threw exception

org.springframework.beans.factory.BeanInitializationException: Could not initialize WebServiceMessageReceiverHandlerAdapter; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.ws.soap.saaj.SaajSoapMessageFactory]: Unresolvable class definition; nested exception is java.lang.NoClassDefFoundError: javax/xml/soap/SOAPException
at org.springframework.ws.transport.http.MessageDispatcherServlet.initMessageReceiverHandlerAdapter(MessageDispatcherServlet.java:380)
at org.springframework.ws.transport.http.MessageDispatcherServlet.initStrategies(MessageDispatcherServlet.java:361)
at org.springframework.ws.transport.http.MessageDispatcherServlet.onRefresh(MessageDispatcherServlet.java:296)
at org.springframework.web.servlet.FrameworkServlet.initWebApplicationContext(FrameworkServlet.java:599)
at org.springframework.web.servlet.FrameworkServlet.initServletBean(FrameworkServlet.java:530)
at org.springframework.web.servlet.HttpServletBean.init(HttpServletBean.java:170)
at javax.servlet.GenericServlet.init(GenericServlet.java:158)
at org.apache.catalina.core.StandardWrapper.initServlet(StandardWrapper.java:1164)
at org.apache.catalina.core.StandardWrapper.allocate(StandardWrapper.java:804)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:128)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:541)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:135)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:360)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:399)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:890)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1789)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191)
at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.base/java.lang.Thread.run(Thread.java:833)
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.ws.soap.saaj.SaajSoapMessageFactory]: Unresolvable class definition; nested exception is java.lang.NoClassDefFoundError: javax/xml/soap/SOAPException
at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:156)
at org.springframework.ws.support.DefaultStrategiesHelper.instantiateBean(DefaultStrategiesHelper.java:149)
at org.springframework.ws.support.DefaultStrategiesHelper.getDefaultStrategies(DefaultStrategiesHelper.java:134)
at org.springframework.ws.support.DefaultStrategiesHelper.getDefaultStrategy(DefaultStrategiesHelper.java:214)
at org.springframework.ws.transport.http.MessageDispatcherServlet.initWebServiceMessageFactory(MessageDispatcherServlet.java:389)
at org.springframework.ws.transport.http.MessageDispatcherServlet.initMessageReceiverHandlerAdapter(MessageDispatcherServlet.java:377)
... 24 common frames omitted
 Caused by: java.lang.NoClassDefFoundError: javax/xml/soap/SOAPException
at java.base/java.lang.Class.getDeclaredConstructors0(Native Method)
at java.base/java.lang.Class.privateGetDeclaredConstructors(Class.java:3405)
at java.base/java.lang.Class.getConstructor0(Class.java:3610)
at java.base/java.lang.Class.getDeclaredConstructor(Class.java:2786)
at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:146)
... 29 common frames omitted
Caused by: java.lang.ClassNotFoundException: javax.xml.soap.SOAPException
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:641)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)
... 34 common frames omitted

Here is my pom.xml:

<?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>2.7.2</version>
    <relativePath/> <!-- lookup parent from repository -->
  </parent>
<groupId>com.company</groupId>
<artifactId>simulator-service</artifactId>
<version>1.0.0-SNAPSHOT</version>
<name>simulator-service</name>
<description>Microservice to simulate X</description>

<properties>
    <java.version>17</java.version>
    <maven.compiler.source>17</maven.compiler.source>
    <maven.compiler.target>17</maven.compiler.target>
    <mapstruct.version>1.4.2.Final</mapstruct.version>
    <swagger.v3.annotations.version>2.1.12</swagger.v3.annotations.version>
    <commons.validator.version>1.7</commons.validator.version>
    <logback.ecs.version>1.3.0</logback.ecs.version>
    <lombok.mapstruct.version>0.2.0</lombok.mapstruct.version>
    <commons.io.version>2.11.0</commons.io.version>
    <springdoc.version>1.6.4</springdoc.version>
    <hamcrest-all.version>1.3</hamcrest-all.version>
    <swagger.annotations.version>1.6.4</swagger.annotations.version>
    <jose4j.version>0.7.12</jose4j.version>
</properties>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-validation</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web-services</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
        <optional>true</optional>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-configuration-processor</artifactId>
    </dependency>
    <dependency>
        <groupId>org.flywaydb</groupId>
        <artifactId>flyway-core</artifactId>
    </dependency>
    <dependency>
        <groupId>com.h2database</groupId>
        <artifactId>h2</artifactId>
        <scope>runtime</scope>
    </dependency>
    <dependency>
        <groupId>org.mapstruct</groupId>
        <artifactId>mapstruct</artifactId>
        <version>${mapstruct.version}</version>
    </dependency>
    <dependency>
        <groupId>org.mapstruct</groupId>
        <artifactId>mapstruct-processor</artifactId>
        <version>${mapstruct.version}</version>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
    </dependency>
    <dependency>
        <groupId>wsdl4j</groupId>
        <artifactId>wsdl4j</artifactId>
    </dependency>
    <dependency>
        <groupId>io.swagger.core.v3</groupId>
        <artifactId>swagger-annotations</artifactId>
        <version>${swagger.v3.annotations.version}</version>
    </dependency>
    <dependency>
        <groupId>commons-validator</groupId>
        <artifactId>commons-validator</artifactId>
        <version>${commons.validator.version}</version>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok-mapstruct-binding</artifactId>
        <version>${lombok.mapstruct.version}</version>
    </dependency>
    <dependency>
        <groupId>commons-io</groupId>
        <artifactId>commons-io</artifactId>
        <version>${commons.io.version}</version>
    </dependency>
    <dependency>
      <groupId>org.bitbucket.b_c</groupId>
      <artifactId>jose4j</artifactId>
      <version>${jose4j.version}</version>
    </dependency>
  <!--    expose swagger-->
    <dependency>
        <groupId>org.springdoc</groupId>
        <artifactId>springdoc-openapi-ui</artifactId>
        <version>${springdoc.version}</version>
    </dependency>
  <dependency>
    <groupId>io.swagger</groupId>
    <artifactId>swagger-annotations</artifactId>
    <version>${swagger.annotations.version}</version>
  </dependency>
</dependencies>

<build>
    <finalName>${project.artifactId}-${project.version}</finalName>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <executions>
                <execution>
                    <id>build-info</id>
                    <goals>
                        <goal>build-info</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-dependency-plugin</artifactId>
            <version>${maven-dependency-plugin.version}</version>
            <executions>
                <execution>
                    <id>unpack</id>
                    <phase>package</phase>
                    <goals>
                        <goal>unpack</goal>
                    </goals>
                    <configuration>
                        <artifactItems>
                            <artifactItem>
                                <groupId>${project.groupId}</groupId>
                                <artifactId>${project.artifactId}</artifactId>
                                <version>${project.version}</version>
                            </artifactItem>
                        </artifactItems>
                    </configuration>
                </execution>
            </executions>
        </plugin>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-surefire-plugin</artifactId>
            <configuration>
                <runOrder>alphabetical</runOrder>
            </configuration>
        </plugin>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-failsafe-plugin</artifactId>
        </plugin>
    </plugins>
</build>
<profiles>
    <profile>
        <id>dependency-check</id>
        <build>
            <plugins>
                <plugin>
                    <groupId>org.owasp</groupId>
                    <artifactId>dependency-check-maven</artifactId>
                    <version>6.0.3</version>
                    <executions>
                        <execution>
                            <id>verify</id>
                            <phase>verify</phase>
                            <goals>
                                <goal>check</goal>
                            </goals>
                            <configuration>
                                <format>XML</format>
                            </configuration>
                        </execution>
                    </executions>
                </plugin>
            </plugins>
        </build>
    </profile>
    <profile>
        <id>swaggergen</id>
        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                    <configuration>
                        <profiles>swaggergen</profiles>
                        <jvmArguments>-Dspring.application.admin.enabled=false</jvmArguments>
                    </configuration>
                    <executions>
                        <execution>
                            <id>pre-integration-test</id>
                            <goals>
                                <goal>start</goal>
                            </goals>
                        </execution>
                        <execution>
                            <id>post-integration-test</id>
                            <goals>
                                <goal>stop</goal>
                            </goals>
                        </execution>
                    </executions>
                </plugin>
            </plugins>
        </build>
    </profile>

</profiles>

I have created the following configuration class:

@EnableWs
@Configuration
public class WebServiceConfig
    extends WsConfigurerAdapter
{
  @Bean
  public ServletRegistrationBean messageDispatcherServlet(ApplicationContext applicationContext) {
    MessageDispatcherServlet servlet = new MessageDispatcherServlet();
    servlet.setApplicationContext(applicationContext);
    servlet.setTransformWsdlLocations(true);
    return new ServletRegistrationBean(servlet, "/webservices/Service/SoapStubService", "/webservices/Service/*");
  }

  @Bean(name = "bnl")
  public DefaultWsdl11Definition defaultWsdl11Definition(XsdSchema bnlSchema) {
    DefaultWsdl11Definition wsdl11Definition = new DefaultWsdl11Definition();
    wsdl11Definition.setPortTypeName("bnlPort");
    wsdl11Definition.setLocationUri("/webservices/Service/SoapStubService");
    wsdl11Definition.setTargetNamespace("http://www.bnl.ll/company/schemas");
    wsdl11Definition.setSchema(bnlSchema);
    return wsdl11Definition;
  }

  @Bean
  public XsdSchema bnlSchema() {
    return new SimpleXsdSchema(new ClassPathResource("/xsd/bnl.xsd"));
  }
}

and the following endpoint class to receive the incoming request:

@Endpoint
public class BnlSoapEndpoint
{
  private static final String NAMESPACE_URI = "http://www.bnl.ll/company/schemas";

  @Autowired
  public BilSoapEndpoint() {
    super();
  }

  @PayloadRoot(namespace = NAMESPACE_URI, localPart = "PingBnl")
  @ResponsePayload
  public PingResponse pingBnl(@RequestPayload PingRequest pingRequest) {
    PingResponse response = new PingResponse();
    response.setStatus(PingStatus.SUCCESS);
    return response;
  }

}

The matching POJOs are using the javax.xml.bind packages which are working and running fine as it seems. Trying to replace them with the jakarta equivalent for newer JDKs caused problems with Hibernate on runtime.

I have tried a bunch of google results and StackOverflow results from 2015-2018 but none have resolved my problem. Here were some dependencies I tried without success or any change in the exception:

    <!-- <dependency>
      <groupId>jakarta.xml.soap</groupId>
      <artifactId>jakarta.xml.soap-api</artifactId>
      <version>3.0.0</version>
    </dependency> -->
    <!-- <dependency>
      <groupId>javax.xml.soap</groupId>
      <artifactId>javax.xml.soap-api</artifactId>
      <version>1.4.0</version>
    </dependency>
    <dependency>
      <groupId>javax.xml.ws</groupId>
      <artifactId>jaxws-api</artifactId>
      <version>2.3.1</version>
    </dependency>
    <dependency>
      <groupId>com.sun.xml.messaging.saaj</groupId>
      <artifactId>saaj-impl</artifactId>
      <version>3.0.0</version>
    </dependency> -->
  <!-- <dependency>
    <groupId>jakarta.xml.bind</groupId>
    <artifactId>jakarta.xml.bind-api</artifactId>
    <version>4.0.0</version>
  </dependency>
    <dependency>
      <groupId>org.glassfish.jaxb</groupId>
      <artifactId>jaxb-runtime</artifactId>
      <version>4.0.0</version>
    </dependency> -->

Any help in resolving this would be highly appreciated.

PS: Resources I read and tried out below

ExceptionError - ClassNotFoundException: javax.xml.soap.SOAPException

StackOverflow - Question 48626824

StackOverflow - JAXB plugin differences

StackOverflow - How to use Spring with WSDL

StackOverflow - how-to-resolve-java-lang-noclassdeffounderror-javax-xml-bind-jaxbexception

EDIT:

bnl.xsd as requested:

<xs:schema elementFormDefault="qualified" targetNamespace="http://www.bnl.ll/company/schemas" version="1.0"
           xmlns:tns="http://www.bnl.ll/company/schemas" xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:element name="PingRequest">
    <xs:complexType>
      <xs:sequence/>
    </xs:complexType>
  </xs:element>
  <xs:element name="PingResponse">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="status" type="tns:PingStatus"/>
        <xs:element name="message" type="xs:string"/>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
  <xs:complexType abstract="true" name="number">
    <xs:sequence/>
  </xs:complexType>
  <xs:simpleType name="PingStatus">
    <xs:restriction base="xs:string">
      <xs:enumeration value="SUCCESS"/>
      <xs:enumeration value="ERROR"/>
    </xs:restriction>
  </xs:simpleType>
</xs:schema>

screenshot of soapUI request failing:

SoapUI

Nico
  • 1,727
  • 1
  • 24
  • 42
  • Can you share WSDL URL and schema(bnl.xsd) ? – Bench Vue Aug 09 '22 at 08:11
  • 1
    I added the XSD content ( just pingRequest and removed any other types etc. ) I cannot provide any WSDL since it contains information not shareable and the examples above have already been modified to not contain any sensitive data, I'm sorry. – Nico Aug 09 '22 at 08:28
  • what if you configure the `spring-boot-starter-web-services` dependency like this: ` org.springframework.boot spring-boot-starter-web-services org.springframework.boot spring-boot-starter-tomcat ` recompile and, do you still receive the error? – sudipn Aug 09 '22 at 08:33
  • @sudipn Sadly this did not change the exception and I still receive the ClassNotFoundException for SOAPException upon receiving a soap request. – Nico Aug 09 '22 at 08:37
  • 1
    `spring-boot-starter-web-services` depends on `jakarta.xml.ws:jakarta.xml.ws-api` which contains the `javax.xml.soap.SOAPException` class so this should work without adding any extra dependencies. I would guess that Maven may have corrupted the jar when it downloaded it. I'd try purging your local Maven repository and rebuilding your application. – Andy Wilkinson Aug 09 '22 at 09:10
  • 1
    @Nico, I ran with your bnl.xsd on Ubuntu (20.04), SpringBoot 2.7.2, JDK 17.0.1 and jaxb2-maven-plugin v 2.5.0. It works fine to serve as WSDL and can get the response to by Postman. But I did not try Jakarta. Why you need a Jakarta? – Bench Vue Aug 09 '22 at 09:37
  • @AndyWilkinson Interestingly enough I just created a new an blank project through Spring Initialzr and there it works completely fine. Seems like something really is wrong with my project or other dependencies added. Even after purging my local mvn repository with '''mvn dependency:purge-local-repository'''' it still fails. Will probably clean my whole .m2 folder and re-attempt after also cleaning my IDE caches. – Nico Aug 09 '22 at 10:13

1 Answers1

0

As Andy Wilkinson pointed out in the comments my local repository got broken or my IDE was holding incorrect caches somewhere and after cleaning my whole .m2 local repository and cleaning the IDE caches, it built completely fine and is able to respond to the SOAP message!

Nico
  • 1,727
  • 1
  • 24
  • 42