Play Framework 2.5.x (java) で Swagger 1.5.x を使う時に Ebean が _ebean_intercept を各モデルにつけてしまう問題の対処

Play Scala 2.2 + swagger 1.3.3 とかだと以下で対処できるようですが、タイトルの組み合わせではこのやり方は使えなかったので、試行錯誤の結果を残しておきます。

java - Swagger is showing _ebean_intercept with everymodel in my play application - Stack Overflow

import com.wordnik.swagger.converter.SwaggerSchemaConverter

class IgnoreConverter extends SwaggerSchemaConverter{
  override def skippedClasses: Set[String] = Set("com.avaje.ebean.bean.EntityBeanIntercept")
  override def ignoredClasses: Set[String] = Set("com.avaje.ebean.bean.EntityBeanIntercept")
  override def ignoredPackages: Set[String] = Set("com.avaje.ebean")
}
public class Global  extends GlobalSettings {
    @Override
    public void beforeStart(Application app) {
        Logger.info("Registering custom converter");
        ModelConverters.addConverter(new IgnoreConverter(), true);
    }
}

変更点

Play 2.5

GlobalSettings - 2.5.x - Play Framework

GlobalSettings が非推奨になりました。各クラスのコンストラクタで設定しましょう。

Swagger 1.5

Overriding Models · swagger-api/swagger-core Wiki

公式ドキュメントは現時点 (2017-04-10) で 1.3 系のままなので、テストクラスを参考にしてくれとのことみたいです。

How do you override models with swagger-core 1.5.3? · Issue #1499 · swagger-api/swagger-core

実装

public class IgnoreConverter implements ModelConverter {
  @Override
  public Property resolveProperty(Type type, ModelConverterContext context, Annotation[] annotations, Iterator<ModelConverter> chain) {
    JavaType _type = Json.mapper().constructType(type);
    if (_type != null) {
      Class<?> cls = _type.getRawClass();
      // Ebean class (_ebean_intercept)
      if (EntityBeanIntercept.class.isAssignableFrom(cls)) {
        return null;
      }
    }
    if (chain.hasNext()) {
      return chain.next().resolveProperty(type, context, annotations, chain);
    } else {
      return null;
    }
  }

  @Override
  public Model resolve(Type type, ModelConverterContext context, Iterator<ModelConverter> chain) {
    if (chain.hasNext()) {
      return chain.next().resolve(type, context, chain);
    } else {
      return null;
    }
  }
}
@Api
public class HomeController extends Controller {

  @Inject
  public HomeController(MessagesApi messagesApi) {
    ModelConverters.getInstance().addConverter(new IgnoreConverter());
  }

  public Result index() {
    return ok("Hello, World!");
  }
}

Effective Java 第3版 は 2017年に出るかもしれない

Java の良書といえば真っ先に名前が上がるだろう Effective Java ですが、第2版の原本が出たのが既に 9年近く前で、流石に古くなってる感があります。

ラムダや Optional の使い方等、最近の Java の機能を加えた改訂版を待っていたのですが、 Quora の回答から、著者の言及にたどり着いたので、紹介しておきます。

今年中には出るんじゃないかってことみたいです。

追記 2017/04/19

Amazon で予約受付が始まりました。

https://www.amazon.co.jp/dp/0134685997

Effective Java (3rd Edition)

Effective Java (3rd Edition)

追記 2017/10/18

ピアソンのページが出来てました。 12/19 発売で、eBook もあります。

Java 9 にも対応するみたいです。

www.informit.com

Docker Compose の構成について

Docker は image が手元にあれば一瞬でサービスを立ち上げることができるので主に開発環境として便利に使ってます。

Docker のベストプラクティスとして “one process per container” が上げられており、一つのシステムを立ち上げるのにコンテナが複数必要になることもよくありますね。コンテナ間の連携は、レガシーな Link 機能で一つずつ繋げていた時代から進化し、Docker Network 機能で独自のネットワークを構成できるようになりました。そして、Docker Compose でコンテナを一気に立ち上げ、システムを構成できます。

で、今この Docker Compose の構成について悩んでいます。こんなとこかなという案をいくつか上げておくので、運用してみて後日談を後ほどまとめたいと思います。机上の空論なので、間違ってるところがあるかも。

    1. Dockerfile 置き場案
    1. Docker プロジェクト内包案
    1. Image 取り込み案

a. Dockerfile 置き場案

SPA なシステムで MySQL にデータを突っ込むようなものを想定しています。

.
├── README.md
├── docker-compose.yml
├── dockerfiles/
│   ├── Dockerfile_api     # <- API 実行環境
│   ├── Dockerfile_front   # <- フロントエンドアプリビルド環境
│   ├── Dockerfile_proxy   # <- Web サーバ
│   └── Dockerfile_mysql   # <- MySQL (公式の MySQL イメージでいいかも)
└── volumes/
    ├── app_source/        # <- API のソースコード
    ├── front_dist/        # <- ビルドされたフロントエンドアプリの出力先
    └── data_volume/       # MySQL のデータディレクトリ
  • Dockerfile 1枚だけのコンテナばかりならこれでよさそう
  • ソースコードは別途 Git 管理されてて git clone http://github/ikosin/some-app volumes/app_source する想定

b. Docker プロジェクト内包案

.
├── README.md
├── docker-compose.yml
├── api/
│   ├── Dockerfile         # <- API 実行環境
│   └── source/            # <- API のソースコード
├── front/
│   ├── Dockerfile         # <- フロントエンドアプリビルド環境
│   └── dist/              # <- ビルドされたフロントエンドアプリの出力先
├── proxy/
│   └── Dockerfile         # <- Web サーバ
└── mysql/
    ├── Dockerfile         # <- MySQL (公式の MySQL イメージでいいかも)
    └── data/              # MySQL のデータディレクトリ
  • だいたいどんなコンテナでも対応できるように分けた構成で、これが王道な気がする
  • ソースコードはどう管理しましょうかね……。Git のサブモジュールにしておくと次の Image 取り込み案に移行するのも簡単でいいかもしれません

(追記)

こちらのブログではこのパターンを採用してそうですね。ソースコードもモノリポで一緒に管理してるんでしょうか。 複数の rails プロジェクトが共存する開発環境を Docker 化した話を晒してみる · カウル Tech Blog

c. Image 取り込み案

.
├── README.md
└── docker-compose.yml
  • ソースコード管理しているリポジトリに Dockerfile も突っ込んでそっちで Image ビルドしてしまいましょう案
  • Docker イメージのプライベートリポジトリが欲しくなるけど、無くても各サーバで各イメージをビルドすればなんとかなる
  • すごい薄い機能のコンテナをわざわざ切り離すのも面倒かもしれないけど、汎用性を意識するようになっていいかも

やってみる

上からお手軽な順にあげてみたつもりです。

現在、CONBUCONBU-API の実行環境を Docker 化しようと現在進めている所なので、ひとまず上からやってみてフィードバックもらいたいと思います。