Home > Net >  Spring Boot SOAP Web Service "No adapter for endpoint" in response
Spring Boot SOAP Web Service "No adapter for endpoint" in response

Time:06-27

I'm trying to dig into Spring SOAP web services and JAXB class generation. Following spring.io tutorial, I've managed to create simple web service app, but it's not answering to my request as it supposed to. Here is my code, configuration (UPD fixed, thanks to DimasG, but still not working):

@EnableWs
@Configuration
public class WebServiceConfiguration extends WsConfigurerAdapter {

    @Bean
    public ServletRegistrationBean registrationBean(ApplicationContext context) {
        MessageDispatcherServlet servlet = new MessageDispatcherServlet();
        servlet.setApplicationContext(context);
        servlet.setTransformWsdlLocations(true);
        return new ServletRegistrationBean(servlet, "/ws/*");
    }

    @Bean(name = "employees")
    public DefaultWsdl11Definition defaultWsdl11Definition(XsdSchema schema) {
        DefaultWsdl11Definition definition = new DefaultWsdl11Definition();
        definition.setPortTypeName("EmployeesPort");
        definition.setLocationUri("/ws");
        definition.setTargetNamespace("http://spring/demo/webservice");
        definition.setSchema(schema);
        return definition;
    }

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

}

XSD schema file:

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://spring/demo/webservice"
           targetNamespace="http://spring/demo/webservice" elementFormDefault="qualified">

    <xs:element name="getEmployeeRequest">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="name" type="xs:string"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>

    <xs:element name="getEmployeeResponse">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="employee" type="tns:employee"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>

    <xs:complexType name="employee">
        <xs:sequence>
            <xs:element name="name" type="xs:string"/>
            <xs:element name="age" type="xs:int"/>
            <xs:element name="position" type="xs:string"/>
            <xs:element name="gender" type="tns:gender"/>
        </xs:sequence>
    </xs:complexType>

    <xs:simpleType name="gender">
        <xs:restriction base="xs:string">
            <xs:enumeration value="M"/>
            <xs:enumeration value="F"/>
        </xs:restriction>
    </xs:simpleType>
</xs:schema>

Endpoint:

@Endpoint
public class EmployeeWebService {

    private static final String NAMESPACE_URI = "http://spring/demo/webservice";

    private final List<Employee> employees = new ArrayList<>();

    @PostConstruct
    public void init() {
        employees.addAll(
                Arrays.asList(
                        createEmployee("John Doe", 30, Gender.M, "Manager"),
                        createEmployee("Jane Doe", 27, Gender.F, "QA"),
                        createEmployee("Bob Johns", 28, Gender.M, "Programmer"),
                        createEmployee("Tiffany Collins", 24, Gender.F, "CEO"),
                        createEmployee("Alice", 25, Gender.F, "Secretary")
                )
        );
    }

    @PayloadRoot(namespace = NAMESPACE_URI, localPart = "getEmployeeRequest")
    @ResponsePayload
    public GetEmployeeResponse get(@RequestPayload GetEmployeeRequest request) {
        Employee found = employees.stream()
                .filter(emp -> emp.getName().equals(request.getName()))
                .findFirst()
                .orElseThrow(() -> new RuntimeException("Not found"));
        GetEmployeeResponse response = new GetEmployeeResponse();
        response.setEmployee(found);
        return response;
    }

}

SOAP getEmployeeRequest:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
                  xmlns:gs="http://spring/demo/webservice">
    <soapenv:Header/>
    <soapenv:Body>
        <gs:getEmployeeRequest>
            <gs:name>Alice</gs:name>
        </gs:getEmployeeRequest>
    </soapenv:Body>
</soapenv:Envelope>

With provided code I'm getting fault message back:

<faultstring xml:lang="en">No adapter for endpoint [public spring.demo.webservice.GetEmployeeResponse com.abondarenkodev.demo.spring.webservice.controller.EmployeeWebService.get(spring.demo.webservice.GetEmployeeRequest)]: Is your endpoint annotated with @Endpoint, or does it implement a supported interface like MessageHandler or PayloadEndpoint?</faultstring>

I've found one possible solution to wrap response and request classes with JAXBElement. Endpoint method with it looks like this:

@PayloadRoot(namespace = NAMESPACE_URI, localPart = "getEmployeeRequest")
@ResponsePayload
public JAXBElement<GetEmployeeResponse> get(@RequestPayload JAXBElement<GetEmployeeRequest> request) {
    Employee found = employees.stream()
            .filter(emp -> emp.getName().equals(request.getValue().getName()))
            .findFirst()
            .orElseThrow(() -> new RuntimeException("Not found"));
    GetEmployeeResponse response = new GetEmployeeResponse();
    response.setEmployee(found);
    return new JAXBElement<>(
            QName.valueOf("GetEmployeeResponse"),
            GetEmployeeResponse.class,
            response
    );
}

There are two options for JAXBElement: jakarta.xml.bind.JAXBElement and javax.xml.bind.JAXBElement. With jakarta element I got same 'No adapter' message, with javax element I'm getting my "Not found" Exception, because request.getValue() is coming as null. enter image description here Second possible solution that I've found is to check if request and response generated classes are annotated with XmlRootElement, and they are indeed annotated. Here is my pom file:

<?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.0</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <groupId>com.abondarenkodev.demo.spring.webservice</groupId>
    <artifactId>spring-soap-demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>spring-soap-demo</name>
    <description>Demo project for Spring Boot WebServices</description>

    <properties>
        <java.version>11</java.version>
    </properties>

    <dependencies>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web-services</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>wsdl4j</groupId>
            <artifactId>wsdl4j</artifactId>
            <version>1.6.3</version>
        </dependency>

        <dependency>
            <groupId>jakarta.xml.bind</groupId>
            <artifactId>jakarta.xml.bind-api</artifactId>
            <version>4.0.0</version>
        </dependency>

        <dependency>
            <groupId>org.jdom</groupId>
            <artifactId>jdom2</artifactId>
            <version>2.0.6.1</version>
        </dependency>

        <dependency>
            <groupId>javax.xml.bind</groupId>
            <artifactId>jaxb-api</artifactId>
            <version>2.3.1</version>
        </dependency>

        <dependency>
            <groupId>org.glassfish.jaxb</groupId>
            <artifactId>jaxb-runtime</artifactId>
            <version>2.3.1</version>
        </dependency>

    </dependencies>

    <build>
        <plugins>

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

            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>jaxb2-maven-plugin</artifactId>
                <version>3.1.0</version>
                <executions>
                    <execution>
                        <id>xjc</id>
                        <goals>
                            <goal>xjc</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <sources>
                        <source>${project.basedir}/src/main/resources/xsd</source>
                    </sources>
                    <outputDirectory>${project.build.directory}/generated-sources/jaxb/</outputDirectory>
                    <clearOutputDir>false</clearOutputDir>
                </configuration>
            </plugin>

        </plugins>
    </build>

</project>

I will appreciate any help. Thank you.

CodePudding user response:

In DefaultWsdl11Definition as I see targetNameSpace is different to that in xsd. And in ServletRegistrationBean /ws/* should be /webservice/*

CodePudding user response:

I've fixed this issue by downgrading Jaxb2 Maven Plugin to version 2.5.0. Last available version of this plugin (3.1.0) generates classes with jakarta imports, while 2.5.0 generates classes with javax imports.

If someone will accidentally step on this question and you know how to fix this with jakarta imports, please let me know.

Final pom file for my project looks like this (no JAXBElement needed in the controller):

<?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.1</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <groupId>com.demo.spring.webservice</groupId>
    <artifactId>demo-spring-webservice</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>demo-spring-webservice</name>
    <description>Demo project for Spring Boot WebServices</description>

    <properties>
        <java.version>11</java.version>
    </properties>

    <dependencies>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web-services</artifactId>
        </dependency>

        <dependency>
            <groupId>wsdl4j</groupId>
            <artifactId>wsdl4j</artifactId>
            <version>1.6.3</version>
        </dependency>

        <dependency>
            <groupId>org.glassfish.jaxb</groupId>
            <artifactId>jaxb-runtime</artifactId>
            <version>2.3.1</version>
        </dependency>

    </dependencies>

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

            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>jaxb2-maven-plugin</artifactId>
                <version>2.5.0</version>
                <executions>
                    <execution>
                        <id>xjc</id>
                        <goals>
                            <goal>xjc</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <sources>
                        <source>${project.basedir}/src/main/resources/xsd</source>
                    </sources>
                    <outputDirectory>${project.build.directory}/generated-sources/jaxb/</outputDirectory>
                    <clearOutputDir>false</clearOutputDir>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>
  • Related