├── .java-version ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── settings.gradle ├── .gitattributes ├── .gitignore ├── .github ├── release.yml ├── workflows │ ├── release.yml │ ├── publish.yml │ └── ci.yml └── dependabot.yml ├── wsdl2kotlin-gradle-plugin ├── src │ └── main │ │ └── kotlin │ │ └── org │ │ └── codefirst │ │ └── wsdl2kotlin │ │ ├── WSDL2KotlinPluginConfiguration.kt │ │ └── WSDL2KotlinPlugin.kt └── build.gradle ├── wsdl2kotlin ├── src │ ├── test │ │ ├── kotlin │ │ │ └── org │ │ │ │ └── codefirst │ │ │ │ └── wsdl2kotlin │ │ │ │ ├── WSDLTest.kt │ │ │ │ └── XSDTest.kt │ │ └── resources │ │ │ ├── sample.xsd.xml │ │ │ └── sample.wsdl.xml │ └── main │ │ └── kotlin │ │ └── org │ │ └── codefirst │ │ └── wsdl2kotlin │ │ ├── Output.kt │ │ ├── Main.kt │ │ ├── WSDL.kt │ │ ├── WSDL2Kotlin.kt │ │ └── XSD.kt └── build.gradle ├── wsdl2kotlin-runtime ├── build.gradle └── src │ ├── test │ └── kotlin │ │ └── org │ │ └── codefirst │ │ └── wsdl2kotlin │ │ ├── FixSurrogatePairOutputStreamTest.kt │ │ ├── WSDLServiceIntTest.kt │ │ └── WSDLServiceStringTest.kt │ └── main │ └── kotlin │ └── org │ └── codefirst │ └── wsdl2kotlin │ ├── FixSurrogatePairOutputStream.kt │ └── WSDLService.kt ├── LICENSE ├── README.md ├── gradlew.bat └── gradlew /.java-version: -------------------------------------------------------------------------------- 1 | 11 2 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suer/wsdl2kotlin/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'wsdl2kotlin' 2 | 3 | include('wsdl2kotlin') 4 | include('wsdl2kotlin-runtime') 5 | include('wsdl2kotlin-gradle-plugin') 6 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # 2 | # https://help.github.com/articles/dealing-with-line-endings/ 3 | # 4 | # These are explicitly windows files and should use crlf 5 | *.bat text eol=crlf 6 | 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore Gradle project-specific cache directory 2 | .gradle 3 | 4 | # Ignore Gradle build output directory 5 | build 6 | bin/ 7 | 8 | # idea 9 | /.idea/ 10 | /local.properties 11 | 12 | -------------------------------------------------------------------------------- /.github/release.yml: -------------------------------------------------------------------------------- 1 | changelog: 2 | categories: 3 | - title: What's Changed 4 | labels: 5 | - '*' 6 | exclude: 7 | labels: 8 | - dependencies 9 | - title: Dependencies 10 | labels: 11 | - dependencies 12 | -------------------------------------------------------------------------------- /wsdl2kotlin-gradle-plugin/src/main/kotlin/org/codefirst/wsdl2kotlin/WSDL2KotlinPluginConfiguration.kt: -------------------------------------------------------------------------------- 1 | package org.codefirst.wsdl2kotlin 2 | 3 | open class WSDL2KotlinPluginConfiguration { 4 | var outputDirectory: String? = null 5 | var paths: List = emptyList() 6 | } 7 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-bin.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /wsdl2kotlin-gradle-plugin/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'java-gradle-plugin' 3 | } 4 | 5 | dependencies { 6 | implementation gradleApi() 7 | implementation project(':wsdl2kotlin') 8 | } 9 | 10 | gradlePlugin { 11 | plugins { 12 | wsdl2kotlinPlugin { 13 | id = 'org.codefirst.wsdl2kotlin.wsdl2kotlin-gradle-plugin' 14 | displayName = 'WSDL2Kotlin' 15 | description = 'Generate Kotlin codes from WSDL and XSD files.' 16 | implementationClass = 'org.codefirst.wsdl2kotlin.WSDL2KotlinPlugin' 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /wsdl2kotlin/src/test/kotlin/org/codefirst/wsdl2kotlin/WSDLTest.kt: -------------------------------------------------------------------------------- 1 | package org.codefirst.wsdl2kotlin 2 | 3 | import kotlin.test.Test 4 | import kotlin.test.assertEquals 5 | 6 | class WSDLTest { 7 | @Test 8 | fun testParse() { 9 | val path = this::class.java.getResource("/sample.wsdl.xml").file 10 | val wsdl = WSDL.parse(path) 11 | assertEquals(wsdl.service.name, "SampleService") 12 | } 13 | 14 | @Test 15 | fun testPackageName() { 16 | val path = this::class.java.getResource("/sample.wsdl.xml").file 17 | val wsdl = WSDL.parse(path) 18 | assertEquals(wsdl.packageName, "org.codefirst.sample.service") 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /wsdl2kotlin/src/main/kotlin/org/codefirst/wsdl2kotlin/Output.kt: -------------------------------------------------------------------------------- 1 | package org.codefirst.wsdl2kotlin 2 | 3 | import java.io.File 4 | import java.nio.charset.Charset 5 | 6 | class Output( 7 | private val serviceName: String, 8 | private val packageName: String, 9 | private val code: String, 10 | ) { 11 | fun save(dir: String = "./") { 12 | val directory = File(dir, packageName.replace('.', '/')) 13 | if (!directory.exists()) { 14 | directory.mkdirs() 15 | } 16 | val file = File(directory, "$serviceName.kt") 17 | println("Generating ${file.canonicalPath} ...") 18 | file.writeText(code, Charset.forName("UTF-8")) 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | 3 | on: 4 | push: 5 | tags: 6 | - "v[0-9]+.[0-9]+.[0-9]+" 7 | 8 | permissions: 9 | contents: write 10 | pull-requests: read 11 | 12 | jobs: 13 | build: 14 | runs-on: ubuntu-latest 15 | steps: 16 | - name: Check out 17 | uses: actions/checkout@v6 18 | - name: Delete release if exists 19 | run: gh release delete ${{ github.ref_name }} -y 20 | continue-on-error: true 21 | env: 22 | GITHUB_TOKEN: ${{ github.token }} 23 | - name: Create release 24 | run: gh release create ${{ github.ref_name }} --generate-notes 25 | env: 26 | GITHUB_TOKEN: ${{ github.token }} 27 | -------------------------------------------------------------------------------- /wsdl2kotlin-gradle-plugin/src/main/kotlin/org/codefirst/wsdl2kotlin/WSDL2KotlinPlugin.kt: -------------------------------------------------------------------------------- 1 | package org.codefirst.wsdl2kotlin 2 | 3 | import org.gradle.api.Plugin 4 | import org.gradle.api.Project 5 | 6 | class WSDL2KotlinPlugin : Plugin { 7 | override fun apply(project: Project) { 8 | val extension = project.extensions.create("wsdl2kotlin", WSDL2KotlinPluginConfiguration::class.java) 9 | 10 | project.task("wsdl2kotlin") { 11 | it.doLast { 12 | val paths = extension.paths 13 | val outputs = WSDL2Kotlin().run(*paths.toTypedArray()) 14 | outputs.forEach { 15 | it.save(extension.outputDirectory ?: ".") 16 | } 17 | } 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /wsdl2kotlin/src/test/kotlin/org/codefirst/wsdl2kotlin/XSDTest.kt: -------------------------------------------------------------------------------- 1 | package org.codefirst.wsdl2kotlin 2 | 3 | import kotlin.test.Test 4 | import kotlin.test.assertEquals 5 | 6 | class XSDTest { 7 | @Test 8 | fun testParse() { 9 | val path = this::class.java.getResource("/sample.xsd.xml").file 10 | val xsd = XSD.parse(path) 11 | assertEquals(32, xsd.elements.size) 12 | } 13 | 14 | @Test 15 | fun testIsXSDTrue() { 16 | val path = this::class.java.getResource("/sample.xsd.xml").file 17 | assertEquals(true, XSD.isXSD(path)) 18 | } 19 | 20 | @Test 21 | fun testIsXSDFalse() { 22 | val path = this::class.java.getResource("/sample.wsdl.xml").file 23 | assertEquals(false, XSD.isXSD(path)) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /wsdl2kotlin/build.gradle: -------------------------------------------------------------------------------- 1 | dependencies { 2 | // This dependency is used internally, and not exposed to consumers on their own compile classpath. 3 | implementation 'com.google.guava:guava:33.5.0-jre' 4 | 5 | implementation "com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.20.1" 6 | implementation "com.github.ajalt.clikt:clikt:5.0.3" 7 | } 8 | 9 | publishing { 10 | publications { 11 | gpr(MavenPublication) { 12 | from(components.java) 13 | pom { 14 | licenses { 15 | license { 16 | name = "MIT License" 17 | url = "https://www.opensource.org/licenses/mit-license.php" 18 | } 19 | } 20 | } 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /wsdl2kotlin-runtime/build.gradle: -------------------------------------------------------------------------------- 1 | dependencies { 2 | // This dependency is used internally, and not exposed to consumers on their own compile classpath. 3 | implementation 'com.google.guava:guava:33.5.0-jre' 4 | 5 | implementation 'org.jetbrains.kotlin:kotlin-reflect' 6 | 7 | testImplementation 'com.github.tomakehurst:wiremock-standalone:3.0.1' 8 | 9 | implementation 'com.squareup.okhttp3:okhttp:5.3.2' 10 | } 11 | 12 | publishing { 13 | publications { 14 | gpr(MavenPublication) { 15 | from(components.java) 16 | pom { 17 | licenses { 18 | license { 19 | name = "MIT License" 20 | url = "https://www.opensource.org/licenses/mit-license.php" 21 | } 22 | } 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: Publish 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | 8 | jobs: 9 | build: 10 | env: 11 | USERNAME: suer 12 | TOKEN: ${{ secrets.GITHUB_TOKEN }} 13 | runs-on: ubuntu-latest 14 | steps: 15 | - name: Check out 16 | uses: actions/checkout@v6 17 | - name: Set up JDK 18 | uses: actions/setup-java@v5 19 | with: 20 | distribution: 'zulu' 21 | java-version-file: '.java-version' 22 | - uses: actions/cache@v5 23 | with: 24 | path: | 25 | ~/.gradle/caches 26 | ~/.gradle/wrapper 27 | key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }} 28 | restore-keys: | 29 | ${{ runner.os }}-gradle- 30 | - name: Publish all modules 31 | run: ./gradlew publish 32 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "gradle" 4 | directories: 5 | - "/" 6 | - "/wsdl2kotlin/" 7 | - "/wsdl2kotlin-runtime/" 8 | - "/wsdl2kotlin-gradle-plugin/" 9 | schedule: 10 | interval: "weekly" 11 | timezone: "Asia/Tokyo" 12 | day: "friday" 13 | groups: 14 | kotlin: 15 | patterns: 16 | - "org.jetbrains.kotlin.jvm" 17 | - "org.jetbrains.kotlin:kotlin-bom" 18 | - "org.jetbrains.kotlin:kotlin-stdlib" 19 | guava: 20 | patterns: 21 | - "com.google.guava:guava" 22 | ktlint: 23 | patterns: 24 | - "com.pinterest.ktlint:ktlint-cli" 25 | ignore: 26 | - dependency-name: "org.codefirst.wsdl2kotlin:wsdl2kotlin" 27 | 28 | - package-ecosystem: "github-actions" 29 | directory: "/" 30 | schedule: 31 | interval: "weekly" 32 | timezone: "Asia/Tokyo" 33 | day: "friday" 34 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 suer 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | 11 | -------------------------------------------------------------------------------- /wsdl2kotlin/src/main/kotlin/org/codefirst/wsdl2kotlin/Main.kt: -------------------------------------------------------------------------------- 1 | package org.codefirst.wsdl2kotlin 2 | 3 | import com.github.ajalt.clikt.core.CliktCommand 4 | import com.github.ajalt.clikt.core.main 5 | import com.github.ajalt.clikt.parameters.arguments.argument 6 | import com.github.ajalt.clikt.parameters.arguments.multiple 7 | import com.github.ajalt.clikt.parameters.arguments.unique 8 | import com.github.ajalt.clikt.parameters.options.default 9 | import com.github.ajalt.clikt.parameters.options.option 10 | import com.github.ajalt.clikt.parameters.types.path 11 | import java.nio.file.Path 12 | 13 | class Main : CliktCommand() { 14 | private val dir: String by option("-d", "--dir", help = "output directory").default("./") 15 | private val paths: Set by argument().path(mustExist = true).multiple().unique() 16 | 17 | override fun run() { 18 | val outputs = WSDL2Kotlin().run(*paths.map { it.toString() }.toTypedArray()) 19 | 20 | outputs.forEach { 21 | it.save(dir) 22 | } 23 | } 24 | } 25 | 26 | fun main(args: Array) { 27 | Main().main(args) 28 | } 29 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | pull_request: 5 | push: 6 | branches: 7 | - master 8 | 9 | jobs: 10 | build: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - name: Check out 14 | uses: actions/checkout@v6 15 | - name: Set up JDK 16 | uses: actions/setup-java@v5 17 | with: 18 | distribution: 'zulu' 19 | java-version-file: '.java-version' 20 | - uses: actions/cache@v5 21 | with: 22 | path: | 23 | ~/.gradle/caches 24 | ~/.gradle/wrapper 25 | key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }} 26 | restore-keys: | 27 | ${{ runner.os }}-gradle- 28 | - name: Build and test all modules 29 | run: ./gradlew build 30 | - name: Upload jar files 31 | uses: actions/upload-artifact@v5 32 | with: 33 | name: jar 34 | path: | 35 | wsdl2kotlin/build/libs/wsdl2kotlin.jar 36 | wsdl2kotlin-runtime/build/libs/wsdl2kotlin-runtime.jar 37 | wsdl2kotlin-gradle-plugin/build/libs/wsdl2kotlin-gradle-plugin.jar 38 | -------------------------------------------------------------------------------- /wsdl2kotlin-runtime/src/test/kotlin/org/codefirst/wsdl2kotlin/FixSurrogatePairOutputStreamTest.kt: -------------------------------------------------------------------------------- 1 | package org.codefirst.wsdl2kotlin 2 | 3 | import org.junit.Test 4 | import java.io.ByteArrayOutputStream 5 | import kotlin.test.assertEquals 6 | 7 | class FixSurrogatePairOutputStreamTest { 8 | private fun assertStream( 9 | input: String, 10 | output: String, 11 | ) { 12 | val byteStream = ByteArrayOutputStream() 13 | val stream = FixSurrogatePairOutputStream(byteStream) 14 | stream.bufferedWriter().use { 15 | it.write(input) 16 | } 17 | assertEquals(output, byteStream.toString()) 18 | } 19 | 20 | @Test 21 | fun testSimpleString() { 22 | assertStream("Hello World", "Hello World") 23 | } 24 | 25 | @Test 26 | fun testSurrogatePairString() { 27 | assertStream("��", "𠀋") 28 | } 29 | 30 | @Test 31 | fun testSuspiciousString1() { 32 | assertStream("&", "&") 33 | } 34 | 35 | @Test 36 | fun testSuspiciousString2() { 37 | assertStream("&", "&") 38 | } 39 | 40 | @Test 41 | fun testSuspiciousString3() { 42 | assertStream(";", ";") 43 | } 44 | 45 | @Test 46 | fun testSuspiciousString4() { 47 | assertStream("&", "&") 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | WSDL2Kotlin 2 | -------------------- 3 | 4 | A stub generator for services implemented by WSDL. 5 | 6 | Inspired by [WSDL2Swift](https://github.com/banjun/WSDL2Swift) 7 | 8 | # usage 9 | 10 | Add maven repository to `build.gradle`: 11 | 12 | ```gradle:build.gradle 13 | buildscript { 14 | repositories { 15 | maven { 16 | name = "GitHubPackages" 17 | url = uri("https://maven.pkg.github.com/suer/wsdl2kotlin") 18 | credentials { 19 | username = project.findProperty("gpr.user") ?: System.getenv("USERNAME") ?: "suer" 20 | password = project.findProperty("gpr.key") ?: System.getenv("TOKEN") ?: "" 21 | } 22 | } 23 | } 24 | } 25 | 26 | ``` 27 | 28 | Then, add plugin configuration: 29 | 30 | ```gradle:build.gradle 31 | apply plugin: 'org.codefirst.wsdl2kotlin.wsdl2kotlin-gradle-plugin' 32 | wsdl2kotlin { 33 | // path to WSDL and XSD files 34 | paths = ["app/src/test/resources/sample.wsdl.xml", "app/src/test/resources/sample.xsd.xml"] 35 | // path to output destination directory of generated source code 36 | outputDirectory = "app/src/main/kotlin/" 37 | } 38 | ``` 39 | 40 | Generate codes by: 41 | 42 | ``` 43 | $ ./gradlew wsdl2kotlin 44 | ``` 45 | 46 | Finally, append `wsdl2kotlin-runtime` to `app/build.gradle`: 47 | 48 | ```gradle:app/build.gradle 49 | dependencies { 50 | implementation 'org.codefirst.wsdl2kotlin:wsdl2kotlin-runtime:0.6.0' 51 | } 52 | ``` 53 | 54 | # for developers 55 | 56 | ## build 57 | 58 | 59 | ``` 60 | $ ./gradlew build 61 | ``` 62 | 63 | ## test 64 | 65 | 66 | ``` 67 | $ ./gradlew test 68 | ``` 69 | 70 | ## lint 71 | 72 | check your source code: 73 | 74 | ``` 75 | $ ./gradlew ktlint 76 | ``` 77 | 78 | format all source code automatically: 79 | 80 | ``` 81 | $ ./gradlew ktFormat 82 | ``` 83 | 84 | -------------------------------------------------------------------------------- /wsdl2kotlin-runtime/src/main/kotlin/org/codefirst/wsdl2kotlin/FixSurrogatePairOutputStream.kt: -------------------------------------------------------------------------------- 1 | package org.codefirst.wsdl2kotlin 2 | 3 | import java.io.ByteArrayOutputStream 4 | import java.io.OutputStream 5 | 6 | // to fix https://bugs.openjdk.java.net/browse/JDK-8203810 7 | class FixSurrogatePairOutputStream( 8 | private val outputStream: OutputStream, 9 | ) : OutputStream() { 10 | private val buffer = ByteArrayOutputStream() 11 | 12 | private var inNumericalCharacterReferences = false 13 | 14 | private var highChar: Int = 0 15 | 16 | override fun write(b: Int) { 17 | if ('&'.code == b) { 18 | inNumericalCharacterReferences = true 19 | } 20 | 21 | if (inNumericalCharacterReferences) { 22 | buffer.write(b) 23 | 24 | if (';'.code == b) { 25 | inNumericalCharacterReferences = false 26 | 27 | // � 28 | val numericalCharacterReferences = buffer.toString() 29 | 30 | // 55360 31 | val charCode = 32 | numericalCharacterReferences 33 | .removePrefix("&#") 34 | .removeSuffix(";") 35 | .toIntOrNull() 36 | 37 | if (charCode == null) { 38 | highChar = 0 39 | outputStream.write(numericalCharacterReferences.toByteArray()) 40 | } else { 41 | if ('\uD800'.code <= charCode && charCode <= '\uDBFF'.code) { 42 | highChar = charCode 43 | } else { 44 | if (highChar > 0) { 45 | // 𠀋 46 | val unicode = String(intArrayOf(highChar, charCode), 0, 2) 47 | 48 | // 131083 49 | val codePoint = unicode.codePointAt(0) 50 | 51 | // 𠀋 52 | outputStream.write("&#$codePoint;".toByteArray()) 53 | 54 | highChar = 0 55 | } else { 56 | // < 57 | outputStream.write("&#$charCode;".toByteArray()) 58 | } 59 | } 60 | } 61 | 62 | buffer.reset() 63 | } 64 | } else { 65 | outputStream.write(b) 66 | } 67 | } 68 | 69 | override fun close() { 70 | outputStream.write(buffer.toByteArray()) 71 | outputStream.close() 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /wsdl2kotlin-runtime/src/test/kotlin/org/codefirst/wsdl2kotlin/WSDLServiceIntTest.kt: -------------------------------------------------------------------------------- 1 | package org.codefirst.wsdl2kotlin 2 | 3 | import com.github.tomakehurst.wiremock.client.WireMock.aResponse 4 | import com.github.tomakehurst.wiremock.client.WireMock.post 5 | import com.github.tomakehurst.wiremock.client.WireMock.stubFor 6 | import com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo 7 | import com.github.tomakehurst.wiremock.junit.WireMockRule 8 | import org.junit.Before 9 | import org.junit.Rule 10 | import org.junit.Test 11 | import org.w3c.dom.Element 12 | import kotlin.test.assertEquals 13 | 14 | class SampleServiceInt : WSDLService() { 15 | override val targetNamespace = "http://service.sample.codefirst.org/" 16 | override var endpoint = "http://localhost:18080" 17 | override var path = "service" 18 | 19 | fun request(parameters: SampleService_echoInt): SampleService_echoIntResponse = 20 | requestGeneric(parameters) 21 | } 22 | 23 | @Suppress("ktlint:standard:class-naming") 24 | class SampleService_echoInt : XSDType() { 25 | var arg0: Int? = null 26 | 27 | override fun xmlParams(): Array = 28 | arrayOf( 29 | XMLParam("", "arg0", arg0, Int::class), 30 | ) 31 | 32 | override fun readSOAPEnvelope(bodyElement: Element) { 33 | arg0 = readSOAPEnvelopeFieldNullable(bodyElement, "arg0", Int::class) 34 | } 35 | } 36 | 37 | @Suppress("ktlint:standard:class-naming") 38 | class SampleService_echoIntResponse : XSDType() { 39 | @Suppress("ktlint:standard:property-naming") 40 | var `return`: Int? = null 41 | 42 | override fun xmlParams(): Array = 43 | arrayOf( 44 | XMLParam("", "return", `return`, Int::class), 45 | ) 46 | 47 | override fun readSOAPEnvelope(bodyElement: Element) { 48 | `return` = readSOAPEnvelopeFieldNullable(bodyElement, "return", Int::class) 49 | } 50 | } 51 | 52 | class WSDLServiceIntTest { 53 | @Rule 54 | @JvmField 55 | var wireMockRule = WireMockRule(18080) 56 | 57 | @Before 58 | fun setup() { 59 | val responseBody = 60 | """ 61 | | 62 | | 63 | |123 64 | | 65 | """.trimMargin() 66 | 67 | stubFor( 68 | post(urlEqualTo("/service")) 69 | .willReturn( 70 | aResponse() 71 | .withHeader("Content-Type", "text/xml") 72 | .withBody(responseBody), 73 | ), 74 | ) 75 | } 76 | 77 | @Test 78 | fun testEchoInt() { 79 | val params = SampleService_echoInt() 80 | params.arg0 = 123 81 | val response = SampleServiceInt().request(params) 82 | assertEquals(123, response.`return`) 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /wsdl2kotlin-runtime/src/test/kotlin/org/codefirst/wsdl2kotlin/WSDLServiceStringTest.kt: -------------------------------------------------------------------------------- 1 | package org.codefirst.wsdl2kotlin 2 | 3 | import com.github.tomakehurst.wiremock.client.WireMock.aResponse 4 | import com.github.tomakehurst.wiremock.client.WireMock.post 5 | import com.github.tomakehurst.wiremock.client.WireMock.stubFor 6 | import com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo 7 | import com.github.tomakehurst.wiremock.junit.WireMockRule 8 | import org.junit.Before 9 | import org.junit.Rule 10 | import org.junit.Test 11 | import org.w3c.dom.Element 12 | import kotlin.test.assertEquals 13 | 14 | class SampleService : WSDLService() { 15 | override val targetNamespace = "http://service.sample.codefirst.org/" 16 | override var endpoint = "http://localhost:18080" 17 | override var path = "service" 18 | 19 | fun request(parameters: SampleService_echoString): SampleService_echoStringResponse = 20 | requestGeneric(parameters) 21 | } 22 | 23 | @Suppress("ktlint:standard:class-naming") 24 | class SampleService_echoString : XSDType() { 25 | var arg0: String? = null 26 | 27 | override fun xmlParams(): Array = 28 | arrayOf( 29 | XMLParam("", "arg0", arg0, String::class), 30 | ) 31 | 32 | override fun readSOAPEnvelope(bodyElement: Element) { 33 | arg0 = readSOAPEnvelopeFieldNullable(bodyElement, "arg0", String::class) 34 | } 35 | } 36 | 37 | @Suppress("ktlint:standard:class-naming") 38 | class SampleService_echoStringResponse : XSDType() { 39 | @Suppress("ktlint:standard:property-naming") 40 | var `return`: String? = null 41 | 42 | override fun xmlParams(): Array = 43 | arrayOf( 44 | XMLParam("", "return", `return`, String::class), 45 | ) 46 | 47 | override fun readSOAPEnvelope(bodyElement: Element) { 48 | `return` = readSOAPEnvelopeFieldNullable(bodyElement, "return", String::class) 49 | } 50 | } 51 | 52 | class WSDLServiceStringTest { 53 | @Rule 54 | @JvmField 55 | var wireMockRule = WireMockRule(18080) 56 | 57 | @Before 58 | fun setup() { 59 | val responseBody = 60 | """ 61 | | 62 | | 63 | |test 64 | | 65 | """.trimMargin() 66 | 67 | stubFor( 68 | post(urlEqualTo("/service")) 69 | .willReturn( 70 | aResponse() 71 | .withHeader("Content-Type", "text/xml") 72 | .withBody(responseBody), 73 | ), 74 | ) 75 | } 76 | 77 | @Test 78 | fun testEchoString() { 79 | val params = SampleService_echoString() 80 | params.arg0 = "test" 81 | val response = SampleService().request(params) 82 | assertEquals("test", response.`return`) 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | @rem SPDX-License-Identifier: Apache-2.0 17 | @rem 18 | 19 | @if "%DEBUG%"=="" @echo off 20 | @rem ########################################################################## 21 | @rem 22 | @rem Gradle startup script for Windows 23 | @rem 24 | @rem ########################################################################## 25 | 26 | @rem Set local scope for the variables with windows NT shell 27 | if "%OS%"=="Windows_NT" setlocal 28 | 29 | set DIRNAME=%~dp0 30 | if "%DIRNAME%"=="" set DIRNAME=. 31 | @rem This is normally unused 32 | set APP_BASE_NAME=%~n0 33 | set APP_HOME=%DIRNAME% 34 | 35 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 36 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 37 | 38 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 39 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 40 | 41 | @rem Find java.exe 42 | if defined JAVA_HOME goto findJavaFromJavaHome 43 | 44 | set JAVA_EXE=java.exe 45 | %JAVA_EXE% -version >NUL 2>&1 46 | if %ERRORLEVEL% equ 0 goto execute 47 | 48 | echo. 1>&2 49 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 50 | echo. 1>&2 51 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 52 | echo location of your Java installation. 1>&2 53 | 54 | goto fail 55 | 56 | :findJavaFromJavaHome 57 | set JAVA_HOME=%JAVA_HOME:"=% 58 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 59 | 60 | if exist "%JAVA_EXE%" goto execute 61 | 62 | echo. 1>&2 63 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 64 | echo. 1>&2 65 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 66 | echo location of your Java installation. 1>&2 67 | 68 | goto fail 69 | 70 | :execute 71 | @rem Setup the command line 72 | 73 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 74 | 75 | 76 | @rem Execute Gradle 77 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 78 | 79 | :end 80 | @rem End local scope for the variables with windows NT shell 81 | if %ERRORLEVEL% equ 0 goto mainEnd 82 | 83 | :fail 84 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 85 | rem the _cmd.exe /c_ return code! 86 | set EXIT_CODE=%ERRORLEVEL% 87 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 88 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 89 | exit /b %EXIT_CODE% 90 | 91 | :mainEnd 92 | if "%OS%"=="Windows_NT" endlocal 93 | 94 | :omega 95 | -------------------------------------------------------------------------------- /wsdl2kotlin/src/main/kotlin/org/codefirst/wsdl2kotlin/WSDL.kt: -------------------------------------------------------------------------------- 1 | package org.codefirst.wsdl2kotlin 2 | 3 | import com.fasterxml.jackson.databind.DeserializationFeature 4 | import com.fasterxml.jackson.dataformat.xml.XmlMapper 5 | import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper 6 | import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty 7 | import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement 8 | import java.io.File 9 | import java.net.URI 10 | 11 | class SOAPAddress { 12 | @JacksonXmlProperty(isAttribute = true) 13 | var location: String = "" 14 | } 15 | 16 | class WSDLPort { 17 | var address: SOAPAddress? = null 18 | } 19 | 20 | class WSDLService { 21 | @JacksonXmlProperty(isAttribute = true) 22 | var name: String = "" 23 | 24 | @JacksonXmlElementWrapper(localName = "port", useWrapping = false) 25 | @JacksonXmlProperty(localName = "port") 26 | var ports = mutableListOf() 27 | } 28 | 29 | class WSDLInput { 30 | @JacksonXmlProperty(isAttribute = true) 31 | var message: String = "" 32 | } 33 | 34 | class WSDLOutput { 35 | @JacksonXmlProperty(isAttribute = true) 36 | var message: String = "" 37 | } 38 | 39 | class WSDLOperation { 40 | lateinit var input: WSDLInput 41 | 42 | lateinit var output: WSDLOutput 43 | } 44 | 45 | class WSDLPortType { 46 | @JacksonXmlElementWrapper(localName = "operation", useWrapping = false) 47 | @JacksonXmlProperty(localName = "operation") 48 | var operations: MutableList = mutableListOf() 49 | } 50 | 51 | class WSDLTypes { 52 | lateinit var schema: XSDSchema 53 | } 54 | 55 | class WSDLPart { 56 | @JacksonXmlProperty(isAttribute = true) 57 | var element: String? = null 58 | } 59 | 60 | class WSDLMessage { 61 | @JacksonXmlProperty(isAttribute = true) 62 | var name: String = "" 63 | 64 | lateinit var part: WSDLPart 65 | } 66 | 67 | @JacksonXmlRootElement(localName = "definitions") 68 | class WSDLDefinitions { 69 | lateinit var service: WSDLService 70 | 71 | @JacksonXmlElementWrapper(localName = "message", useWrapping = false) 72 | @JacksonXmlProperty(localName = "message") 73 | var messages: MutableList = mutableListOf() 74 | 75 | @JacksonXmlElementWrapper(localName = "portType", useWrapping = false) 76 | @JacksonXmlProperty(localName = "portType") 77 | var portTypes: MutableList = mutableListOf() 78 | 79 | @JacksonXmlProperty(isAttribute = true) 80 | var targetNamespace: String = "" 81 | 82 | lateinit var types: WSDLTypes 83 | 84 | fun findType(message: String): String? { 85 | val name = message.removePrefix("tns:") 86 | val part = messages.first { it.name == name }.part 87 | 88 | if (part.element == null) { 89 | return null 90 | } 91 | 92 | val elementName = part.element?.removePrefix("tns:") 93 | if (!types.schema.elements.any { it.name == elementName }) { 94 | return null 95 | } 96 | 97 | return "${service.name}_$elementName" 98 | } 99 | 100 | val packageName: String 101 | get() = 102 | URI(targetNamespace) 103 | .host 104 | .split('.') 105 | .reversed() 106 | .joinToString(".") 107 | } 108 | 109 | class WSDL { 110 | companion object { 111 | fun parse(path: String): WSDLDefinitions { 112 | val xmlMapper = XmlMapper() 113 | xmlMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) 114 | return xmlMapper.readValue(File(path), WSDLDefinitions::class.java) 115 | } 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /wsdl2kotlin/src/main/kotlin/org/codefirst/wsdl2kotlin/WSDL2Kotlin.kt: -------------------------------------------------------------------------------- 1 | package org.codefirst.wsdl2kotlin 2 | 3 | class WSDL2Kotlin { 4 | fun run(vararg paths: String): Array { 5 | val wsdls = mutableListOf() 6 | paths.forEach { 7 | if (XSD.isXSD(it)) { 8 | val xsd = XSD.parse(it) 9 | wsdls 10 | .last() 11 | .types.schema.elements 12 | .addAll(xsd.elements) 13 | wsdls 14 | .last() 15 | .types.schema.complexTypes 16 | .addAll(xsd.complexTypes) 17 | } else { 18 | wsdls.add(WSDL.parse(it)) 19 | } 20 | } 21 | 22 | return wsdls 23 | .map { 24 | generateOutput(it) 25 | }.toTypedArray() 26 | } 27 | 28 | private fun generateOutput(wsdl: WSDLDefinitions): Output { 29 | var kotlin = 30 | """package ${wsdl.packageName} 31 | """.trimEnd(' ') 32 | 33 | kotlin += 34 | """ 35 | import org.codefirst.wsdl2kotlin.WSDLService 36 | import org.codefirst.wsdl2kotlin.XMLParam 37 | import org.codefirst.wsdl2kotlin.XSDType 38 | import org.w3c.dom.Element 39 | """.trimEnd(' ') 40 | 41 | val location = 42 | wsdl.service.ports 43 | .first { it.address != null } 44 | .address 45 | ?.location 46 | val endpoint = location?.substringBeforeLast("/") 47 | val path = location?.substringAfterLast("/") 48 | 49 | kotlin += 50 | """ 51 | class ${wsdl.service.name} : WSDLService() { 52 | override val targetNamespace = "${wsdl.targetNamespace}" 53 | override var endpoint = "$endpoint" 54 | override var path = "$path" 55 | """.trimEnd(' ') 56 | wsdl.portTypes.forEach { portType -> 57 | portType.operations.forEach { operation -> 58 | val inputType = wsdl.findType(operation.input.message) 59 | val outputType = wsdl.findType(operation.output.message) 60 | if (inputType != null && outputType != null) { 61 | kotlin += 62 | """ 63 | fun request(parameters: $inputType): $outputType { 64 | return requestGeneric<$inputType, $outputType>(parameters) 65 | } 66 | """.trimEnd(' ') 67 | } 68 | } 69 | } 70 | 71 | kotlin += 72 | """ 73 | } 74 | """.trimEnd(' ') 75 | wsdl.types.schema.complexTypes.forEach { complexType -> 76 | kotlin += generateType(complexType.name ?: "", wsdl, complexType, "") 77 | } 78 | 79 | wsdl.types.schema.elements.filter { it.complexType != null }.forEach { element -> 80 | kotlin += generateType(element.name, wsdl, element.complexType, "tns") 81 | } 82 | 83 | return Output(wsdl.service.name, wsdl.packageName, kotlin) 84 | } 85 | 86 | private fun generateType( 87 | name: String, 88 | wsdl: WSDLDefinitions, 89 | complexType: XSDComplexType?, 90 | namespace: String, 91 | ): String { 92 | var kotlin = "" 93 | 94 | val subClassSequence = complexType?.complexContent?.extension?.sequence 95 | if (subClassSequence != null) { 96 | complexType.sequence = subClassSequence 97 | } 98 | 99 | complexType?.sequence?.elements?.filter { it.type == null }?.forEach { 100 | it.complexType?.name = "${complexType.name}_${it.name}" 101 | kotlin += generateType("${name}_${it.name}", wsdl, it.complexType, namespace) 102 | } 103 | 104 | val classDecorator = 105 | if (complexType?.isFinal == true) { 106 | "" 107 | } else { 108 | "open " 109 | } 110 | kotlin += 111 | """${classDecorator}class ${wsdl.service.name}_$name : ${complexType?.baseTypeInKotlin(wsdl.service) ?: "XSDType"}() { 112 | """.trimEnd() 113 | complexType?.sequence?.elements?.forEach { 114 | kotlin += 115 | """ 116 | var ${it.safeName}: ${it.typeInKotlin(wsdl.service, complexType)} = ${it.initialValue(wsdl.service, complexType)} 117 | """.trimEnd() 118 | } 119 | 120 | kotlin += 121 | """ 122 | 123 | override fun xmlParams(): Array { 124 | return ${if (complexType?.isExtended == true) { 125 | "super.xmlParams() + " 126 | } else { 127 | "" 128 | }}arrayOf( 129 | """.trimEnd() 130 | complexType?.sequence?.elements?.forEach { 131 | kotlin += 132 | """ 133 | XMLParam("$namespace", "${it.name}", ${it.safeName}, ${it.kclassInKotlin(wsdl.service, complexType)}), 134 | """.trimEnd() 135 | } 136 | kotlin += 137 | """ 138 | ) 139 | } 140 | 141 | override fun readSOAPEnvelope(bodyElement: Element) { 142 | """.trimEnd() 143 | if (complexType?.isExtended == true) { 144 | kotlin += 145 | """ 146 | super.readSOAPEnvelope(bodyElement) 147 | """.trimEnd() 148 | } 149 | complexType?.sequence?.elements?.forEach { 150 | kotlin += 151 | """ 152 | ${it.safeName} = ${it.readMethod()}(bodyElement, "${it.name}", ${it.kclassInKotlin(wsdl.service, complexType)}) 153 | """.trimEnd() 154 | } 155 | kotlin += 156 | """ 157 | } 158 | } 159 | """.trimEnd(' ') 160 | return kotlin 161 | } 162 | } 163 | -------------------------------------------------------------------------------- /wsdl2kotlin/src/main/kotlin/org/codefirst/wsdl2kotlin/XSD.kt: -------------------------------------------------------------------------------- 1 | package org.codefirst.wsdl2kotlin 2 | 3 | import com.fasterxml.jackson.databind.DeserializationFeature 4 | import com.fasterxml.jackson.dataformat.xml.XmlMapper 5 | import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper 6 | import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty 7 | import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement 8 | import java.io.File 9 | 10 | class XSDSequence { 11 | @JacksonXmlElementWrapper(localName = "element", useWrapping = false) 12 | @JacksonXmlProperty(localName = "element") 13 | var elements: MutableList = mutableListOf() 14 | } 15 | 16 | class XSDExtension { 17 | @JacksonXmlProperty(isAttribute = true) 18 | var base: String = "" 19 | 20 | var sequence: XSDSequence? = null 21 | } 22 | 23 | class XSDComplexContent { 24 | var extension: XSDExtension? = null 25 | } 26 | 27 | class XSDComplexType { 28 | @JacksonXmlProperty(isAttribute = true) 29 | var name: String? = null 30 | 31 | var sequence: XSDSequence? = null 32 | 33 | var complexContent: XSDComplexContent? = null 34 | 35 | @JacksonXmlProperty(isAttribute = true) 36 | var final: String? = null 37 | 38 | val isFinal: Boolean 39 | get() = !final.isNullOrEmpty() 40 | 41 | val isExtended: Boolean 42 | get() = this.complexContent?.extension?.base != null 43 | 44 | fun baseTypeInKotlin(service: WSDLService): String? { 45 | if (!isExtended) { 46 | return null 47 | } 48 | return TypeResolver.baseTypeInKotlin("", this.complexContent?.extension?.base, service, this) 49 | } 50 | } 51 | 52 | class XSDElement { 53 | var complexType: XSDComplexType? = null 54 | 55 | @JacksonXmlProperty(isAttribute = true) 56 | var name: String = "" 57 | 58 | @JacksonXmlProperty(isAttribute = true) 59 | var type: String? = null 60 | 61 | @JacksonXmlProperty(isAttribute = true) 62 | var minOccurs: Int? = null 63 | 64 | @JacksonXmlProperty(isAttribute = true) 65 | var maxOccurs: String? = null 66 | 67 | val safeName: String 68 | get() { 69 | // https://kotlinlang.org/docs/keyword-reference.html#soft-keywords 70 | val keywords = arrayListOf("return", "operator", "var", "val", "out") 71 | if (keywords.contains(name)) { 72 | return "`$name`" 73 | } 74 | return name 75 | } 76 | 77 | fun typeInKotlin( 78 | service: WSDLService, 79 | parentType: XSDComplexType?, 80 | ): String { 81 | val kotlinTypeName = baseTypeInKotlin(service, parentType) 82 | 83 | if (maxOccurs == "unbounded") { 84 | return "Array<$kotlinTypeName>?" 85 | } 86 | if (minOccurs == 0) { 87 | return "$kotlinTypeName?" 88 | } 89 | 90 | return kotlinTypeName 91 | } 92 | 93 | private fun isNullable(): Boolean = maxOccurs == "unbounded" || minOccurs == 0 94 | 95 | fun readMethod(): String = 96 | if (isNullable()) { 97 | "readSOAPEnvelopeFieldNullable" 98 | } else { 99 | "readSOAPEnvelopeField" 100 | } 101 | 102 | fun kclassInKotlin( 103 | service: WSDLService, 104 | parentType: XSDComplexType?, 105 | ): String { 106 | val kotlinTypeName = baseTypeInKotlin(service, parentType) 107 | 108 | if (maxOccurs == "unbounded") { 109 | return "Array<$kotlinTypeName>::class" 110 | } 111 | 112 | return "$kotlinTypeName::class" 113 | } 114 | 115 | fun initialValue( 116 | service: WSDLService, 117 | parentType: XSDComplexType?, 118 | ): String { 119 | val kotlinTypeName = baseTypeInKotlin(service, parentType) 120 | 121 | if (maxOccurs == "unbounded") { 122 | return "emptyArray<$kotlinTypeName>()" 123 | } 124 | 125 | if (minOccurs == 0) { 126 | return "null" 127 | } 128 | 129 | return when (kotlinTypeName) { 130 | "String" -> "\"\"" 131 | "Boolean" -> "false" 132 | "Byte" -> "0" 133 | "Int" -> "0" 134 | "Float" -> "0F" 135 | "Long" -> "0L" 136 | "Date" -> "java.util.Date()" 137 | "ByteArray" -> "ByteArray(0)" 138 | else -> "$kotlinTypeName()" 139 | } 140 | } 141 | 142 | private fun baseTypeInKotlin( 143 | service: WSDLService, 144 | parentType: XSDComplexType?, 145 | ): String = TypeResolver.baseTypeInKotlin(this.name, this.type, service, parentType) 146 | } 147 | 148 | private class TypeResolver { 149 | companion object { 150 | fun baseTypeInKotlin( 151 | name: String, 152 | type: String?, 153 | service: WSDLService, 154 | parentType: XSDComplexType?, 155 | ): String { 156 | if (type == null) { 157 | return service.name + "_" + parentType?.name + "_" + name 158 | } 159 | 160 | if (type.startsWith("tns:")) { 161 | return service.name + "_" + type.removePrefix("tns:") 162 | } 163 | 164 | return when (type.substringAfterLast(":")) { 165 | "string" -> "String" 166 | "boolean" -> "Boolean" 167 | "byte" -> "Byte" 168 | "int" -> "Int" 169 | "float" -> "Float" 170 | "long" -> "Long" 171 | "dateTime" -> "java.util.Date" 172 | "base64Binary" -> "ByteArray" 173 | else -> "" 174 | } 175 | } 176 | } 177 | } 178 | 179 | @JacksonXmlRootElement(localName = "schema") 180 | class XSDSchema { 181 | @JacksonXmlElementWrapper(localName = "element", useWrapping = false) 182 | @JacksonXmlProperty(localName = "element") 183 | var elements: MutableList = mutableListOf() 184 | set(value) { 185 | // workaround for https://github.com/FasterXML/jackson-dataformat-xml/issues/275 186 | elements.addAll(value) 187 | } 188 | 189 | @JacksonXmlElementWrapper(localName = "complexType", useWrapping = false) 190 | @JacksonXmlProperty(localName = "complexType") 191 | var complexTypes: MutableList = mutableListOf() 192 | set(value) { 193 | // workaround for https://github.com/FasterXML/jackson-dataformat-xml/issues/275 194 | complexTypes.addAll(value) 195 | } 196 | } 197 | 198 | class XSD { 199 | companion object { 200 | fun parse(path: String): XSDSchema { 201 | val xmlMapper = XmlMapper() 202 | xmlMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) 203 | return xmlMapper.readValue(File(path), XSDSchema::class.java) 204 | } 205 | 206 | fun isXSD(path: String): Boolean { 207 | val xsd = parse(path) 208 | return xsd.elements.any() 209 | } 210 | } 211 | } 212 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # 4 | # Copyright © 2015-2021 the original authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | # SPDX-License-Identifier: Apache-2.0 19 | # 20 | 21 | ############################################################################## 22 | # 23 | # Gradle start up script for POSIX generated by Gradle. 24 | # 25 | # Important for running: 26 | # 27 | # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is 28 | # noncompliant, but you have some other compliant shell such as ksh or 29 | # bash, then to run this script, type that shell name before the whole 30 | # command line, like: 31 | # 32 | # ksh Gradle 33 | # 34 | # Busybox and similar reduced shells will NOT work, because this script 35 | # requires all of these POSIX shell features: 36 | # * functions; 37 | # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», 38 | # «${var#prefix}», «${var%suffix}», and «$( cmd )»; 39 | # * compound commands having a testable exit status, especially «case»; 40 | # * various built-in commands including «command», «set», and «ulimit». 41 | # 42 | # Important for patching: 43 | # 44 | # (2) This script targets any POSIX shell, so it avoids extensions provided 45 | # by Bash, Ksh, etc; in particular arrays are avoided. 46 | # 47 | # The "traditional" practice of packing multiple parameters into a 48 | # space-separated string is a well documented source of bugs and security 49 | # problems, so this is (mostly) avoided, by progressively accumulating 50 | # options in "$@", and eventually passing that to Java. 51 | # 52 | # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, 53 | # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; 54 | # see the in-line comments for details. 55 | # 56 | # There are tweaks for specific operating systems such as AIX, CygWin, 57 | # Darwin, MinGW, and NonStop. 58 | # 59 | # (3) This script is generated from the Groovy template 60 | # https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt 61 | # within the Gradle project. 62 | # 63 | # You can find Gradle at https://github.com/gradle/gradle/. 64 | # 65 | ############################################################################## 66 | 67 | # Attempt to set APP_HOME 68 | 69 | # Resolve links: $0 may be a link 70 | app_path=$0 71 | 72 | # Need this for daisy-chained symlinks. 73 | while 74 | APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path 75 | [ -h "$app_path" ] 76 | do 77 | ls=$( ls -ld "$app_path" ) 78 | link=${ls#*' -> '} 79 | case $link in #( 80 | /*) app_path=$link ;; #( 81 | *) app_path=$APP_HOME$link ;; 82 | esac 83 | done 84 | 85 | # This is normally unused 86 | # shellcheck disable=SC2034 87 | APP_BASE_NAME=${0##*/} 88 | # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) 89 | APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s 90 | ' "$PWD" ) || exit 91 | 92 | # Use the maximum available, or set MAX_FD != -1 to use that value. 93 | MAX_FD=maximum 94 | 95 | warn () { 96 | echo "$*" 97 | } >&2 98 | 99 | die () { 100 | echo 101 | echo "$*" 102 | echo 103 | exit 1 104 | } >&2 105 | 106 | # OS specific support (must be 'true' or 'false'). 107 | cygwin=false 108 | msys=false 109 | darwin=false 110 | nonstop=false 111 | case "$( uname )" in #( 112 | CYGWIN* ) cygwin=true ;; #( 113 | Darwin* ) darwin=true ;; #( 114 | MSYS* | MINGW* ) msys=true ;; #( 115 | NONSTOP* ) nonstop=true ;; 116 | esac 117 | 118 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 119 | 120 | 121 | # Determine the Java command to use to start the JVM. 122 | if [ -n "$JAVA_HOME" ] ; then 123 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 124 | # IBM's JDK on AIX uses strange locations for the executables 125 | JAVACMD=$JAVA_HOME/jre/sh/java 126 | else 127 | JAVACMD=$JAVA_HOME/bin/java 128 | fi 129 | if [ ! -x "$JAVACMD" ] ; then 130 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 131 | 132 | Please set the JAVA_HOME variable in your environment to match the 133 | location of your Java installation." 134 | fi 135 | else 136 | JAVACMD=java 137 | if ! command -v java >/dev/null 2>&1 138 | then 139 | die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 140 | 141 | Please set the JAVA_HOME variable in your environment to match the 142 | location of your Java installation." 143 | fi 144 | fi 145 | 146 | # Increase the maximum file descriptors if we can. 147 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then 148 | case $MAX_FD in #( 149 | max*) 150 | # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. 151 | # shellcheck disable=SC2039,SC3045 152 | MAX_FD=$( ulimit -H -n ) || 153 | warn "Could not query maximum file descriptor limit" 154 | esac 155 | case $MAX_FD in #( 156 | '' | soft) :;; #( 157 | *) 158 | # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. 159 | # shellcheck disable=SC2039,SC3045 160 | ulimit -n "$MAX_FD" || 161 | warn "Could not set maximum file descriptor limit to $MAX_FD" 162 | esac 163 | fi 164 | 165 | # Collect all arguments for the java command, stacking in reverse order: 166 | # * args from the command line 167 | # * the main class name 168 | # * -classpath 169 | # * -D...appname settings 170 | # * --module-path (only if needed) 171 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. 172 | 173 | # For Cygwin or MSYS, switch paths to Windows format before running java 174 | if "$cygwin" || "$msys" ; then 175 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) 176 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) 177 | 178 | JAVACMD=$( cygpath --unix "$JAVACMD" ) 179 | 180 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 181 | for arg do 182 | if 183 | case $arg in #( 184 | -*) false ;; # don't mess with options #( 185 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath 186 | [ -e "$t" ] ;; #( 187 | *) false ;; 188 | esac 189 | then 190 | arg=$( cygpath --path --ignore --mixed "$arg" ) 191 | fi 192 | # Roll the args list around exactly as many times as the number of 193 | # args, so each arg winds up back in the position where it started, but 194 | # possibly modified. 195 | # 196 | # NB: a `for` loop captures its iteration list before it begins, so 197 | # changing the positional parameters here affects neither the number of 198 | # iterations, nor the values presented in `arg`. 199 | shift # remove old arg 200 | set -- "$@" "$arg" # push replacement arg 201 | done 202 | fi 203 | 204 | 205 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 206 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 207 | 208 | # Collect all arguments for the java command: 209 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, 210 | # and any embedded shellness will be escaped. 211 | # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be 212 | # treated as '${Hostname}' itself on the command line. 213 | 214 | set -- \ 215 | "-Dorg.gradle.appname=$APP_BASE_NAME" \ 216 | -classpath "$CLASSPATH" \ 217 | org.gradle.wrapper.GradleWrapperMain \ 218 | "$@" 219 | 220 | # Stop when "xargs" is not available. 221 | if ! command -v xargs >/dev/null 2>&1 222 | then 223 | die "xargs is not available" 224 | fi 225 | 226 | # Use "xargs" to parse quoted args. 227 | # 228 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed. 229 | # 230 | # In Bash we could simply go: 231 | # 232 | # readarray ARGS < <( xargs -n1 <<<"$var" ) && 233 | # set -- "${ARGS[@]}" "$@" 234 | # 235 | # but POSIX shell has neither arrays nor command substitution, so instead we 236 | # post-process each arg (as a line of input to sed) to backslash-escape any 237 | # character that might be a shell metacharacter, then use eval to reverse 238 | # that process (while maintaining the separation between arguments), and wrap 239 | # the whole thing up as a single "set" statement. 240 | # 241 | # This will of course break if any of these variables contains a newline or 242 | # an unmatched quote. 243 | # 244 | 245 | eval "set -- $( 246 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | 247 | xargs -n1 | 248 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | 249 | tr '\n' ' ' 250 | )" '"$@"' 251 | 252 | exec "$JAVACMD" "$@" 253 | -------------------------------------------------------------------------------- /wsdl2kotlin-runtime/src/main/kotlin/org/codefirst/wsdl2kotlin/WSDLService.kt: -------------------------------------------------------------------------------- 1 | package org.codefirst.wsdl2kotlin 2 | 3 | import okhttp3.Interceptor 4 | import okhttp3.MediaType.Companion.toMediaTypeOrNull 5 | import okhttp3.OkHttpClient 6 | import okhttp3.Request 7 | import okhttp3.RequestBody 8 | import okio.BufferedSink 9 | import org.w3c.dom.Document 10 | import org.w3c.dom.Element 11 | import org.w3c.dom.Node 12 | import java.text.SimpleDateFormat 13 | import javax.xml.parsers.DocumentBuilder 14 | import javax.xml.parsers.DocumentBuilderFactory 15 | import javax.xml.transform.OutputKeys 16 | import javax.xml.transform.Transformer 17 | import javax.xml.transform.TransformerFactory 18 | import javax.xml.transform.dom.DOMSource 19 | import javax.xml.transform.stream.StreamResult 20 | import kotlin.reflect.KClass 21 | import kotlin.reflect.KMutableProperty 22 | import kotlin.reflect.full.memberProperties 23 | 24 | data class XMLParam( 25 | val namespace: String, 26 | val name: String, 27 | val value: Any?, 28 | val clazz: KClass<*>, 29 | ) 30 | 31 | class SOAPFaultException( 32 | faultString: String, 33 | ) : RuntimeException(faultString) 34 | 35 | const val DATETIME_FORMAT = "yyyy-MM-dd'T'HH:mm:ssX:00" 36 | 37 | class DocumentHelper { 38 | companion object { 39 | fun newDocumentBuilder(): DocumentBuilder = 40 | DocumentBuilderFactory 41 | .newInstance() 42 | .apply { 43 | this.isNamespaceAware = true 44 | }.newDocumentBuilder() 45 | 46 | fun newTransformer(): Transformer = 47 | TransformerFactory.newInstance().newTransformer().apply { 48 | this.setOutputProperty(OutputKeys.INDENT, "yes") 49 | } 50 | 51 | fun getChildElementsByTagName( 52 | parentElement: Element, 53 | tagName: String, 54 | ): List { 55 | val items = parentElement.childNodes 56 | val nodes = mutableListOf() 57 | for (i in 0 until items.length) { 58 | val item = items.item(i) 59 | if (item.localName == tagName) { 60 | nodes.add(item as Element) 61 | } 62 | } 63 | return nodes 64 | } 65 | } 66 | } 67 | 68 | abstract class XSDType { 69 | abstract fun xmlParams(): Array 70 | 71 | fun soapRequest(tns: String): Document { 72 | val document = DocumentHelper.newDocumentBuilder().newDocument() 73 | 74 | val envelopeElement = document.createElement("S:Envelope") 75 | envelopeElement.setAttribute("xmlns:S", "http://schemas.xmlsoap.org/soap/envelope/") 76 | envelopeElement.setAttribute("xmlns:tns", tns) 77 | document.appendChild(envelopeElement) 78 | 79 | val headerElement = document.createElement("S:Header") 80 | envelopeElement.appendChild(headerElement) 81 | 82 | val bodyElement = document.createElement("S:Body") 83 | envelopeElement.appendChild(bodyElement) 84 | 85 | xmlElements("tns:${this.javaClass.simpleName.split('_').last()}", document) 86 | .forEach { bodyElement.appendChild(it) } 87 | 88 | return document 89 | } 90 | 91 | private fun xmlElements( 92 | name: String, 93 | document: Document, 94 | ): Array { 95 | val typeElement = document.createElement(name) 96 | 97 | xmlParams().forEach { param -> 98 | val name = 99 | if (param.namespace.isBlank()) { 100 | param.name 101 | } else { 102 | "${param.namespace}:${param.name}" 103 | } 104 | xmlElements(param.value, name, document).forEach { 105 | typeElement.appendChild(it) 106 | } 107 | } 108 | 109 | return arrayOf(typeElement) 110 | } 111 | 112 | private fun xmlElements( 113 | value: Any?, 114 | name: String, 115 | document: Document, 116 | ): Array { 117 | val element = document.createElement(name) 118 | when (value) { 119 | is java.util.Date -> { 120 | element.textContent = SimpleDateFormat(DATETIME_FORMAT).format(value) 121 | } 122 | 123 | is ByteArray -> { 124 | element.textContent = 125 | java.util.Base64 126 | .getEncoder() 127 | .encodeToString(value) 128 | } 129 | 130 | is Array<*> -> { 131 | return value.map { xmlElements(it, name, document).first() }.toTypedArray() 132 | } 133 | 134 | is XSDType -> { 135 | value.xmlParams().forEach { param -> 136 | xmlElements(param.value, param.name, document).forEach { childElement -> 137 | element.appendChild(childElement) 138 | } 139 | } 140 | } 141 | 142 | null -> { 143 | return arrayOf() 144 | } 145 | 146 | else -> { 147 | element.textContent = value.toString() 148 | } 149 | } 150 | 151 | return arrayOf(element) 152 | } 153 | 154 | abstract fun readSOAPEnvelope(bodyElement: Element) 155 | 156 | protected fun readSOAPEnvelopeField( 157 | parentElement: Element, 158 | tagName: String, 159 | clazz: KClass, 160 | ): T = readSOAPEnvelopeFieldNullable(parentElement, tagName, clazz)!! 161 | 162 | private fun isSingleType(clazz: KClass): Boolean = 163 | when (clazz) { 164 | String::class, Boolean::class, Int::class, Float::class, Long::class, java.util.Date::class, ByteArray::class -> true 165 | else -> false 166 | } 167 | 168 | protected fun readSOAPEnvelopeFieldNullable( 169 | parentElement: Element, 170 | tagName: String, 171 | clazz: KClass, 172 | ): T? { 173 | val items = DocumentHelper.getChildElementsByTagName(parentElement, tagName) 174 | if (items.isEmpty()) { 175 | return null 176 | } 177 | 178 | if (isSingleType(clazz)) { 179 | return singleNodeToObject(items.first(), clazz) 180 | } 181 | 182 | if (clazz != ByteArray::class && clazz.java.isArray) { 183 | val k = clazz.java.componentType.kotlin 184 | 185 | if (isSingleType(k)) { 186 | val array = items.map { singleNodeToObject(it, k) }.toTypedArray() 187 | return when (k) { 188 | String::class -> array.map { it as String }.toTypedArray() 189 | Boolean::class -> array.map { it as Boolean }.toTypedArray() 190 | Int::class -> array.map { it as Int }.toTypedArray() 191 | Float::class -> array.map { it as Float }.toTypedArray() 192 | Long::class -> array.map { it as Long }.toTypedArray() 193 | java.util.Date::class -> array.map { it as java.util.Date }.toTypedArray() 194 | ByteArray::class -> array.map { it as ByteArray }.toTypedArray() 195 | else -> array 196 | } as T 197 | } 198 | 199 | val arr = 200 | java.lang.reflect.Array 201 | .newInstance(k.java, items.size) 202 | items.forEachIndexed { i, item -> 203 | java.lang.reflect.Array 204 | .set(arr, i, singleNodeToObject(item, k)) 205 | } 206 | return arr as T 207 | } 208 | 209 | val t = 210 | clazz.java.newInstance() as? XSDType 211 | ?: throw NotImplementedError("Unsupported type: ${clazz.simpleName}") 212 | val properties = t.javaClass.kotlin.memberProperties 213 | 214 | val item = items.first() 215 | 216 | properties.filterIsInstance>().forEach { p -> 217 | val param = t.xmlParams().first { p.name == it.name } 218 | 219 | val v = readSOAPEnvelopeFieldNullable(item, param.name, param.clazz) 220 | 221 | p.setter.call(t, v) 222 | } 223 | 224 | return t as T 225 | } 226 | 227 | private fun singleNodeToObject( 228 | item: Node, 229 | clazz: KClass, 230 | ): T { 231 | return when (clazz) { 232 | String::class -> { 233 | item.textContent 234 | } 235 | 236 | Boolean::class -> { 237 | item.textContent.equals("true", ignoreCase = true) 238 | } 239 | 240 | Int::class -> { 241 | item.textContent.toInt() 242 | } 243 | 244 | Float::class -> { 245 | item.textContent.toFloat() 246 | } 247 | 248 | Long::class -> { 249 | item.textContent.toLong() 250 | } 251 | 252 | java.util.Date::class -> { 253 | SimpleDateFormat(DATETIME_FORMAT).parse(item.textContent) 254 | } 255 | 256 | ByteArray::class -> { 257 | java.util.Base64 258 | .getDecoder() 259 | .decode(item.textContent) 260 | } 261 | 262 | else -> { 263 | val t = 264 | clazz.java.newInstance() as? XSDType 265 | ?: throw NotImplementedError("Unsupported type: ${clazz.simpleName}") 266 | t.readSOAPEnvelope(item as Element) 267 | return t as T 268 | } 269 | } as T 270 | } 271 | } 272 | 273 | abstract class WSDLService { 274 | abstract val targetNamespace: String 275 | abstract var endpoint: String 276 | abstract var path: String 277 | 278 | protected val interceptors = mutableListOf() 279 | 280 | protected val requestUrl: String 281 | get() = endpoint.removeSuffix("/") + "/" + path.removePrefix("/") 282 | 283 | protected inline fun requestGeneric(i: I): O { 284 | val soapRequest = i.soapRequest(targetNamespace) 285 | 286 | val requestBody = 287 | object : RequestBody() { 288 | override fun contentType() = "text/xml".toMediaTypeOrNull() 289 | 290 | override fun writeTo(sink: BufferedSink) { 291 | DocumentHelper.newTransformer().transform( 292 | DOMSource(soapRequest), 293 | StreamResult(FixSurrogatePairOutputStream(sink.outputStream())), 294 | ) 295 | } 296 | } 297 | 298 | val request = 299 | Request 300 | .Builder() 301 | .url(requestUrl) 302 | .post(requestBody) 303 | .build() 304 | val client = 305 | OkHttpClient 306 | .Builder() 307 | .also { builder -> 308 | interceptors.forEach { 309 | builder.addInterceptor(it) 310 | } 311 | }.build() 312 | val response = client.newCall(request).execute() 313 | 314 | val document = DocumentHelper.newDocumentBuilder().parse(response.body?.byteStream()) 315 | val bodyElement = DocumentHelper.getChildElementsByTagName(document.documentElement, "Body").first() 316 | 317 | val fault = DocumentHelper.getChildElementsByTagName(bodyElement, "Fault").firstOrNull() 318 | if (fault != null) { 319 | val faultString = fault.getElementsByTagName("faultstring").item(0).textContent 320 | throw SOAPFaultException(faultString) 321 | } 322 | 323 | val o = O::class.java.newInstance() 324 | o.readSOAPEnvelope(bodyElement.firstChild as Element) 325 | return o 326 | } 327 | 328 | fun addInterceptor(interceptor: Interceptor) { 329 | interceptors.add(interceptor) 330 | } 331 | } 332 | -------------------------------------------------------------------------------- /wsdl2kotlin/src/test/resources/sample.xsd.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | -------------------------------------------------------------------------------- /wsdl2kotlin/src/test/resources/sample.wsdl.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | --------------------------------------------------------------------------------