- 投稿日:2019-07-30T21:54:51+09:00
Spring Boot + WireMockでNoHttpResponseException
事象
商用で動いているSpring BootのAppを改修した。
AppにはRestTemplateを使って他の連携先システムのREST APIを呼びにいく箇所があり、該当箇所を含む単体テストはWireMockでモックサーバを立てて実施していた。改修に応じてテストを追加した所、既存のテストが突然
NoHttpResponseException:[server] failed to respond
などと例外を吐いてコケるようになった。テストを単体で実行すると通り、通しで実行するとコケるという状態のため、テスト自体のミスでは無い模様。
ということで調査開始。原因
WireMockへアクセスするAppのHttp Clientに、HttpURLConnectionを使用している場合に発生するバグらしい。
https://github.com/tomakehurst/wiremock/issues/97
SpringのRestTemplateも内部的にはHttpURLConnectionを使っているので該当。対策
spring-cloud-contract-wiremockを使う。
https://github.com/tomakehurst/wiremock/issues/97
同issueに何種類かの対策が示されているので、お気に召すものを採用すれば良いと思われる。
一応の選定基準は以下の様な感じ。
Spring Bootのバージョンを上げる or HttpClientを変える
商用で動いているAppなので、テストのために構成変更は基本NG→✕HttpClientのconnection reuseを無効化
設定場所が分からないし、Appの動作に影響出そう→✕spring-cloud-contract-wiremockの利用
テストのライブラリ変更だけで完結→○spring-cloud-contract-wiremockは名前の通り内部でwireMockを利用しているので、テストコードの変更も最小限で済みました。
具体的には、サーバ設定の記法を変更して、既存のテスト用resourceのディレクトリを指定してやるだけ。
詳しい使い方は公式参照Configuration(before)public class ExampleUnitTest { @Rule public WireMockClassRule wireMockRule = new WireMockClassRule(8080); ....Configuration(after)@AutoConfigureWireMock(port = 8080, stubs = "classpath*:/META-INF/**/mappings/**/*.json") public class ExampleUnitTest { ....上記の通り、私の場合は
stubs =
で指定しているテスト用resourceのパスをよしなにしてやるだけで既存のテストコードがそのままパスするようになりました。
- 投稿日:2019-07-30T12:41:45+09:00
swagger condegenからの自動生成メモ
swagger condegenからの自動生成メモ
公式の情報が多すぎてちょっとよくわからなくなったので、メモ残します
使った理由
- ドキュメントを絶対正義とした開発をしたかったから。
- クライアントも出力出来てテストしやすそうだったから。
generateしてみる
難しいことはなく、↓でできます。
java -jar swagger-codegen-cli.jar generate \ -i swagger.json \ -l java \ -o outfolder \しかし、package構成やプロジェクト名がなかなか実用的ではなかったりしますね。
オプションを指定できる
公式に従い、確認します。
spring使いたかったので、springのoptionを調べますjava -jar swagger-codegen-cli-2.4.7.jar config-help -l spring sortParamsByRequiredFlag Sort method arguments to place required parameters before optional parameters. (Default: true) ensureUniqueParams Whether to ensure parameter names are unique in an operation (rename parameters that are not). (Default: true) allowUnicodeIdentifiers boolean, toggles whether unicode identifiers are allowed in names or not, default is false (Default: false) modelPackage package for generated models apiPackage package for generated api classes invokerPackage root package for generated code groupId groupId in generated pom.xml artifactId artifactId in generated pom.xml artifactVersion artifact version in generated pom.xml artifactUrl artifact URL in generated pom.xml artifactDescription artifact description in generated pom.xml scmConnection SCM connection in generated pom.xml scmDeveloperConnection SCM developer connection in generated pom.xml scmUrl SCM URL in generated pom.xml developerName developer name in generated pom.xml developerEmail developer email in generated pom.xml developerOrganization developer organization in generated pom.xml developerOrganizationUrl developer organization URL in generated pom.xml licenseName The name of the license licenseUrl The URL of the license sourceFolder source folder for generated code localVariablePrefix prefix for generated code members and local variables serializableModel boolean - toggle "implements Serializable" for generated models (Default: false) bigDecimalAsString Treat BigDecimal values as Strings to avoid precision loss. (Default: false) fullJavaUtil whether to use fully qualified name for classes under java.util. This option only works for Java API client (Default: false) hideGenerationTimestamp hides the timestamp when files were generated withXml whether to include support for application/xml content type and include XML annotations in the model (works with libraries that provide support for JSON and XML) (Default: false) dateLibrary Option. Date library to use joda - Joda (for legacy app only) legacy - Legacy java.util.Date (if you really have a good reason not to use threetenbp java8-localdatetime - Java 8 using LocalDateTime (for legacy app only) java8 - Java 8 native JSR310 (preferred for jdk 1.8+) - note: this also sets "java8" to true threetenbp - Backport of JSR310 (preferred for jdk < 1.8) java8 Option. Use Java8 classes instead of third party equivalents true - Use Java 8 classes such as Base64 false - Various third party libraries as needed disableHtmlEscaping Disable HTML escaping of JSON strings when using gson (needed to avoid problems with byte[] fields) (Default: false) title server title name or client service name configPackage configuration package for generated code basePackage base package (invokerPackage) for generated code interfaceOnly Whether to generate only API interface stubs without the server files. (Default: false) delegatePattern Whether to generate the server files using the delegate pattern (Default: false) singleContentTypes Whether to select only one produces/consumes content-type by operation. (Default: false) java8 use java8 default interface (Default: false) async use async Callable controllers (Default: false) responseWrapper wrap the responses in given type (Future,Callable,CompletableFuture,ListenableFuture,DeferredResult,HystrixCommand,RxObservable,RxSingle or fully qualified type) useTags use tags for creating interface and controller classnames (Default: false) useBeanValidation Use BeanValidation API annotations (Default: false) implicitHeaders Use of @ApiImplicitParams for headers. (Default: false) swaggerDocketConfig Generate Spring Swagger Docket configuration class. (Default: false) useOptional Use Optional container for optional parameters (Default: false) generateForOpenFeign Generate for usage with OpenFeign (instead of feign) (Default: false) library library template (sub-template) to use (Default: spring-boot) spring-boot - Spring-boot Server application using the SpringFox integration. spring-mvc - Spring-MVC Server application using the SpringFox integration. spring-cloud - Spring-Cloud-Feign client with Spring-Boot auto-configured settings.指定してみました。
ちゃんと全部Packageを指定しないとdefaultのio.swaggerに出力されるので注意
{ "groupId": "hoge", "artifactId": "hoge", "artifactVersion": "1.0.0-SNAPSHOT", "basePackage": "hoge", "configPackage": "hoge", "modelPackage" "hoge", "apiPackage" "hoge", "java8": true, "useBeanValidation": true }generate
java -jar swagger-codegen-cli-2.4.7.jar generate \ -i ./swagger.yml \ -l spring \ -o ./ \ -c ./config.jsonmvn install
pom書き換える
追記
<dependency> <groupId>javax.xml.bind</groupId> <artifactId>jaxb-api</artifactId> <version>2.1</version> </dependency>mvn install
成功
そういえばSpringのバージョンは?
古い
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.9.RELEASE</version> </parent>参考
https://github.com/swagger-api/swagger-codegen
https://github.com/swagger-api/swagger-codegen/wiki/Server-stub-generator-HOWTO
- 投稿日:2019-07-30T12:41:45+09:00
swagger condegenからの自動生成メモ(spring) -1
swagger condegenからの自動生成メモ
公式の情報が多すぎてちょっとよくわからなくなったので、メモ残します
使った理由
- ドキュメントを絶対正義とした開発をしたかったから。
- クライアントも出力出来てテストしやすそうだったから。
generateしてみる
難しいことはなく、↓でできます。
java -jar swagger-codegen-cli.jar generate \ -i swagger.json \ -l java \ -o outfolder \しかし、package構成やプロジェクト名がなかなか実用的ではなかったりしますね。
オプションを指定できる
公式に従い、確認します。
spring使いたかったので、springのoptionを調べますjava -jar swagger-codegen-cli-2.4.7.jar config-help -l spring sortParamsByRequiredFlag Sort method arguments to place required parameters before optional parameters. (Default: true) ensureUniqueParams Whether to ensure parameter names are unique in an operation (rename parameters that are not). (Default: true) allowUnicodeIdentifiers boolean, toggles whether unicode identifiers are allowed in names or not, default is false (Default: false) modelPackage package for generated models apiPackage package for generated api classes invokerPackage root package for generated code groupId groupId in generated pom.xml artifactId artifactId in generated pom.xml artifactVersion artifact version in generated pom.xml artifactUrl artifact URL in generated pom.xml artifactDescription artifact description in generated pom.xml scmConnection SCM connection in generated pom.xml scmDeveloperConnection SCM developer connection in generated pom.xml scmUrl SCM URL in generated pom.xml developerName developer name in generated pom.xml developerEmail developer email in generated pom.xml developerOrganization developer organization in generated pom.xml developerOrganizationUrl developer organization URL in generated pom.xml licenseName The name of the license licenseUrl The URL of the license sourceFolder source folder for generated code localVariablePrefix prefix for generated code members and local variables serializableModel boolean - toggle "implements Serializable" for generated models (Default: false) bigDecimalAsString Treat BigDecimal values as Strings to avoid precision loss. (Default: false) fullJavaUtil whether to use fully qualified name for classes under java.util. This option only works for Java API client (Default: false) hideGenerationTimestamp hides the timestamp when files were generated withXml whether to include support for application/xml content type and include XML annotations in the model (works with libraries that provide support for JSON and XML) (Default: false) dateLibrary Option. Date library to use joda - Joda (for legacy app only) legacy - Legacy java.util.Date (if you really have a good reason not to use threetenbp java8-localdatetime - Java 8 using LocalDateTime (for legacy app only) java8 - Java 8 native JSR310 (preferred for jdk 1.8+) - note: this also sets "java8" to true threetenbp - Backport of JSR310 (preferred for jdk < 1.8) java8 Option. Use Java8 classes instead of third party equivalents true - Use Java 8 classes such as Base64 false - Various third party libraries as needed disableHtmlEscaping Disable HTML escaping of JSON strings when using gson (needed to avoid problems with byte[] fields) (Default: false) title server title name or client service name configPackage configuration package for generated code basePackage base package (invokerPackage) for generated code interfaceOnly Whether to generate only API interface stubs without the server files. (Default: false) delegatePattern Whether to generate the server files using the delegate pattern (Default: false) singleContentTypes Whether to select only one produces/consumes content-type by operation. (Default: false) java8 use java8 default interface (Default: false) async use async Callable controllers (Default: false) responseWrapper wrap the responses in given type (Future,Callable,CompletableFuture,ListenableFuture,DeferredResult,HystrixCommand,RxObservable,RxSingle or fully qualified type) useTags use tags for creating interface and controller classnames (Default: false) useBeanValidation Use BeanValidation API annotations (Default: false) implicitHeaders Use of @ApiImplicitParams for headers. (Default: false) swaggerDocketConfig Generate Spring Swagger Docket configuration class. (Default: false) useOptional Use Optional container for optional parameters (Default: false) generateForOpenFeign Generate for usage with OpenFeign (instead of feign) (Default: false) library library template (sub-template) to use (Default: spring-boot) spring-boot - Spring-boot Server application using the SpringFox integration. spring-mvc - Spring-MVC Server application using the SpringFox integration. spring-cloud - Spring-Cloud-Feign client with Spring-Boot auto-configured settings.指定してみました。
ちゃんと全部Packageを指定しないとdefaultのio.swaggerに出力されるので注意
{ "groupId": "hoge", "artifactId": "hoge", "artifactVersion": "1.0.0-SNAPSHOT", "basePackage": "hoge", "configPackage": "hoge", "modelPackage" "hoge", "apiPackage" "hoge", "java8": true, "useBeanValidation": true }generate
java -jar swagger-codegen-cli-2.4.7.jar generate \ -i ./swagger.yml \ -l spring \ -o ./ \ -c ./config.jsonmvn install
pom書き換える
追記
<dependency> <groupId>javax.xml.bind</groupId> <artifactId>jaxb-api</artifactId> <version>2.1</version> </dependency>mvn install
成功
そういえばSpringのバージョンは?
古い
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.9.RELEASE</version> </parent>参考
https://github.com/swagger-api/swagger-codegen
https://github.com/swagger-api/swagger-codegen/wiki/Server-stub-generator-HOWTO
- 投稿日:2019-07-30T12:07:16+09:00
Java学習日記 1日目
初めまして。ミントッパと言います。
現在27歳、大学卒業後5年間製造業やってました。上がらない給料、下がる一方のボーナスに将来の不安を感じ
エンジニアになるべく転職を決意しました。独学でRubyを学び、大したスキルは無いが勉強意欲を評価されて無事内定!
8月よりJavaエンジニアとして働くことになった。エンジニアはアウトプットが大事とのことなので
今日から勉強の記録をしていこうと思う。
- 投稿日:2019-07-30T09:19:39+09:00
Javaのラムダ式を改めて
はじめに
IT業界に飛び込んで早2年ちょっとが経過。
本格的にコーディングに取り組んだのが正直なところ、1年とちょっとくらいしかない。
かつ、運用保守ということもあり、既存の実装をなるべく汚さないようにエンハンスすることが正な世界で生きてきた。
そして何と言っても、そのパッケージで利用されていたJDKはjava1.7!!
という上記の背景からも、なかなかjava8以降に触れることも少なかったので、今一度学び直したいと思った。
備忘録も兼ねつつ、今後はQiitaへの執筆も本格化していきたいところでもあるので、今回の執筆に至った。まずはその第一歩として、ラムダ式についての理解がぼんやりしていたので、記事を通して理解を深めたい。
ラムダ式って何? ⇨ インタフェースって何?
ラムダ式をいきなり理解する前に、どうやら関数型インタフェースに関する前提知識が必要そう。
そうなるとそもそも、インタフェースって何?と聞かれるとはっきり答えることができない自分がいる。
恥を恐れずJavaにおけるインタフェースについて、まずはしっかり理解しておこうと思う。Javaにおけるインタフェースとは?
以下の記事がわかりやすく、参考になるかと思います。
https://www.internetacademy.jp/it/programming/java/difference-between-interface-and-abstract.htmlインタフェースとは、メソッドの箱だけを準備しておき、その箱を実際に利用するとき(継承)に、継承先のクラスに実装を強制させる。
例えば、Employee
というEntityに対するServiceクラスとして、EmployeeService
を実装する場面を考える。EmployeeService.javainterface EmployeeService { Employee getEmployee(String pk); }Serviceクラスの実装でよく見かける(使われるケース)として、Serviceのinterfaceを実装し、メソッドのみを外部に公開する方法。
EmployeeService
の実装クラスとして、EmployeeServiceImpl
を別クラスで作成する。EmployeeServiceImpl.javapublic class EmployeeServiceImpl implements EmployeeService { Employee getEmployee(String pk) { // Daoにアクセスして、pkに一致するEmployeeを取得する。 return employeeDao.find(pk); } }ここで重要なのは、この
EmployeeServiceImpl
はEmployeeService
を継承しているため、
EmployeeService
にて宣言された、getEmployee
を必ず実装しなくてはいけないということ。
こうすることで、インタフェースを継承した実装クラスは必ずインタフェースで宣言されたメソッドを実装しなくてはコンパイルエラーとなり、実装を強制することができる。抽象クラスとインタフェースの一番の違いは、多重継承することができるという点。
多重継承について詳しくは記載しないが、要するに複数の実装を強制する仕組みをインタフェースだと利用できるということ。
(複数のインタフェースをひとつのクラスが継承することができるということ。)ラムダ式って何? ⇨ 関数型インタフェースって何? ⇨ 関数って何?
インタフェースについてはわかった。わかったけど、まだラムダ式を理解しにかかるには足りていない知識がある。
関数型インタフェースってなに?
ん、関数型
ってなに?
んん、関数
ってなに?Javaにおける関数とは?
関数とは何かは以下のURLが参考になります。
https://stackoverflow.com/questions/155609/whats-the-difference-between-a-method-and-a-function要するに関数とは、
とあるパラメータ(引数)を受け取り、引数をもとに何らかの処理を加えた上で結果の値を返す(return)するもの。
関数を実装する際に気をつけるべきポイントがあるため、ついでにここで紹介しておく。
Javaのような言語でプログラミングを経験していると、遅かれ早かれ副作用
という単語を聞くことになる。
副作用というのは超簡単にざっくりと言うと・・・
関数の実行結果が常に一定とならない実装
だと自分は理解しています。副作用のない関数を実装するために意識しておくポイントは以下です。
1. 関数は引数の値以外からは影響を受けない。
2. 同じ引数の値であれば、常に同じ値を返す。具体的な実装例等は別途調べてみてください。(自分よりもうまく説明してくれている記事は5万とあります。)
話は戻って、関数とは結局、入力に対して値を返すものです。
関数って何? ⇨ 関数型インタフェースって何?
関数についてはざっくり理解できた。
じゃあいよいよ関数型インタフェースって何?という話に主題を移してみる。
以下の記事がかなり参考になるので記載しておきます。
http://www.ne.jp/asahi/hishidama/home/tech/java/functionalinterface.html#h_outlineこちらの記事でも言及されているように、関数型インタフェースとは、
定義されている抽象メソッドが1つだけあるインターフェース。
ということです。
この記事の中で紹介した、
EmployeeService
は関数型インタフェースと呼ぶことができます。
pk
に一致するEmployee
を取得して返すということのみを行なっているService
クラスです。EmployeeService.java@FunctionalInterface public interface EmployeeService { Employee getEmployee(String pk); }関数型インタフェースを定義するのポイントとしては、
@FunctionalInterface
のアノテーション。
このアノテーションを付与することで、関数型インタフェースであることを明示的に宣言でき、コンパイル時にも条件を満たしていない場合はエラーとなります。
また、実装を追う場面でもこのアノテーションが付与されていることで、関数型インタフェースであることを他者から見てもわかりやすくなります。
※default
やstatic
メソッドが定義されていても、それらは関数型インタフェースの条件からは除外されるらしい。関数型インタフェースって何? ⇨ ラムダ式って何?
JDK1.8から、関数型インタフェース(抽象メソッドを1つのみ保持しているインタフェース)を特別なものとして扱うことになった。
さて、本記事の本題にようやく返ってきました。ここからようやく結局ラムダ式ってなに?を突き詰めようと思います。以下の記事がすごくわかりやすく、ラムダ式のことを図解してくれているので参考になります。
http://masatoshitada.hatenadiary.jp/entry/2015/02/09/190150つまるところ、ラムダ式を理解するためには、
Function
を例に型推論
を理解することが一番だと思う。ラムダ式って何? ⇨ Functionって何? 型推論って何?
FunctionとはJava8で導入されたパッケージです。
Function<T, R>
で型が定義されており、T
は引数となる型、R
は戻り値として返す型となります。
で、このFunction
は関数型インタフェースとして定義されており、apply
というメソッドのみを持ちます。ラムダ式を利用して、
Function
を実装することができます。
以下に簡単に実装例を示します。
例)Employee
のName
をFunction
を利用して取得する。Employee.java@Getter @Setter @AllArgsConstructor(staticName = "of") public class Employee { /** Id */ private int id; /** Name */ private String name; }Main.javapubic class Main { public static void main(String args[]){ Employee emp = Employee.of(1, "Sample太郎") Function<Employee, String> getEmployeeName = employee -> employee.getName(); String empName = getEmployeeName.apply(emp); System.out.println(empName); // 「Sample太郎」が出力される。 } }※
Name
取り出すくらいならGetter
使えよなんて声はご愛嬌ください。上記の例で重要なのはここ。
Function<Employee, String> getEmployeeName = employee -> employee.getName();
Function
の引数となる型(Employee
)から、戻り値としてemployee.getName()
の結果である、文字列型(String
)を返却する処理を、Function
が持っているapply
というメソッドに実装します。
ということをラムダ式を用いてやっている。
型推論
でemployee
がT
であるEmployee
だとJavaは解釈し、型推論
でreturn
する値がString
であることをJavaは解釈します。(賢いですね・・・)String empName = getEmployeeName.apply(emp);そして実際に上記部分で、Stringの
empName
にFunction
のapply
を適用させる。というように関数型インタフェースの記載をシンプルにできるメリットがラムダ式にはあります。
ラムダ式って何?
結局自分が理解したラムダ式とは、関数型インタフェースを実装するにあたり、型推論を駆使して実装をシンプルにする便利なやつだということ。
ラムダ式単体での活用シーンは限られており、ラムダ式が真に実力を発揮するのは、Function
やstream
と合わさった時なのかなと。
stream
を利用する際に特にこのラムダ式を意識することは必ずしも必要ではないが、理解しておいても損はないかな。おわりに
Optional
の学び直しもやろうと思っているが、どうやらラムダ式(というよりはConsumer
とか)が絡んできそう。
記事書くことで理解も捗る + 備忘 になるので、今後も積極的に書いていきたいと思う。間違いやアドバイス等々ございましたら、コメントよろしくお願いいたします・・・!
次回は
Optional
に関する記事を書きたいと思います。
ではでは〜
- 投稿日:2019-07-30T08:58:55+09:00
【Programming News】Qiitaまとめ記事 July 29, 2019 Vol.15
筆者が2019/7/29(月)に気になったQiitaの記事をまとめました。昨日のまとめ記事はこちら。
2019/7/21(日)~2019/7/27(土)のWeeklyのまとめのまとめ記事もこちらで公開しております。
Java
Python
- Tips
- Apps
Rails
- Tips
Vue.js
Android
- Tips
Swift
- Beginner
- Tips
Kotlin
- Beginner
- Tips
Flutter
JavaScript
- Beginner
- Tips
Node.js
React
Laravel
Keras
- Beginner
PowerShel
Spark
R言語
MySQL
Azure
AWS
- EC2
- AWS Lambda
- Tips
- AWS CodeStar
Docker
- Tips
- DockerコンテナのロギングにGrafana+Lokiを試してみた
- 最短2文でLibraのテストネットを立ち上げるDockerイメージ作りました
- もっと簡単にDockerでNuxt.jsを始めてみる(続Dockerでローカル環境を汚さずにNuxt.jsを始めてみる)
- Hugo を Docker 上で動作させる
- Nginx版:mkcertを使ってローカル環境でもDockerでも楽々SSL
- Vagrant環境のDockerでJenkinsサーバを構築し、スレーブのWindowsマシンを接続する(前半)
- Vagrant環境のDockerでJenkinsサーバを構築し、スレーブのWindowsマシンを接続する(後半)
- DockerでNuxt.js on TypeScriptを始めてみよう
- DockerでRailsの環境構築
TypeScript
Google Apps Script
機械学習
- Beginner
Raspberry
- Tips
Develop
- Tips
- Meetup
Intellij IDEA
更新情報
Kotlin
- Kotlin入門
Android
Java
IDE