首页 > 解决方案 > Kotlin Unmarshalling 中的 SOAP Web 服务失败

问题描述

一开始这是一个非常普遍的问题,但有没有人使用 Spring Boot 在 Kotlin 中构建 SOAP Web 服务。我正在 Kotlin 中构建一个 SOAP Web 服务,并面临一个关于 Kotlin 数据类的非常奇怪的问题,尽管我正在使用jackson-module-kotlin.

问题是:

Resolving exception from endpoint [public com.abdulsamadsyed.webservice.model.WebserviceResponse com.abdulsamadsyed.webservice.endpoint.WebserviceEndpoint.getCountry(com.abdulsamadsyed.webservice.model.WebserviceRequest)]: com.sun.xml.bind.v2.runtime.IllegalAnnotationsException: 1 counts of IllegalAnnotationExceptions
com.abdulsamadsyed.webservice.model.WebserviceRequest does not have a no-arg default constructor.
    this problem is related to the following location:
        at com.abdulsamadsyed.webservice.model.WebserviceRequest

这是我的 xsd 文件

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://com.abdulsamadsyed/guides/webservice"
       targetNamespace="http://com.abdulsamadsyed/guides/webservice" elementFormDefault="qualified">

<xs:element name="WebserviceRequest">
    <xs:complexType>
        <xs:sequence>
            <xs:element name="name" type="xs:string"/>
        </xs:sequence>
    </xs:complexType>
</xs:element>
<xs:element name="WebserviceResponse">
    <xs:complexType>
        <xs:sequence>
            <xs:element name="country">
                <xs:complexType>
                    <xs:sequence>
                        <xs:element name="name" type="xs:string"/>
                        <xs:element name="population" type="xs:int"/>
                        <xs:element name="capital" type="xs:string"/>
                    </xs:sequence>
                </xs:complexType>
            </xs:element>
        </xs:sequence>
    </xs:complexType>
</xs:element>

</xs:schema>

请求的数据类:

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = ["name"])
@XmlRootElement(name = "WebserviceRequest")
class WebserviceRequest(@JsonProperty("name") val name: String)

响应的数据类:

@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "WebserviceResponse")
class WebserviceResponse (
    @JsonProperty("name") val name: String,
    @JsonProperty("population") val population: Int,
    @JsonProperty("capital")  val capital: String
    )

配置 kotlin 模块的简单配置类:

@Configuration
class WebserviceConfig {
    @Bean
    fun objectMapper(): ObjectMapper = ObjectMapper()
        .registerKotlinModule()
        .registerModule(JavaTimeModule())
}

SOAP 请求的配置类:

@EnableWs
@Configuration
class SOAPRequestConfig {
    @Bean
    fun messageDispatcherServlet(applicationContext: ApplicationContext): ServletRegistrationBean<MessageDispatcherServlet> {
        val servlet = MessageDispatcherServlet()
        servlet.setApplicationContext(applicationContext)
        servlet.isTransformWsdlLocations = true
        return ServletRegistrationBean(servlet, "/findcountry/*")
    }
    @Bean(name = arrayOf("countries"))
    fun defaultWsdl11Definition(scoringSchema: XsdSchema?): DefaultWsdl11Definition {
        val wsdl11Definition = DefaultWsdl11Definition()
        wsdl11Definition.setPortTypeName("CountriesPort")
        wsdl11Definition.setLocationUri("/findcountry")
        wsdl11Definition.setTargetNamespace("http://com.abdulsamadsyed/guides/webservice")
        wsdl11Definition.setSchema(scoringSchema)
        return wsdl11Definition
    }
    @Bean
    fun serviceSchema(): XsdSchema {
        return SimpleXsdSchema(ClassPathResource("service.xsd"))
    }
}

我的 POM(我正在使用 Java 11):

<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web-services</artifactId>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.module</groupId>
            <artifactId>jackson-module-kotlin</artifactId>
        </dependency>
        <dependency>
            <groupId>org.jetbrains.kotlin</groupId>
            <artifactId>kotlin-reflect</artifactId>
        </dependency>
        <dependency>
            <groupId>org.jetbrains.kotlin</groupId>
            <artifactId>kotlin-stdlib-jdk8</artifactId>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.dataformat</groupId>
            <artifactId>jackson-dataformat-xml</artifactId>
            <version>2.12.4</version>
        </dependency>
        <dependency>
            <groupId>wsdl4j</groupId>
            <artifactId>wsdl4j</artifactId>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.module</groupId>
            <artifactId>jackson-module-kotlin</artifactId>
            <version>2.12.4</version>
        </dependency>
        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
        </dependency>
        <!-- Using jpa because it has Jaxb implemetation-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
            <version>2.5.4</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!--        <dependency>-->
        <!--            <groupId>javax.xml.bind</groupId>-->
        <!--            <artifactId>jaxb-api</artifactId>-->
        <!--        </dependency>-->

        <!--        &lt;!&ndash; JAXB Implementation &ndash;&gt;-->
        <!--        <dependency>-->
        <!--            <groupId>com.sun.xml.bind</groupId>-->
        <!--            <artifactId>jaxb-impl</artifactId>-->
        <!--            <version>3.0.0</version>-->
        <!--            <scope>runtime</scope>-->
        <!--        </dependency>-->

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

        <!--        &lt;!&ndash; https://mvnrepository.com/artifact/javax.activation/activation &ndash;&gt;-->
        <!--        <dependency>-->
        <!--            <groupId>javax.activation</groupId>-->
        <!--            <artifactId>activation</artifactId>-->
        <!--            <version>1.1</version>-->
        <!--        </dependency>-->

        <!--        &lt;!&ndash; https://mvnrepository.com/artifact/org.glassfish.jaxb/jaxb-runtime &ndash;&gt;-->
        <!--        <dependency>-->
        <!--            <groupId>org.glassfish.jaxb</groupId>-->
        <!--            <artifactId>jaxb-runtime</artifactId>-->
        <!--        </dependency>-->
    </dependencies>

它只接受请求并返回一个包含 3 个字段的响应。

现在是我的 Endpoint 类,它接收请求并返回响应对象

@Endpoint
class WebserviceEndpoint {
    @PayloadRoot(namespace = "http://com.abdulsamadsyed/guides/webservice", localPart = "WebserviceRequest")
    @ResponsePayload
    fun getCountry(@RequestPayload request: WebserviceRequest): WebserviceResponse {
        print("---------------------------" +  request.name + "-------------------------")
        return WebserviceResponse(request.name, 20000, "helsinki")
    }
}

当我使用以下国家-request.xml 运行它时

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
   xmlns:gs="http://com.abdulsamadsyed/guides/webservice">
   <soapenv:Header/>
   <soapenv:Body>
      <gs:WebserviceRequest>
         <gs:name>Spain</gs:name>
      </gs:WebserviceRequest>
   </soapenv:Body>
</soapenv:Envelope>

用这个命令

curl --header "content-type: text/xml" -d @countries-request.xml http://localhost:8081/findcountry

它给了我以下错误,我也粘贴在上面。

Resolving exception from endpoint [public com.abdulsamadsyed.webservice.model.WebserviceResponse com.abdulsamadsyed.webservice.endpoint.WebserviceEndpoint.getCountry(com.abdulsamadsyed.webservice.model.WebserviceRequest)]: com.sun.xml.bind.v2.runtime.IllegalAnnotationsException: 1 counts of IllegalAnnotationExceptions
    com.abdulsamadsyed.webservice.model.WebserviceRequest does not have a no-arg default constructor.
        this problem is related to the following location:
            at com.abdulsamadsyed.webservice.model.WebserviceRequest

实际上,当请求到来时,解组应该起作用,因为我正在使用 jackson-module-kotlin并且它说我们不需要为数据类属性提供默认值。https://github.com/FasterXML/jackson-module-kotlin

任何帮助都将受到高度评价,因为我无法找到许多使用 Kotlin 构建 SOAP Web 服务的资源。

标签: spring-bootkotlinsoapjacksonunmarshalling

解决方案


推荐阅读