スターエンジニアになりたい

異世界転生を待って早10年

Spring Boot 設定ファイルの読み込み 2.4系以降のgroup化の方法

Spring Bootで設定ファイルの読み込み方が2.4系から変わっています。(今更ですが。。。)
と言っても、単純にapplication.yaml, application-dev.yamlなどと分けているような場合は無関係です。
「include」でプロパティファイルをさらに細かく分けていた場合は変わることになります。 やりたいことの変更点を具体的に言うと、spring.profiles.include から spring.profiles.group に変わってます。

2.3以前

spring:
  profiles:
    include:
      - common
      - external-local
      - mybatis-local

こんな感じで各設定をまとめておくと便利でした。spring強者の皆さまにおかれましてはお世話になっていた方も多いように思います。
2.4以降では使えないので、同じようなことをgroupを使用して実現します。
application.yamlにこうやってこうです。

2.4以降

spring:
  profiles:
    group:
      local:
        - common
        - external-local
        - mybatis-local
        - local
...

つまりgroupはどうすればいいかと言うと、「あるプロファイルが読み込まれたときに、一緒に読み込ませたいプロファイルをグループとして定義する」 だと考えるとシンプルだと思います。

ネット上では実例交えた記事が溢れていますが、当時ビシッとした分かりやすいものがなかった + 前の現場でも困っている人がいたようなので小ネタ記事にしました。(これを題材にしようと思っていたの1年以上前....自分ブログモチベどした...)


ひとりごと

ブログを書く気が全然起きないのです...w
しばらくはgithubオンリーでやっていこうと思ってます...。
githubリポジトリ作って、readmeとか書いてそれにプラスして、
説明するようなブログも書ける人本当に尊敬する....
せめてこういう小ネタ的なのをブログに投稿していきたい....

それではまた次回にお会いしましょう〜〜〜

再開。

いやあ...このブログも久しぶりすぎ....
一年以上放置してしもうた....
アクセス見たら意外と見られてて草w

言い訳としては、
仕事が忙しかったので放置してましたw

某スタートアップの新規開発にジョインしてリリースしたり、
某企業のtoBサービスの新規開発の案件(微熱を帯びていた...w)で奮闘したりしてました。 今は別の案件に入って割とゆったりやっています。

一年以上の疲労が溜まっていたので1ヶ月くらいゆっくりしたいなあと、2月は心身ともに休めました。 また何かしたいなあ〜という気持ちが出てきたので、まずはブログということでブログ再開。


本当に濃い約一年半でした....

本当に貴重な経験をさせていただいたと思います。
お世話になった方々、本当にありがとうございました。(見てないと思うけれども....)
スタートアップではN社長とかPMのK君とか、微熱ではYさんとかHさんとかOさんSさんとか...w

微熱案件ではマネジメントとかそういうところで悩んだり挫折もあったけれども、
人間として大きくなったというか、成長できたと思っています。

本当に周りの人に恵まれています....

要件決めから関わったスタートアップは本当に思い入れがあるし、
微熱の方ではアプリケーション開発側のメインのアーキテクト?としてやらせてもらえて本当に楽しかったです。
そこそこ大きい規模なのでやっぱり設計とかかなり悩んだりしたので、辛かったけど、
辛いけど楽しいみたいな感じでした。つらたのしい感じw

本当に色んなことがあって、ひと回りどころか20回りくらい成長できた気がしますw
いつか記事にしたいなあ...

しばらくは技術記事を投稿していく所存です。
(古くて微妙な記事は削除しました)

それではまた次回にお会いしましょう〜〜〜

DbUnit AmbiguousTableNameExceptionが発生 #9

こんにちは hkrblog です.
DbUnit使用時にエンカウントしたAmbiguousTableNameExceptionを解決したので
それを記していきたいと思います.
若干日が経っちゃってちょい曖昧気味...

状況整理 / 原因

まず自分の場合は、SpringBoot, DBはPostgreSQLですね.
状況としては、
* データベース内に同名のテーブルが存在してる
(つまり別スキーマに同名のテーブルが存在している)

基本的にはこの状況だと思います.
自分の場合は厄介だったのが、VIEW(ビュー)を作成していたということですね.
これ全然関係なくて、DbUnitは普通にテーブルを探しに行くのでビューは関係なし.
初動でもしかしてビューか!?と疑ったので若干時間無駄にしました.
話を戻すと原因は上記の同名のテーブルが存在しているということ.
DbUnitは内部でテーブル名をマップ(確か)に詰めていくんだけれども、
そこで同名のテーブルがくるとAmbiguousTableNameExceptionを発生させる.
(だった気がした..)

なので、どのschemaのどのtableなのか?をハッキリさせれば良い.
で自分の場合はエラー表示されるテーブル名が大文字だったのも気になった.
これ関係あったんだかなかったんだか忘れちゃったんだけど、
小文字のはずのテーブル名が大文字で認識できるはずはないということでその辺も設定をしました.


実施した解決方法

1. Configuration
@Configuration
public class DbUnitConfig {

    @Value("${dbunit.schema.name}")
    private String schema;

    @Bean
    public DatabaseConfigBean dbUnitDatabaseConfig() {
        DatabaseConfigBean bean = new DatabaseConfigBean();
        bean.setQualifiedTableNames(true);
        bean.setCaseSensitiveTableNames(true);
        return bean;
    }

    @Bean
    public DatabaseDataSourceConnectionFactoryBean dbUnitDatabaseConnection(
                     DataSource dataSource, DatabaseConfigBean dbUnitDatabaseConfig ) {
        DatabaseDataSourceConnectionFactoryBean bean = 
                     new DatabaseDataSourceConnectionFactoryBean();
        bean.setDataSource(dataSource);
        bean.setDatabaseConfig(dbUnitDatabaseConfig);
        bean.setSchema(schema);
        return bean;
    }

}

設定クラスはこんな感じ.(インデントとかの関係で見づらくなってたらすみません)
DatabaseConfigBeanの登録で大文字小文字の区別したりという感じで、
DatabaseDataSourceConnectionFactoryBeanでスキーマ名をセットしてあげてます.

2. ファイル名

あとは読み込むCSVファイルの名前をスキーマ名.テーブル名.csvに変更する
テストデータを入力したcsvファイルの名前を例えば,
myschemaのmytableにデータを投入したいなら(myschemaは上のクラスでセットしたschema名)
名前は、myschema.mytable.csv にします.


あとは実際に実行してみてください.
できましたね? ...ね!?ね!?

PostgresはOK!!この勢いで
Oracleも余裕じゃ~(Oracleも使用している)と思ったらNoSuchTableExceptionが発生して
発狂しかけたので次回はDbUnitの NoSuchTableExceptionの解決記事にしようかなと思います.

もしかしたらKotlin記事になるかもです...

それではまた次回にお会いしましょう~~~~~.

Pythonのデコレーターでメタプログラミング 【第3回】【動的に装飾】 #7

どうも hrkblog です.
久しぶりの更新になってしまった....
今回はデコレーターの最終回です.
デコレータで動的にデコレートしていきます.
早速コードを見ていきます..!!

# plus_arg() is injected into Foo
def plus_arg(self, a, b):
    return a + b


# minus_arg() is injected into Foo
def minus_arg(self, a, b):
    return a - b


def change_methods(new):
    if new.__name__ != '__new__':
        return new

    def __new__(cls, *args, **kws):
        # Add attributes
        cls.plus_arg = plus_arg
        cls.minus_arg = minus_arg

        # Delete attributes
        if hasattr(cls, 'say'):
            del cls.say
        return super(cls.__class__, cls).__new__(cls, *args, **kws)

    return __new__


class Foo(object):
    @change_methods
    def __new__():
        pass

    def say(self):
        print("Hi me:", self)


def main():
    foo = Foo()
    print('plus_arg : {}\nminus_arg : {}'.format(foo.plus_arg(1, 3), foo.minus_arg(1, 3)))

    try:
        print(foo.say())
    except AttributeError as ex:
        print('method say() has already been deleted.')
        print(ex)


if __name__ == '__main__':
    main()

まずは、mainから.

foo = Foo()
    print('plus_arg : {}\nminus_arg : {}'.format(foo.plus_arg(1, 3), foo.minus_arg(1, 3)))

    try:
        print(foo.say())
    except AttributeError as ex:
        print('method say() has already been deleted.')
        print(ex)

Fooのインスタンス生成 -> fooのplus_arg(1, 3)とfooのminus_arg(1, 3)を呼び出して
結果をそれぞれ出力してみてます.
そのあとfooのsay()メソッドを呼び出してプリントしてます.
そしてsay()がなければ'method say() has already been deleted'のメッセージをプリントすることにします.
ここだけだとなんのこっちゃて感じですね.

引数を足したり引いたりする単純なplus_arg()とminus_arg()が今回Fooに付け足すメソッドです.

# plus_arg() is injected into Foo
def plus_arg(self, a, b):
    return a + b


# minus_arg() is injected into Foo
def minus_arg(self, a, b):
    return a - b

クラスFooをみてみます.

class Foo:
    @change_methods
    def __new__():
        pass

    def say(self):
        print("Hi me:", self)

Fooは__new__にデコレーターをつけてます.
そして単純な出力をするメソッドsay()があります.
このいかにもな@change_methodsをみてみます.

def change_methods(new):
    if new.__name__ != '__new__':
        return new

    def __new__(cls, *args, **kws):
        # Add attributes
        cls.plus_arg = plus_arg
        cls.minus_arg = minus_arg

        # Delete attributes
        if hasattr(cls, 'say'):
            del cls.say
        return super(cls.__class__, cls).__new__(cls, *args, **kws)

    return __new__

普通のデコレーターですね.
引数の関数の名前が__new__ではないならそのままその返すようにしてます.
__new__だった場合は新しい__new__をあげるようにします.(new __new__じゃん...)
このnew __new__はクラスにplus_argとminus_argというattributeを付け足してます.
(__new__インスタンス生成時__init__の前に呼ばれます.)
そしてクラスにsayという属性があれば削除してしまいます.

実行結果は以下です.

plus_arg : 4
minus_arg : -2
method say() has already been deleted.
'Foo' object has no attribute 'say'

意外と簡単でしたね....?
いろんな使い道がありそうですが、
メタプログラミングってコードがカオスになりがちなんですよねw
(前に参画していた苦い記憶が蘇ってきたので今日はこの辺で......w)

今度はSpring Bootの記事でも書こうかなと思っていたり.....
Javaブロックチェーンの記事とかも書きたい.....

今回3部作にして思ったのは1回目を書くと続き書かなきゃ...となるんですが、
ちょっと日が経つと重荷になってじゃっかんめんどくさくなる...

なので次はその時書きたい記事にしたいと思います....
それではまた次回にお会いしましょう~~~~~~

Pythonのデコレーターでメタプログラミング 【第2回】【動的に装飾】 #6

どうも hkrblog です.
最近仕事が忙しく更新できませんでした....w(言い訳苦しい...)
今日は前回の続きの記事です.
まだメタプログラミングという感じはしないです.

デコレーターが関数の修飾(上書き)をすることができるなら、 デコレーター対象の関数の中身がない場合は関数自体を生やすことになるのではないか?
という発想ですね.
こう書くとちょっと馬鹿っぽいですねw

技術内容としては普通に デコレーターに引数を渡す というものです.
@デコレーターの関数シンタックスシュガーに引数を渡します.
コードを見ましょう...!!!

def argument_sayer(what):
    def _say(method):
        def _action(self, *args, **kws):
            print(what)
            return method(self, *args, **kws)

        return _action

    return _say


def create_pc(maker_name):
    class PC:
        @argument_sayer(maker_name)
        def display(self):
            pass

    return PC()


def main():
    pc1 = create_pc('DELL')
    pc2 = create_pc('ASUS')
    pc1.display()
    print('-------------')
    pc2.display()


if __name__ == '__main__':
    main()


"""
DELL
-------------
ASUS
"""

あ〜〜〜〜、、、これはメソッド生やしちゃってますねw
まず、メインなんですがcreate_pc('DELL')でPC作ってますね.
create_pc()はというと、シンプルに引数にメーカー名をとり、PCのインスタンスを作成する関数ですね.
pc1.display()で何かは分からないですが、PCインスタンスのdisplayメソッドを呼び出しましたね.
じゃあ、displayメソッドは何かというと、中身はないです....
しかし、デコレーターが付いてます.
このデコレーターは引数にメーカー名を取って、修飾します.
argument_sayer(what)こいつなんですが、何してるかというと、デコレーターの関数を作成してます.
なので_say()がデコレーターになります. で実際の処理の部分が_actionですね.
print(what)でメーカー名を出力する動きです.
PCクラスのdisplayメソッドは何もしないメソッドでしたが、無事デコレーターで処理を作成することができました.
パッっと見るとわからん...となるのですが、書いてみるとこんなものか.....という感じですね.

次回は最終回です!
また次回でお会いしましょう~~~

Pythonのデコレーターでメタプログラミング 【第1回】【動的に装飾】 #5

どうも hkrblog です.

昨日までの投稿内容がクソ雑魚wすぎたのか、あまりビューがないので
少しは誰かの役に立ちそうなPythonのデコレーターに関する記事を今日から3回に渡って書いていこうと思います.

デコレーターというと、メソッドに処理を加えるようなイメージがあると思います.
実際その解釈でOKだと思うんですが、
今シリーズの内容を超ざっくりいうと、メタプログラミングのような使い方もできます という記事です.

ただ、急に入ると変に難しく感じたりするので、第一回ではデコレーターのド基本の使い方を見ていこうと思います.
デコレーターなんて知ってるわ!!!!コラ!!!みたいな人はまずこの記事を見ないとは思うのですが、
第一回の対象読者ではないのでブラウザをそっと閉じてください...w
まずコードです.


def deco(func):
    def inner():
        print('before func')
        ret = func()
        print(ret + '!!!')
        print('after func')
    return inner


def sample():
    return 'Hello'


def main():
    # Original sample output
    print(sample())
    print('--------------')

    # Decorated sample output
    decorated = deco(sample)
    decorated()


if __name__ == '__main__':
    main()

仕事でpython使わなくなって久しいので、
デコレーターって実際どう書くんだったっけ?ってなって一旦これで思い出しましたw
危ない危ないw

まずmain()から見ていきます.
print(sample())sampleを呼び出し、出力してますね.
sample()はというとreturn 'Hello'するだけという簡単なメソッドです.

次が本題です.
doco(sample)sampleの関数オブジェクトを引数に、関数deco()を呼び出しました.
decoはというと、innerを返してます.(一旦funcは忘れて...)
innerは何かというと、内部関数innerの関数オブジェクトです.
で、その関数オブジェクトを変数decoratedにぶち込みます.
innerの関数オブジェクトなので、decorated()でinner()が呼ばれますね.
これでやっとsample()に話が戻ってきて、sampleはfuncなので、ret = func()ここで実行されました.

出力結果がこちらです.

Hello
--------------
before func
Hello!!!
after func

どうでしょうか、わかりましたでしょうか....?
ではまた次回#6、第2回 デコレーターでメソッドの中身を生やすでお会いしましょう.
さよなら~~~.

Pythonのメタプログラミング 入門 dynamically create class ! #4

どうも hkrblog です.

最近やたらと寒いですね.....

今日はpythonメタプログラミング入門と題して本当に触りの部分、
クラスを動的に作って、インスタンス生成して、メソッド呼び出すくらいのものです.
(やっぱりpythonだとコード短いし、パパパッて感じで書けてしまう感じがして
ブログとかに載せやすいからついついpython関連の記事になってしまう....w)
実際このコードは2, 3か月前に書いたものです...
まずはコードを載せてしまいます.

class Student:
    def __init__(self, student_id, name):
        self.student_id = student_id
        self.name = name

    def say_my_name(self):
        return "Hi I'm " + self.name


def student_init(self, student_id, name):
    self.student_id = student_id
    self.name = name


def say_my_name(self):
    return "Hi I'm " + self.name


def main():
    student_class = type('Student2', (), {'__init__': student_init,
                                          'say_my_name': say_my_name})
    student_a = Student(1, 'Alice')
    student_b = student_class(2, 'Mike')
    print(type(student_a), student_a.say_my_name())
    print(type(student_b), student_b.say_my_name())


if __name__ == '__main__':
    main()

type関数でクラスを作成します
main()のprint文print(type(student_a), student_a.say_my_name())でも使ってますが、普段良く使うあのtype関数です
type(classname, superclasses, attribute dict)こんな感じです.
つまり動的に作成したクラス名がStudent2です.(我ながらセンス0ですねw)

今回関数を定義してますが、ラムダが使えます.
'say_my_name': lambda self ~~~と書いてあげれば大丈夫です.

比較対象として、Studentクラスも作成してます.
実行結果は以下です.

<class '__main__.Student'> Hi I'm Alice
<class '__main__.Student2'> Hi I'm Mike

動的にStudent2クラスを作成して実行できました.

ではみなさん #5 でお会いしましょう.