なんとな~くしあわせ?の日記

「そしてそれゆえ、知識そのものが力である」 (Nam et ipsa scientia potestas est.) 〜 フランシス・ベーコン

KotlinでS3バケットをmockする場合s3mockが便利だった

s3mock

github.com

ユースケース

  • ユニットテストでS3バケットへのファイルアップロード/ダウンロードをテストする場合
    • mockのS3バケットJUnitで立ち上げたり、全部のファイルを事前に削除して再作成、みたいなことができる

使い方

ライブラリのセットアップ
mock S3サーバの起動
        // mock s3 サーバを起動する
        S3Mock.Builder().withPort(8080).withInMemoryBackend().build().start()

        // AWS SDKのS3Clientのインスタンスを作る
        val s3Client = S3Client
                .builder()
                .region(Region.AP_NORTHEAST_1)
                .endpointOverride(URI.create("http://127.0.0.1:8080"))
                .credentialsProvider(AnonymousCredentialsProvider.create())
                .build()

        // s3へ操作
        s3Client.createBucket(***)
  • PythonだとmotoAWSサービスのmockを提供しているのでそういうのを使ったりする

WSL2上でXServerを立ててLinuxのアプリを使う

WSL2上でXServerを立ててLinuxのアプリを使う

autoize.com

Xfce4のインストール

$ cat /etc/debian_version
10.4

$ sudo apt-get update && sudo apt-get upgrade -y
$ sudo apt-get install xfce4

トラブル回避

  • ここまでやってxfce4を起動させると「Error: Can't open display」と出てくるが、自分の場合それはWindows Defender FirewallのほうでVcXsrvの通信がブロックされていたのが原因だった。コントロールパネルからWindows Defender ファイアウォールの詳細設定を開き、VcXsrvの通信をすべて許可すれば大丈夫。 *1

X ServerのIPアドレス指定

X Windowのサーバを立ち上げるときって、DISPLAYの環境変数にそのXサーバのIPアドレスを指定しないといけないのだが、WSLの場合/etc/resolve.confにIPアドレスが書かれているのでそれを拾って.bashrcなどに設定すればよい。*2

  • 以下を~/.bashrcに追記して、startxfce4とやればLinux上のDesktopが起動できる
export DISPLAY=`grep -oP "(?<=nameserver ).+" /etc/resolv.conf`:0.0

できあがり

  • gpgのキーとかをこっちに移動させたいな

f:id:panzer-jagdironscrap1:20200524170946p:plain
VcXsrv

*1:そのへんの情報はWSLのGitHubのissueから知ったCan't use X-Server in WSL 2 #4106

*2:WSLのGitHubのissueからCan't use X-Server in WSL 2 #4106

Kotlin+spring-bootでapplication.ymlのデータを読み込む

Kotlin+spring-bootでapplication.ymlのデータを読み込む

  • spring-bootでコンフィグファイルを外だしするとき、一般的にはapplication.propertiesやapplication.ymlに設定する
  • Kotlinで作成したプロジェクトで読み込む方法を調査した
  • Javaでも使えると思う

@ConfigurationPropertiesを使う

  • stackoverflow.com
    • @ConfigurationPropertiesを使い、YAMLの内容をデータクラスに注入する
    • prefixを指定することでYAMLのあるキーの下にある要素を取得できる
@Configuration
@ConfigurationProperties(prefix = "myconfig")
class MqttProperties {
    lateinit var myHost: String
    lateinit var myPort: String
    lateinit var myUser: String
    lateinit var myPass: String    
}
myconfig:
  my-host: ssl://example.com
  my-port: 23894
  my-user: user
  my-pass: pass
  • これは通常の用途ならば何も問題ないと思われる。簡単。
  • しかし、動的にbeanを登録したい場合、BeanDefinitionRegistryPostProcessorを使うのだが、それのメソッドが呼ばれた段階では@ConfigurationPropertiesでプロパティがロードされていない
  • @ConfigurationPropertiesがロードされるのはbeanが登録された後ぐらいみたいなんですよね…深くは調べてないけど

そのへんの話は以下
spring - Create N number of beans with BeanDefinitionRegistryPostProcessor - Stack Overflow

Binder APIを使用する

github.com

  • Wikiの記述にあるようにBinder APIは@ConfigurationPropertiesの枠組みの外側で動くことができる
  • BeanDefinitionRegistryPostProcessorを使う場合でもEnvironmentが読み込まれた段階でプロパティをロードできるので、よろしい
サンプルコード
myconfig:
  sample:
    key1: value1
    key2: value2
    key2: value3
@Configuration
class BindSampleConfig : EnvironmentAware {

    private lateinit var environment: Environment
    private lateinit var sample: Map<String, String>


    override fun setEnvironment(environment: Environment) {
        // EnvironmentAwareのメソッドをオーバーライド
        this.environment = environment
        // ここでspringのprofile別のコンフィグを読み分ける
        val binder = Binder.get(environment)

        this.sample = binder
                .bind("myconfig.sample", Bindable.mapOf(String::class.java, String::class.java))
                .orElseThrow { IllegalStateException() } // 読み込み失敗ならば例外、など
    }
}
  • Bindable.listOfとかBindable.mapOfとかが使えるので、型さえ合わせればいろいろ応用が利きそう