寄付あるいは養分

みなさんskebというサービスをご存知でしょうか?
ご存知じゃない場合は時代遅れなので調べてください
(今更skebについて言及するこの記事自体も時代遅れ説、、


skeb.jp


簡単にまとめると
・即売会で絵師にスケブ(色紙を渡してイラストを描いてもらう行為)を依頼するような気軽さで絵を依頼できる
・依頼の金額は任意(ただし参考価格を絵師側が提示している)
・他のクラウドソーシング系サービスと比較して絵師側が有利に取引できるような機能設計をしている
 例:参考価格での検索をできないようにして価格低下圧が発生しないようなデザイン
・skeb依頼による成果物の著作権は常に絵師側に帰属する
・依頼のリテイク不可

というようなサービスです。
著作権・リテイク不可等の制限を設けることでできるだけ絵師を集めることを狙ってサービスが設計されているわけですね。
客じゃなければあなたが商品ではないですが、絵師をあつめて絵師を商品化… まあこの場合は絵師も依頼がきやすくなってwinwinという感じすね。

あなたは“客”ではなくて“商品”なのだ - 週刊アスキー

クリエイターに幸をもたらす今までになかった素敵なサービスですね。
気軽にクリエイターに依頼ができるという意味でクライアント側もうれしいですね。
(あえて仕事の内容を制限することで生まれるビジネスもあるということ?)

↓創業者のコメントがあります

イラスト依頼サービス「Skeb」手数料無料化。運営の利益は大丈夫!? 製作者の呟きまとめ | AppBank


●そうはいっても

今更ながらskebで依頼してみようかと思い立って側と気付いたのですが、
正直書いて欲しい絵を人に伝えるのって結構難しいですね?
それに付け加えてお金をはらって依頼したいほど見たい絵があるかというところが問題です。

神絵師が考えた最強な絵を見れたら嬉しいですが、そこに自分が介在してくるとなるとなかなか二の足を踏む感じがあります。
そもそも今までの人生でも絵を見た最初は「おー」とはなりますが、その後は正直2、3回見て満足する感じでした。

なので、skebを使う動機があるとしてもその中身の絵自体が欲しくて依頼することはないんですよね。
もし自分がskebで依頼をするとしたら、
・好きなクリエイターに寄付/応援するような気持ち
・好きなコンテンツの絵を増やして界隈を盛り上げて欲しい気持ち
のどちらかになるかなと思います

というわけで今回初めて依頼を出してみました

こうご期待!?
(ちなみに依頼したのは原神の胡桃です、かわいいですね)


●寄付

でskebに依頼するときは寄付みたいな気持ちでするという話だったんですが、
じゃあ実際の寄付もやってみるかということで依頼してみました。


赤十字


おそらく人生で初寄付です!
まあただ想定通りですがお金払って終わりみたいな感じなところありますね。

寄付文化根付くきっかけに?増える「良いこと」へのお金の使い方 | コラム | auじぶん銀行

寄付行為には効用があるみたいな話がありますがどうなんでしょう、
今のところなんともないですが、日中じわじわくるタイプの嬉しさがあるのかもしれませんね。
500万寄付すれば誰でも勲章がもらえるらしいですし夢もあっていいのかもしれないですね。


まあ人生頑張りましょうという話でした
以上

はてぶには好き勝手に何書いてもいい

ってまじ?


最近サークルのブログを引っ越しました
それがこちらです

www.teikoku-vol.com

これを作るのには publiiを使いました
publiはGUIがある静的サイトジェネレータです

Static Site Generator with GUI to build privacy-focused SEO-friendly website

静的サイトジェネレータ+ファイルホスティングでのブログはもうだいぶ一般的というかWPを使っている方が珍しいかなくらいの印象ですね
料金とスパムコメントを気にしなくていいのと一番大きいのセキュリティ面ですね。
よっぽどじゃなければ静的ホスティングしたサイトは10年後も残っているような気がしますし


静的サイトジェネレータとは?という方はこの記事がおすすめです
osjupiter.netlify.app


...


まあ何を隠そう上記記事も僕が書いたんですが、、

今管理しているブログはサークル(帝ぼる)、これ、くらうる谷の3つになっています。

静的サイトジェネレータの欠点がいちいち記事書いた後にコミットしてプッシュするというのがめんどいというのがあるんですよね、
その点publiiはUIありで非エンジニアでも画像アップロード等のやる気が出ないエンジニアでもそれなりのサイトができるという点が良いかなと思っています。

非エンジニアも含めた静的サイトの生成に悩んでいる方にはおすすめです
もしくはすなおにはてなブログを使いましょう。
ブラウザひらけば記事が書けてこういうふうに書き殴ることもできるので


以上!

KotlinのisはJavaのinstanceofだよ

各位

お疲れ様です。 表題の通りKotlinのisはJavaのinstanceofを内部的には使用しています。

以上よろしくお願いいたします。


というわけで、Kotlinのパターンマッチにつかうisが内部的にどのような処理を行っているのかが気になったので調べてみました。 方法としてはKotlinでisを使ったコードをコンパイルしてできたクラスファイルを Javaコンパイラデコンパイルします。

Kotlinのコンパイラのバージョンは'1.3.11 デコンパイラにはCFR v0.139を使用しました。

Kotlinのコード

class A(){
    val a="aaa"
}
fun test(hoge:Int){
    val b= if(hoge==0)A()else null
    if(b is A){
        print("a")
    }else{
        print("b")
    }

}

これをコンパイルして得たTestKt.classデコンパイルした結果が以下のとおりです。

コマンド

java -jar cfr-0.139.jar   out/production/classes/TestKt.class 
/*
 * Decompiled with CFR 0.139.
 * 
 * Could not load the following classes:
 *  kotlin.Metadata
 */
import java.io.PrintStream;
import kotlin.Metadata;

@Metadata([省略])
public final class TestKt {
    public static final void test(int hoge) {
        A b;
        A a = b = hoge == 0 ? new A() : null;
        if (b instanceof A) {
            String string = "a";
            System.out.print((Object)string);
        } else {
            String string = "b";
            System.out.print((Object)string);
        }
    }
}

みごとにinstanceofが登場していることがわかりますね。 Javaではinstanceofを使うのはあまり良くないとされていると思いますが、 Kotlinではスマートキャストのおかげか大活躍していますね。

ちなみにinstanceofの内部の動きに関してはJJUG CCC Fall 2018で発表された方がいて 大変勉強になりました。以下のリンクがその時のスライドです。 参考にどうぞ

Deep dive into instanceof

楽しく見ていただいた方はチャンネル登録お願いします。(?)


追記

スマートキャストが動いている例もやってみました。


sealed class A{
    class B(var num:Int):A()
    class C(var str:String):A()
    class D(var double: Double,var int: Int):A()

}
fun test(hoge:Int){
    val v:A= if(hoge==0){
        A.B(1)
    }else if(hoge==1){
        A.C("1")
    } else {
        A.D(1.0,2)
    }
    when(v){
        is A.B->
            print(v.num)
        is A.C->
            print(v.str)
        is A.D->
            print(listOf(v.double,v.int))
    }

}

逆翻訳後

/* クラス定義は省略します */
public final class TestKt {
    public static final void test(int hoge) {
        A v = hoge == 0 ? (A)new A.B(1) : (hoge == 1 ? (A)new A.C("1") : (A)new A.D(1.0, 2));
        A a = v;
        if (a instanceof A.B) {
            int n = ((A.B)v).getNum();
            System.out.print(n);
        } else if (a instanceof A.C) {
            String string = ((A.C)v).getStr();
            System.out.print((Object)string);
        } else if (a instanceof A.D) {
            List list = CollectionsKt.listOf((Object[])new Object[]{((A.D)v).getDouble(), ((A.D)v).getInt()});
            System.out.print(list);
        }
    }
}

普通にダウンキャストと同じバイトコードになるようですね。

JJUG CCC fall2018参加メモ

JJUG CCC 2018 Fall に行ってきました。 備忘録と生存報告がてらに聴講した発表についてメモ。

www.java-users.jp

会場

西新宿のベルサール新宿グランドコンファレンスセンターに 10:00から開始でした。

うっかり新宿駅から歩いていってしまったので大変な目に会いました。 寒い朝の新宿を歩いて20分位したらつきました。 (西新宿の建物は新宿をなのるな?)

1.Javaの未来を考えよう

1つ目は基調講演のJavaの未来を考えようでした。 ついたのが10:30くらいだったので最後の15分くらいしか聞けませんでした。

中身はいい感じにメモした方がいらっしゃったのでぺたり

最後の15分位は10年位前にSIerがバリバリstrutsを業務で使っていたのに、 コントリビュートをほとんどしないフリーライダーばかりであったみたいな話をしていました。 JJUGというコミュニティを運営している方々はやはりフリーライダーのことを良くは思っていないようで、 JJUG CCCに聴衆として参加するだけじゃなくどんどんコミュニティに貢献していけみたいなことを喋ってらっしゃいました。 (途中でフォローが入って、CCCに参加するようなことも貢献の一つであるという解釈をしていましたが) ほぼ技術情報を表に出せていない自分にとっては耳が痛い話でした。

2.モジュールグラフが作られる様子を学ぼう

モジュールグラフが作られる様子を学ぼう - Qiita

2つ目はJava9から導入されたモジュールシステムに関するお話でした。 正直モジュールグラフという字面を見てJavaのモジュールシステムのことを指していると気づかずになんとなくこの発表を聞いていました。(Java9以上にまだ触ったことがないのです)

モジュールシステムについて全く事前知識がなかったのですが、この発表のおかげでモジュールシステムがどういうふうに動いているかの枠組みがつかめた気がします。

LINE で広告プラットフォームを Java + Golang で立ち上げた話

polyglotなマイクロサービスをどのように構築したか?という話をLINE社内の事例を出して発表されていました。 この発表によると広告関連のシステムは初見の人にはちんぷんかんぷんではあるが、 わりと業界内では構成が統一されているというお話でした。 個人的に気になったキーワードは、サービス感の連携のバッファとして使用しているKafkaとそのスキーマを定義する Apache avroです。 そのうち調べたいと思います。

俺が好きなのはJavaだけどJavaじゃない 〜虎の穴でのJava活用について〜

speakerdeck.com

萌え萌え履歴書が萌え萌えすぎて開くのに躊躇したよかったです。 レガシーなECシステムを自社開発するようになり、エンジニアの採用の一環として?オープンスペースや 他にも様々な取り組みを行っているようです。 気になった人は調べてみよう!

生粋のKotlin LoverによるLINEのKotlinの話

LINE社内のKotlin事例だけだと発表が持たないので 最近のKotlinのアップデート内容やKotlin Confの話をされていました。

自分もKotlinを趣味の開発では使っているのですが いかんせんコルーチンなり新し目の機能を試していないので勉強になりました。 特にInline classesについては普段Javaでやっている開発で同じような機能が欲しくなった場面があったので そのうち試してみようと思います。

複雑なドメインに泥臭く立ち向かう

speakerdeck.com

介護保険という複雑のドメイン周りをどのようにチームで噛み砕いていったかという話を詳細にしてくださいました。 会社でもこのくらいチームで向き合えればもっとドメインの理解が深まりそうだなぁと思う一方、 実際これをどのように自分の労働環境でやっていくか考えるとなかなか前途多難です。

Deep dive into instanceof

個人的に一番面白かったお話でした。 今までJVMの中のコードのことを考えたことがなかったのですが、 この発表でJVMのコードを読んでみたくなりました。 (まずはコンパイルされたあとのバイトコードをみていきたいですね)

GraphQL vs Traditional Rest API

www.slideshare.net

GraphQL Javaのライブラリを使用したコードを実際に動かしながら GraphQLでやれることを発表されていました。 GraphQLの導入で一番インパクトがあるのはフロント側とサーバ側できちんとスキーマを定義することであるという ような話でした。 (Restはサーバ側が用意したAPIの詳細を知り合わせる必要があるが、共通のスキーマを定義することでスキーマにさえ従えば良くなる) 個人的にはGraphQL-javaのライブラリがかなり強力そうに感じました。

Scala とマイクロサービスでつくる証券会社とスタートアップ

speakerdeck.com

社内でscalaの機能をいかに活用して安全で高速に開発を行っているかという話でした。 個人的にはKotlinの発表で知ったinline classが活躍しそうな事例の話をされていて「それKotlinでできるよ」みたいなことで 頭が一杯になっていました。 (発表内ではサービス開始した4~5年前にはサーバサイドKotlinの事例がなかったというフォローをきちんとされていました) その他にもモデリングをどのように行っているかや採用しているFinagle/Finatraの話が参考になりました。 自分は普段の業務では効率的/高速な開発ができるフレームワークを使用していないため、 ある程度揃ったフレームワークを使用した開発もいいなあという感じです。 (Finatraがどのようなスタックを持っているか全然知りませんが)

懇親会

学会の懇親会みたいなめっちゃぼっちを回避して無事1名の方と雑談や情報交換を行うことができました。 次はもうちょっと多くの人と話したいと思います。(こなみ) 最後に集合写真取るの知らなくて20:30に帰ったのはちょっと勿体無かったなと思っております。

まとめ感想

いろいろJava周り(JVM周り?)の話が聞けて刺激になりました。 僕も他の人に刺激が与えられるくらいにはアウトプット力であったりシステム力(ちから)を上げていきたいと思います。 というわけで少しでも貢献になればと思って記事を書いてみましたので、皆さん是非リンク集としてこの記事をお役立ててください。 よろしこっ

参考

・発表スライドがまとまっているページ

GitHub - jjug-ccc/slides-articles-2018Fall: JJUG CCC 2018 Fall 登壇資料まとめ

parcelでelectron向けビルド

parcelでelectron向けビルドするためのオプションについて

手っ取り早いまとめ

parcel watch .\src\index.html --public-url ./ --no-hmr --target=electron

以下詳細

parcelはコマンドなしで実行すると開発用のビルドとhttpのサーブを行ってくれます

parcel hoge.html

本番向けにはbuildサブコマンドを使います.

parcel build hoge.html

ほかにもwatchサブコマンドでビルドだけ行わせることができます.

parcel watch hoge.html

しかしながら,parcelは開発ビルド(デフォルト,watch)をすると(用途は不明ですが) websocketで開発用のサーバと通信を行うコードを出力します. したがって以下のようにelectronと組み合わせて使用すると electronアプリからのページアクセス時にエラーを発行します.

parcel watch hoge.html &
electron dist/hoge.html
// WebSocket': The URL 'ws://:61948/' is invalid エラー発生

この問題をparcelのissueで調べると以下のissueを見つけました. Failed to construct 'WebSocket': The URL 'ws://:61948/' is invalid · Issue #856 · parcel-bundler/parcel · GitHub

したがってparcel watchの際には--no-hmrをつけましょう

parcel watch hoge.html --no-hmr

おわり

おまけ

上記のwebsockの問題以外にもelctronと組み合わせた際にエラーが発生するケースがあります.

絶対パス<->相対パス

electronはデフォルトの設定ではパスを絶対パスでアクセスしようとするとうまく動作しない問題があります. 例: /js/hoge.js 等 (参考: https://qiita.com/tuttieee/items/4123784f1eb68a1d3925) この問題を回避するには参考ページにあるようにfileプロトコルアクセス時のパス解決をインターセプトするか, もしくは初めから相対パスを使う方法があります. parcelはデフォルトではビルド後のファイルのリンクが/から始まる絶対パス指定になってしまいます. この絶対パス指定をやめるために--public-urlを使用しましょう.

parcel watch hoge.index --public-url .

こうするとパスの起点が設定されなくなり相対パスURLが生成されるようになります.

electronのimport

electronを使用する場合,rendererプロセス側のコードから

import  electron from "electron"

というようにelectronのAPIにアクセスするために‘electron‘モジュールをインポートするのですが, このimport文がparcelに解釈されてしまう関係でエラーが発生します. これを回避するために--target=electronをつけましょう.

swagger-codegen テンプレートとロジックのカスタマイズ

swagger-codegenのテンプレとロジックのカスタマイズ

前回の記事から引き続き swagger-codgenをさわっていきます.

今回はswagger-codegen(以下codegen)のカスタマイズ方法を記載します. カスタマイズ方法については以下の記事を参考にしていますが, この記事に乗っていないことをなるべく記述していきたいと思います!

こんなに簡単! Swagger Codegenのカスタマイズ https://qiita.com/Quramy/items/c583f3213f0b77ff1bac

なお最終的なファイル構成をgithubに上げているのでそちらも併せてご確認ください.

既存のテンプレートで動かす

まずはカスタマイズする前にどのような出力が行われるかを確認してみます. 前回の記事にもjarを使用した実行方法を記載していますが,今回はgradleを使用した方法を紹介します.

gradleの準備

gradleは依存解決+ビルドを行ってくれる支援ツールです. jvm系言語のビルドによく使用されますがC++などのビルドにも対応しているらしいです. 公式ページに記載があるように,パッケージマネージャからinstallするのがおすすめです.

macの場合はbrewで,windowsの場合はchocolaty経由でインストールしましょう. (chocolatyはwindows向けのパッケージマネージャです.インストールもinstallにあるスクリプトをcmdに張り付けるだけなのでぜひ導入しましょう.)

 brew install gradle # mac
 choco install gradle # windows

設定ファイルの準備

codegenを実行するためのbuild.gradleを任意のディレクトリに用意します. また生成に使用するサンプルとしてここからサンプルのSwagger定義を取得してswagger.jsonとして保存します

build.gradleはgradle用の設定ファイルです.

plugins {
  id 'org.hidetake.swagger.generator' version '2.12.0'
}

repositories {
  jcenter()
}

dependencies {
  // Add dependency for Swagger Codegen CLI
  swaggerCodegen 'io.swagger:swagger-codegen-cli:2.3.1'
}

swaggerSources {
  example{
    inputFile = file('swagger.json') //swagger定義ファイル
    code {
      language = 'spring'  //生成先のフレームワーク/言語
    }
  }
}

この設定を用意することでgradle-swagger-generator-plugin を利用してcodegenを動作させられます. また同時にgroovyを使用できるようプラグインを設定しています.

実行

以下のコマンドでcodegenプラグインを実行できます.

gradle generateSwaggerCode

これでbuildディレクトリ以下にソースコードが生成されました. 生成対象はbuild.gradlelanguage = 'spring'と設定したため,springbootを使用したサーバサイドのコードが生成されました.

# tree build
build
└── swagger-code-example
    ├── README.md
    ├── pom.xml
    └── src
        └── main
            ├── java
            │   └── io
            │       └── swagger
            │           ├── RFC3339DateFormat.java
            │           ├── Swagger2SpringBoot.java
            │           ├── api
            │           │   ├── ApiException.java
            │           │   ├── ApiOriginFilter.java
            │           │   ├── ApiResponseMessage.java
            │           │   ├── NotFoundException.java
            │           │   ├── PetApi.java
            │           │   ├── PetApiController.java
            │           │   ├── StoreApi.java
            │           │   ├── StoreApiController.java
            │           │   ├── UserApi.java
            │           │   └── UserApiController.java
            │           ├── configuration
            │           │   ├── CustomInstantDeserializer.java
            │           │   ├── HomeController.java
            │           │   ├── JacksonConfiguration.java
            │           │   └── SwaggerDocumentationConfig.java
            │           └── model
            │               ├── Category.java
            │               ├── ModelApiResponse.java
            │               ├── Order.java
            │               ├── Pet.java
            │               ├── Tag.java
            │               └── User.java
            └── resources
                └── application.properties

language='go'と設定してやるとgolang向けのクライアントのコードを生成できます.

# tree build
build
└── swagger-code-example
    ├── README.md
    ├── api
    │   └── swagger.yaml
    ├── api_client.go
    ├── api_response.go
    ├── category.go
    ├── configuration.go
    ├── docs
    │   ├── Category.md
    │   ├── ModelApiResponse.md
    │   ├── Order.md
    │   ├── Pet.md
    │   ├── PetApi.md
    │   ├── StoreApi.md
    │   ├── Tag.md
    │   ├── User.md
    │   └── UserApi.md
    ├── git_push.sh
    ├── model_api_response.go
    ├── order.go
    ├── pet.go
    ├── pet_api.go
    ├── store_api.go
    ├── tag.go
    ├── user.go
    └── user_api.go

カスタマイズしたい対象を見つける

カスタマイズ対象のピックアップ

さて今回のテーマはカスタマイズですが,まずはカスタマイズしたい個所をピックアップします. codegenのテンプレートは様々な言語に対応していますが 中には手で修正しないとビルドに成功しないテンプレートもあります. 今回はcodegenの設定を以下のように設定してコードを生成します.

build.gradle

//抜粋
  example{
    inputFile = file('mytemplate/ninja.yaml') //swagger定義
    code {
      language = 'java' 
      configFile = file('config.json')
    }
  }

mytemplate/ninja.yaml

# 抜粋
definitions:
  Person:
    type: "object"
    required:
    - "name"
    properties:
      id:
        type: "integer"
        format: "int64"
      name:
        type: "string"
        example: "doggie"
      group:
        type: "string"
        description: "pet status in the store"
        enum:
        - "伊賀"
        - "甲賀"
        - "はぐれ"

すると,コンパイルした際に以下のようなエラーが出ます.

 警告: 識別子として'_'が使用されました
    _("伊賀"),

これはEnumクラスの定義として以下のようなコードが出力されているためです.

  /**
   * pet status in the store
   */
  @JsonAdapter(GroupEnum.Adapter.class)
  public enum GroupEnum {
    _("伊賀"),
    
    _("甲賀"),
    
    _("はぐれ");

    private String value;

すこし調べたところ,これはswagger定義にあるEnumを以下のようにEnumの定数名に変換しているためでした.

String var = value.replaceAll("\\W+", "_").toUpperCase();

当該コード

この処理で全角文字をすべて_に変換しているために起きている問題のようです. 今回はこの問題を回避するようなカスタマイズを行います. (ちなみにこの全角をEnumに設定するとうまくコード生成されないのがただのバグなのかSwaggerの定義にEnumに全角を設定してはいけないせいなのかは知りません!だれか詳しい人がいたら教えてください!!!><)

カスタマイズをはじめる

テンプレートのカスタマイズ

codegen参考記事にあるようにテンプレートとそのテンプレートに流し込むデータを作るロジック部に大別されます. イメージとしては以下のような感じです.

(swagger定義yaml)->ロジック部->(中間データ構造)->mustacheテンプレート

language毎のテンプレートファイルはcodegenのリポジトリのresouces以下で確認できます. language=javaの場合のテンプレートはこれです.

さて問題のコードがどのテンプレートファイルから生まれたのかをgrep等を使用して探してみると,どうやらmodelInnerEnum.mustacheが問題のコードに対応するようです.

テンプレートは一部のファイルだけのカスタマイズが可能なため,modelInnerEnum.mustachemytemplate/template/以下に保存し, build.gradleを以下のように設定します. こうすることでもともとのテンプレートをtemplateDir以下の同名ファイルでオーバーライドすることができます.

// 抜粋
  example{
    inputFile = file('mytemplate/ninja.yaml') //swagger定義
    code {
      language = 'java' 
      templateDir = file('mytemplate/template/')
    }
  }

Mustacheの文法に注意しながらテンプレートを適当に編集して保存します.

mytemplate/template/modelInnerEnum.mustache

   public enum {{#datatypeWithEnum}}{{{.}}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{classname}}{{/datatypeWithEnum}} {
     {{#allowableValues}}
       {{#enumVars}}
+      // こんなこめんとをいれました
     {{{name}}}({{{value}}}){{^-last}},
     {{/-last}}{{#-last}};{{/-last}}
       {{/enumVars}}

この状態でgradle generateSwaggerCodeをしたら以下のように出力が変化しています.

  /**
   * pet status in the store
   */
  @JsonAdapter(GroupEnum.Adapter.class)
  public enum GroupEnum {
      // こんなこめんとをいれました
    _("伊賀"),
    
      // こんなこめんとをいれました
    _("甲賀"),
    
      // こんなこめんとをいれました
    _("はぐれ");

    private String value;

このようにテンプレートに追加した文字列がそのまま出力されるため, 簡単なカスタマイズであればこのテンプレートのカスタマイズだけで十分目的を果たせると思います.

ロジックのカスタマイズ

さて先ほど

(swagger定義yaml)->ロジック部->(中間データ構造)->mustacheテンプレート

と紹介しましたが,このようにテンプレートに埋め込む中間データ構造の値を変化させたい場合はロジックのカスタマイズが避けられません.

ロジック部のデータモデル

さてロジック部において各プロパティはCodegenPropertyクラスで扱われています.今回はこのへんenumVars.nameを別名で上書きすることにします.

Vender Extensions

ところで,Swagger定義では,Extensionsと呼ばれるx-から始まるカスタムプロパティを様々な項目に設定することができます. こちらの記事では,このextensions(Vender Extensions)を使用して中間データ構造に値を設定し,その値をテンプレートで参照することでカスタマイズを行っています. 今回はこのextension機能を利用してCodegenPropertyに値を渡し,ロジック内で特定のextensionがついていた場合はその値ででEnumの定数名を上書きします.

ロジックの継承とオーバライド

さきほどからlanguage='hoge'のように出力先の名前を指定していますが, ここの設定にはCodegenConfigインターフェースを継承したクラスのFQCN(パッケージ名とクラス名)を指定すればそのクラスを使用してくれます. したがって,カスタマイズしたいクラスを継承したクラスを自分で定義してそれをクラスパスに追加することで,任意の処理を既存の処理に挟み込むことができます.

というわけでlanguage='java'の際に使用されるJavaClientCodegenを継承したクラスをGroovyで定義してコンパイルしてクラスパスに追加して,そのクラス名をlanguageに指定して実行することでロジックのカスタマイズができました. (最終的ファイルをgithubに上げておいたので参考にしてください)

mytemplate/logic/MySwaggerLogic.groovy

import io.swagger.codegen.*;
import io.swagger.codegen.languages.*;

class MySwaggerLogic extends JavaClientCodegen {
    @Override
    public void updateCodegenPropertyEnum(CodegenProperty var) {
        super.updateCodegenPropertyEnum(var)
        if(var.vendorExtensions.containsKey("x-enum-names")){
            def alternames=var.vendorExtensions['x-enum-names']
            def enums=var.allowableValues["enumVars"]
            if(alternames.size()!=enums.size()){
                return
            }
            alternames.eachWithIndex{str,i->
                enums[i]["name"]=str
            }
        }
    }
}

build.gradle

plugins {
  id 'groovy'  // groovyでロジックを記述する際に使用
  id 'org.hidetake.swagger.generator' version '2.12.0'
}

repositories {
  jcenter()
}

dependencies {
  // Add dependency for Swagger Codegen CLI
  swaggerCodegen 'io.swagger:swagger-codegen-cli:2.3.1'
  // groovyのクラスファイルをクラスパスに追加
  swaggerCodegen files('build/classes/main/')
  swaggerCodegen localGroovy()
  // groovyコンパイル用の設定
  compile 'io.swagger:swagger-codegen-cli:2.3.1'
  compile localGroovy()
}

swaggerSources {
  example{
    inputFile = file('mytemplate/ninja.yaml') //swagger定義
    code {
      language = 'MySwaggerLogic' 
      configFile = file('config.json')
      templateDir = file('mytemplate/template/')
    }
  }
}
// swaggerSourceの前にgroovyをコンパイル
swaggerSources.example.code.dependsOn compileGroovy 
//ロジック記述ファイルの場所
sourceSets.main.groovy.srcDirs=['mytemplate/logic']

結果

  /**
   * pet status in the store
   */
  @JsonAdapter(GroupEnum.Adapter.class)
  public enum GroupEnum {
      // こんなこめんとをいれました
    Iga("伊賀"),
    
      // こんなこめんとをいれました
    Kouga("甲賀"),
    
      // こんなこめんとをいれました
    Alone("はぐれ");

    private String value;

想定したとおりにカスタマイズすることができました.

まとめと補足

本記事ではswagger-codegenを使用してコードを生成する方法,そしてテンプレートとロジックのカスタマイズ方法を解説しました.

個人的には前回の記事 にscaffoldingにcodegenを使ってみてはと書いた手前あれですが,用意されているテンプレートによってはいろいろなカスタマイズが必要になるのでなかなか良しあしがあるように感じます.本当に最初だけにとどめてそのあとは直接生成したコードを編集するのが楽な気がします...

補足

  • codegenのテンプレートはバージョンが変わるとところどころ変わっていることがあるので,github等でテンプレートを見る際は手元のcodegenのバージョンに注意してください
  • swagger仕様には2.0,3.0,3.1?の主なバージョンがありますが,codegenの3.0対応はあまり進んでいないらしい上にそれが原因でフォークプロジェクトができているようです

速習プリパラ1クール目

概要

今からプリパラを見直す際に(個人的に思う)見るべき話数を上げていきます. A プリパラシリーズ上必要 B そのクール上は見たほうがいいかも C 正直ちゃんとみてない

1クール目 ソラミスマイル編

1 アイドル始めちゃいました

A 記念すべき一話. みれぃの「プリパラは好きプリ?」は後々多用されるセリフであるが. この時点ではわりとさっらとやりとりされているね

2 約束やぶっちゃダメぷりっ

A らぁらとみれぃのコンビ結成回. みれぃとらぁらの関係性の基礎となるような話なので必須

3 チーム解散?困るクマ~!

C 練習回でもあり,そふぃ初登場?回でもあり, 校長の友達嫌いがわかる会でもある. 急ぎ目であればいらないかな?

4 かしこま!元気 For You

C テニス組,校長,のんが活躍する話 友達との約束うんぬん~みたいな友情な話, 女児アニメにはこういう話が大事ね

5 あたし、そふぃさんと歌いたいワニ!

B そふぃ回. そふぃ,ちゃんこ,こすもが登場する会. そふぃの人格説明回なのでとばすとわかりづらくなるかも. そふぃ勧誘をみれぃが認めた回でもある. ここからしばらくそふぃを追いかける話なので大事かもね

6 異議あり?らぁらがウチにやってきたっぷり!

C みれいの家訪問回. 正直両親はどうでもいいが, 2人が想像するアイドル検事みれい像の画像がシリーズでちょくちょく出てきた気がする. 新曲お披露目会かつMD作成会でもある. みれぃの昔の写真がMDの発想素だったのね(見直して知った)

7 レッドフラッシュを探して・・・

B そふぃ,うさぎ,校長回? 校長が次クールに向けてめっちゃスタンバってますね そふぃとらぁらのからみ2 そふぃとトモチケを交換するので期待させてからの

8 ドキドキ!夏だ!水着だ!プールでかしこまっ♪

C 幼馴染のなお回 シリーズを通してちょくちょくある 仲たがい...いいね 女児アニメ回 あの演説からこの曲であるみたいな気持ちにならないか? みれぃのアイドルは友達も笑顔に~のセリフは12話に使われる

9 ときめきアイドル大集合!

A そふぃとらぁらのからみ3 キュピコン初登場?

そふぃの出自の話なのでみておいたほうがよいかも トモチケ交換で期待させておいてからの

10 秋色ラブリーライブ

C 新しいコーデを考えながららぁらがぼけ倒す会 裏でそふぃの挫折が描かれていて1クール目の終わりまでの土台となるが見なくてもわかるか チーム結成もそふぃに断られるはなし

11 どうする?どうなる!?3人目!!!

B 1クール目終わりに向けて大事 メイキングドラマの振りが次の会で回収される

12 はばたけ、そふぃ!

A ソラミスマイル結成回 みれぃはそふぃのこと嫌いだな? ドロシー&レオナ登場回でもあるし2クール目に必要な話 初3人ライブ

13 空見て笑って・チーム名発表!

A チーム名決定話 ぷりぷりかしこま そふぃとみれぃの話でもある ファルルが出てくる

14 ライバル登場!イゴ、よろしく!!

A シオンが参戦! れっついごー好き ドレッシングパフェ結成回&初ライブ 初見はかなりインパクトあった

15 一触即発?シオンVSみれぃぷりっ!

C シオン回 初ソラミVSドレシではあるが 話は大きく進まない

続く!?