Java11でSOAP使いたいと言われた人に送る記事

# Java11のSOAPについて

JEP 320に従い、SOAP関連の資材がJavaSEから削除されました。(JakartaEEにお引越しするのかな?)
そのため、以下のコマンドが廃止されています。

1. wsimport ・・・ WSDL情報を元に、クライアント資材を生成(インターフェイス、DTO)
1. wsgen    ・・・ 実装からWSDLを生成

SOAPサーバを新規に構築することはないと思いますが、業務システムだと、まだまだSOAPの受信は必要です。

削除されたのは、理由があるので仕方がないのですが、Java11でどうすれば良いのか、私はすごく困りました。
私と同じように困る人もいるので、問題解決の助力となるようにメモを残します。

## Maven Pluginを利用したwsimprtの実行

wsimportがJavaSEから削除されましたが、jarはMaven Centralから取得することができます。
そのため、以下のdependencyを追加します。

```
<dependency>
    <groupId>com.sun.tools.ws</groupId>
    <artifactId>webservices-tools</artifactId>
    <version>1.6</version>
</dependency>
```

あとは、com.sun.tools.ws.WsImportをMaven Pluginの助けを借りて実行するだけです。
オプションについては、Java8などのwsimportのドキュメントを確認し、適時書き換えてください。

mvn installを実行すると、必要なインターフェイス、DTOが生成されます。

```pom.xml
			<plugin>
				<groupId>org.codehaus.mojo</groupId>
				<artifactId>exec-maven-plugin</artifactId>
				<executions>
					<execution>
						<id>ws-generate-from-wsdl</id>
						<phase>generate-sources</phase>
						<goals>
							<goal>exec</goal>
						</goals>
						<configuration>
							<executable>java</executable>
							<addOutputToClasspath>true</addOutputToClasspath>
							<longModulepath>false</longModulepath>
							<arguments>
　　　　　　　　　　　　　        <!-- WindowsだとコメントがSJISになってしまうため、文字コードを指定 -->
								<argument>-Dfile.encoding=UTF-8</argument>
								<argument>-Dsun.jnu.encoding=UTF-8</argument>
								<argument>-verbose</argument>
								<argument>-classpath</argument>
								<classpath/>
								<argument>com.sun.tools.ws.WsImport</argument>
								<argument>-extension</argument>
								<argument>-Xnocompile</argument>
								<argument>-d</argument>
								<argument>${project.basedir}/src/main/java</argument>
								<argument>-p</argument>
								<argument>jp.co.hoge.soap.hello</argument>
								<argument>${project.basedir}/src/main/resources/wsdl/HelloSoapService.wsdl</argument>
							</arguments>
						</configuration>
					</execution>
				</executions>
			</plugin>
			<plugin>
				<groupId>org.codehaus.mojo</groupId>
				<artifactId>build-helper-maven-plugin</artifactId>
				<version>3.0.0</version>
				<executions>
					<execution>
						<id>add-source</id>
						<phase>generate-sources</phase>
						<goals>
							<goal>add-source</goal>
						</goals>
						<configuration>
							<sources>
								<source>${project.basedir}/src/main/java</source>
							</sources>
						</configuration>
					</execution>
				</executions>
			</plugin>

```
build-helper-maven-pluginは、コードの生成されたことをIDEに知らせるPluginになります。
IDEはファイルシステムと非同期となっているためです。

いちいちコマンドで実行するより、むしろあるべき姿になったきもしますね:grinning:

## Spring JaxWebProxy を使用したSOAP通信

必要な資材が生成され、めでたしめでたし、、、としたいのですが、
Java EE のコードを書くのはつらいです。(主観ですが)

調べてみると、Spring JaxWebProxyというのがあるのですが、
XMLで記載するサンプルばかりで、環境別にURLを切替できなくて不便だなと感じました。

戻り値がObjectなのが、かなりイケてないですが、
以下の感じでJaxWsPortProxyFactoryBeanの力を借りて、SOAPのClientをインスタンス化します。

```
@Configuration
public class HelloWebServiceConfig {

	/**
	 * HelloWebServiceProxyのインスタンスを生成する
	 *
	 * @param wsdlUrl http://localhost:8080/axis2/services?wsdl
	 * @return Object JaxWsPortProxyFactoryBean
	 * @throws MalformedURLException
	 */
	@Bean
	public Object createHelloWebServiceProxyInstance(String wsdlUrl)  {

		JaxWsPortProxyFactoryBean bean = new JaxWsPortProxyFactoryBean();

		bean.setServiceInterface(HelloWebService.class);
		bean.setServiceName("helloWebService"); // WSDLに記載されているサービス名と同じものを記載する。省略不可。
		try {
			bean.setWsdlDocumentUrl(new URL(wsdlUrl));
		} catch (MalformedURLException e) {
			e.printStackTrace();
		}

		return bean;
	}
}
```

実際にSOAPを実行する場合のサンプルは下記のとおりです。

```
// SOAP Clientのインスタンス化
ApplicationContext ctx = new AnnotationConfigApplicationContext(HelloWebServiceConfig.class);
HelloWebService soapClient = (HelloWebService)ctx.getBean("createHelloWebServiceProxyInstance", "http://localhost:8080/axis2/services?wsdl");

// 実行サンプル
HelloWebServiceResponseDTO response = soapClient.execute(helloWebServiceRequestDTO);
```

SpringFrameworkの力を借りると、すっきりしたコードになりますね:grin:

SOAP通信実現のために追加したパッケージは、下記のとおりです。
( 不要なパッケージが含まれているかもしれません。ご指摘頂けると助かります。)

```
		<!-- JaxWsPortProxyFactoryBean / SOAP通信実現のため  -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-web</artifactId>
			<version>5.1.8.RELEASE</version>
		</dependency>

		<!-- xml.bind module / SOAP通信実現のため  -->
		<dependency>
			<groupId>javax.xml.bind</groupId>
			<artifactId>jaxb-api</artifactId>
			<version>2.3.0</version>
		</dependency>
		<dependency>
			<groupId>com.sun.xml.bind</groupId>
			<artifactId>jaxb-core</artifactId>
			<version>2.3.0</version>
		</dependency>
		<dependency>
			<groupId>com.sun.xml.bind</groupId>
			<artifactId>jaxb-impl</artifactId>
			<version>2.3.0</version>
		</dependency>

		<!-- xml.ws module / SOAP通信実現のため -->
		<dependency>
			<groupId>javax.xml.ws</groupId>
			<artifactId>jaxws-api</artifactId>
			<version>2.3.0</version>
		</dependency>
		<dependency>
			<groupId>com.sun.xml.ws</groupId>
			<artifactId>jaxws-rt</artifactId>
			<version>2.3.0</version>
		</dependency>
		<!-- javax.activation / SOAP通信実現のため -->
		<dependency>
			<groupId>javax.activation</groupId>
			<artifactId>activation</artifactId>
			<version>1.1.1</version>
		</dependency

```

## まとめ

Java11でws系のパッケージが消えたということで、最初は不安ばかりでしたが、簡単なコードで実現することが出来ました。
もしかしたら、gRPCよりは、実は扱いやすいプロトコルなのもしれません。