tokuhirom's blog

適当に JDBC でデータとってきてダンプするスニペット

生JDBCで適当にデータ出してデバッグしたいって時につかうやつです。

    protected void selectAndPrint(Connection connection, String query) {
        log.info("======> dumpTable: {} <====", query);
        try (PreparedStatement preparedStatement = connection.prepareStatement(query)) {
            try (ResultSet rs = preparedStatement.executeQuery()) {
                ResultSetMetaData metaData = rs.getMetaData();
                log.info("| {} |", IntStream.range(0, metaData.getColumnCount())
                                            .mapToObj(i -> {
                                                try {
                                                    return metaData.getColumnName(i + 1);
                                                } catch (SQLException e) {
                                                    throw new RuntimeException(e);
                                                }
                                            }).collect(Collectors.joining(" | ")));
                while (rs.next()) {
                    log.info("| {} |", IntStream.range(0, metaData.getColumnCount())
                                                .mapToObj(i -> {
                                                    try {
                                                        return rs.getString(i + 1);
                                                    } catch (SQLException e) {
                                                        throw new RuntimeException(e);
                                                    }
                                                }).collect(Collectors.joining(" | ")));
                }
            }
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }
Created: 2020-06-26 18:49:46 +0900
Updated: 2020-06-26 18:49:46 +0900

Swift で Foundation の data をバイト列で初期化したい

Data([0xDE, 0xAD, 0xBE, 0xEF]) こんな感じ。Data とか、一般的な名前すぎてググってもなんか見つけにくい。

Created: 2020-06-18 10:39:21 +0900
Updated: 2020-06-18 10:39:21 +0900

thrift compiler のバイナリを static build したい

http://archive.apache.org/dist/thrift/ からダウンロードする。

https://stackoverflow.com/questions/20068947/how-to-static-link-linux-software-that-uses-configure

linux の場合

sudo yum install glibc-static -y
./configure --enable-static --without-ruby --without-nodejs --without-php --without-python --without-c_glib --without-go --without-nodejs --without-lua CFLAGS="-static"
make -j9 LDFLAGS="-all-static"

osx の場合

osx では static build ができないので諦める。

brew install bison
export PATH="/usr/local/opt/bison/bin:$PATH"
export LDFLAGS="-L/usr/local/opt/bison/lib"
./configure --without-ruby --without-nodejs --without-php --without-python --without-c_glib --without-go --without-nodejs --without-lua
make -j 9
Created: 2020-06-17 18:58:44 +0900
Updated: 2020-06-17 18:58:44 +0900

[C#] C# で byte 列を16進数に変換したい

https://stackoverflow.com/questions/623104/byte-to-hex-string

の通りにやればいい。

byte[] data = { 1, 2, 4, 8, 16, 32 };
string hex = BitConverter.ToString(data);

// Result: 01-02-04-08-10-20

標準ライブラリでこういう表現できるのは便利だなーという感想。

Created: 2020-06-12 23:41:06 +0900
Updated: 2020-06-12 23:41:06 +0900

Gradle の dependency locking について

昔の gradle には dependency locking 機能がなかった。ビルドするタイミングによって、別の依存モジュールが利用されたりしていた。。 最近、gradle に dependency locking 機能がついたので試してみた。 carton.lock とか package-lock.json とか、そういうのと同じようなことができるようになる。 同じレポジトリからビルドしたら同じ jar が生成されるようになる。便利。

dependency locking を利用すると gradle.lockfile というファイルが生成される。

デフォルトだとフェーズ単位でファイルが生成されるから enableFeaturePreview('ONE_LOCKFILE_PER_PROJECT') を settings.gradle に書いて1ファイルにまとめるようにしたほうが良い。gradle 7.0 ではこの方式がデフォルトになる予定なので、最初からこの feature flag は enabled にしたほうが良いです。管理上も、そのほうが便利。

  • ./gradlew dependencies --write-locks ってするとロックファイルが書かれる
  • ./gradlew classes --update-locks org.apache.commons:commons-lang3,org.slf4j:slf4j-api とかで特定のモジュールだけアップデートできる

たぶんもう普通に使えるけど、まだ開発途中って感じはする。./gradlew dependencies してもサブプロジェクトのぶんを一括で作れない、とか。。

↓実際に line-bot-sdk-java を利用して試しに生成してみたやつがこれ。 https://github.com/tokuhirom/line-bot-sdk-java/commit/08a53ed86eedcf1072e7c12e77d7e1777f54c933

Created: 2020-05-13 10:00:39 +0900
Updated: 2020-05-13 10:00:39 +0900

PowerShell に git branch 情報を表示する

https://github.com/dahlbyk/posh-git

を利用すればいい。https://www.powershellgallery.com/packages/posh-git/1.0.0-beta4 PowerShell gallery からインストールすればいいです。

profile.ps1 に以下のように設定した。

Import-Module posh-git

function prompt {
    $prompt = & $GitPromptScriptBlock
    if ($prompt) { "$prompt " } else { " " }
}

$global:GitPromptSettings.DefaultPromptAbbreviateHomeDirectory = $true
$global:GitPromptSettings.EnableFileStatus = $false
Created: 2020-03-20 23:20:33 +0900
Updated: 2020-03-20 23:20:33 +0900

jacoco で lombok で生成されたコードを無視したい

Created: 2020-03-07 09:06:53 +0900
Updated: 2020-03-07 09:06:53 +0900

/actuator/configprops で kotlin の @ConfigurationProperties つけてるビーンが出ないよってとき

configprops は constructor の引数を見ている。何も指定しないと java と同じく arg0 とかになって acutuator で設定が見れない。

↓gradle の場合は以下のようにオプションを指定しよう。

            compileKotlin {
                kotlinOptions {
                    jvmTarget = "1.8"
                    allWarningsAsErrors = true
                    javaParameters = true // ←これ!
                }
            }
Created: 2020-02-27 15:43:49 +0900
Updated: 2020-02-27 15:43:49 +0900

NullPointerException の stacktrace が出ないケース

https://stackoverflow.com/questions/2411487/nullpointerexception-in-java-with-no-stacktrace https://stackoverflow.com/questions/4659151/recurring-exception-without-a-stack-trace-how-to-reset

hotspot だと最適化の都合で、出ないケースがあるらしい。

-XX:-OmitStackTraceInFastThrow を入れると全部出るようになるが、パフォーマンスに若干の影響があるのかな。試してない。

→ パフォーマンスはあんま問題なさそうだが、ディスク溢れないように気をつけよう、という識者の意見。

Created: 2020-02-27 10:30:43 +0900
Updated: 2020-02-27 10:30:43 +0900

Skitch が catalina で使えなくなったので頑張って OSX のスクショ機能を使っていた

OSX のスクショ機能なんであんな使いにくいの。。モーダルにしなくてよくない?? って苦しんでたけど、

↓これで skitch をまた使えるようになった。安心。 https://neko11.com/macos-catalina%E3%81%AB%E3%81%97%E3%81%A6%E3%81%8B%E3%82%89skitch%E3%81%A7%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%BC%E3%83%B3%E3%82%B7%E3%83%A7%E3%83%83%E3%83%88%E3%81%A7%E3%81%8D%E3%81%AA%E3%81%8F%E3%81%AA/

Created: 2020-02-26 09:13:10 +0900
Updated: 2020-02-26 09:13:10 +0900

compressed oops

https://blog.tiqwab.com/2019/07/21/openjdk-oop.html http://itdoc.hitachi.co.jp/manuals/link/cosmi_v0970/03Y1660D/EY160244.HTM https://www.baeldung.com/jvm-compressed-oops

Created: 2020-01-29 11:32:29 +0900
Updated: 2020-01-29 11:32:29 +0900

cloc みたいな行数適当に数える奴

#!/usr/bin/env perl
use strict;

&main; exit;

sub main {
    my %white = map { $_ => 1 } qw/
        kt java pl js rb py
    /;

    my %result;

    for my $file (split /\n/, `git ls-files`) {
        my ($ext,) = ($file =~ m{\.([^./_-]{1,4}$)});
        $ext //= '-';
        my $lines = do {
            open my $fh, '<', $file;
            my $n = 0;
            $n++ while <$fh>;
            close $fh;
            $n;
        };
        $result{$ext} += $lines;
    }

    my $total = 0;
    for my $ext (sort { $result{$a} <=> $result{$b} } keys %result) {
        if (%white) {
            next unless $white{$ext};
        }

        my $r = $result{$ext};
        printf("%5s %10s\n", $ext, commify($r));
        $total += $r;
    }
    print "\n";
    printf("%5s %10s\n", "Total", commify($total));
}

sub commify {
    local $_ = shift;
    1 while s/^([-+]?\d+)(\d{3})/$1,$2/;
    return $_;
}

Created: 2020-01-25 08:11:20 +0900
Updated: 2020-01-25 08:11:20 +0900

[kotlin] lateinit が初期化されてるか確認する

lateinit var foo: String である時に、lateinit 変数が初期化ずみか調べるには ::foo.isInitialized とすると良い

Created: 2020-01-11 10:18:34 +0900
Updated: 2020-01-11 10:18:34 +0900

mysql 8.0.17 から 8.0.19 までは member は予約語

MEMBER; added in 8.0.17 (reserved); became nonreserved in 8.0.19

Created: 2020-01-10 00:07:49 +0900
Updated: 2020-01-10 00:07:49 +0900

レポジトリの中に含まれる kotlin/java ファイル数を歴史込みで集計する

TSV が出るので、出たら tableau とかで集計する。

# XXX git checkout --force するんで手元がぶっ壊れるので注意してね! XXX
import subprocess
import os
from datetime import datetime, timedelta, date


print("ago\tlanguage\tfiles\tlines")

subprocess.run(['git', 'stash', '--quiet'])
subprocess.run(['git', 'checkout', '--quiet', 'master'])

for ago in range(1, 500, 10):
    cmd = '''git log --before '%d day ago' -n 1 --oneline "--format=format:%%H %%aI" | sed -e "s/T.*//" ''' % ago
    res = subprocess.run(['/bin/sh', '-c', cmd], capture_output=True)
    splitted = res.stdout.decode().rstrip().split(' ')
    commit = splitted[0]
    date = splitted[1]
    subprocess.run(['git', 'checkout', '--force', '--quiet', commit])

    kotlin_cnt = 0
    kotlin_lines = 0
    java_cnt = 0
    java_lines = 0
    for dirName, subdirList, fileList in os.walk('.'):
        for fname in fileList:
            if fname.endswith('.kt'):
                kotlin_cnt += 1
                kotlin_lines += sum(1 for line in open(f"{dirName}/{fname}"))
            elif fname.endswith('.java'):
                java_cnt += 1
                java_lines += sum(1 for line in open(f"{dirName}/{fname}"))

    print(f"{date}\tkotlin\t{kotlin_cnt}\t{kotlin_lines}")
    print(f"{date}\tjava\t{java_cnt}\t{java_lines}")
Created: 2019-12-12 15:56:49 +0900
Updated: 2019-12-12 15:56:49 +0900

mutable なクラスがどのぐらい DI 対象になってるか調べたい

BeanPostProcessor で探せる。

import org.springframework.beans.factory.config.BeanPostProcessor
import org.springframework.context.annotation.Profile
import org.springframework.stereotype.Component
import java.lang.reflect.Modifier

@Component
@Profile("!real")
class MyProcessor : BeanPostProcessor {
    override fun postProcessAfterInitialization(bean: Any, beanName: String): Any? {
        val fields = bean.javaClass.declaredFields
        val packageName = bean.javaClass.packageName
        if ((!packageName.startsWith("org.springframework"))
            && fields.filter { !Modifier.isFinal(it.modifiers) }.count() > 0) {
            println("$bean has mutable field.")
        }
        return bean;
    }
}
Created: 2019-12-10 15:57:28 +0900
Updated: 2019-12-10 15:57:28 +0900

[spring] @Configuration と @Component は違う、あるいは @Bean lite mode について

Spring の @Configuration は @Component の stereotype だと思っていたが、挙動が違うとのこと。

https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/context/annotation/Bean.html

@Bean Lite Mode というものがあって、@Component を利用すると CGLIB proxy を利用した aspect 系の処理が動かないらしい。

https://github.com/spring-projects/spring-framework/issues/14061

歴史を振り返ると、spring 3 の頃にバグ報告されたから lite mode ということにしたようにもみえる(深追いしてない)。

(全く知らなくてまつださんに教えてもらった)


【20191123 追記】

Spring framework 5.2 以後では、@Configuration(proxyBeanMethods=false) と書けるようになっているから、これを利用するのが良さそう(意図が明確なので)。

Created: 2019-11-19 10:22:12 +0900
Updated: 2019-11-19 10:22:12 +0900

Spring framework 5.2 以後=Spring Boot 2.2 以後では WebClient のレスポンスの取り扱いが便利になっている件

https://twitter.com/making/status/1192216994147270656?s=20

WebClient からの response status などを取得しやすくなっている。 便利。

    val logger = LoggerFactory.getLogger(WebfluxSampleApplication::class.java)

    val url = "http://example.com/"

    val webClient = WebClient.builder()
            .build()
    val entityMono = webClient.get().uri("http://example.com/")
            .retrieve()
            .toEntity(String::class.java)

    logger.info("Sent http request. url=$url")

    val entity = entityMono.block()!!

    if (entity.statusCode.is2xxSuccessful) {
        val body = entity.body
        logger.info("HTTP request succeeded. url=$url status=${entity.statusCodeValue} length=${body?.length}")

        // process response data...
        println(body)
    } else {
        logger.info("HTTP request failed. url=$url status=${entity.statusCodeValue} body=${entity.body}")
    }
Created: 2019-11-07 08:58:18 +0900
Updated: 2019-11-07 08:58:18 +0900

assertj 3.12.0 の breaking change がエグい

Iterator<Foo> fooIterable = getFooIterable();
assertThat(fooIterable)
    .extracting(Foo::getId)
    .isEqualTo(List.of(1,2))

みたいな書き方だったのが

Iterator<Foo> fooIterable = getFooIterable();
assertThat(fooIterable)
    .toIterable()
    .extracting(Foo::getId)
    .isEqualTo(List.of(1,2))

と書かなくてはいけなくなった。

該当のコミットはこれ。

https://github.com/joel-costigliola/assertj-core/commit/acafa142aa903afd611de812576e6e80e12e7964#diff-71630712302645dfc9a55762045740e6

もとのメソッドを Deprecated にして一旦置いといても良かったように思うのだが。。

Created: 2019-10-31 00:32:13 +0900
Updated: 2019-10-31 00:32:13 +0900

`ClassLoader#getResources("")` の返り値が Java9 以後は jar:file: も含むようになっている

package com.example;

public class Example {
    public static void main(String[] args) throws java.io.IOException {
        System.err.println("JVM: " + java.lang.management.ManagementFactory.getRuntimeMXBean().getVmVersion());

        ClassLoader classLoader = Example.class.getClassLoader();
        System.out.println(classLoader);

        java.util.Enumeration<java.net.URL> resources = classLoader.getResources("");
        while (resources.hasMoreElements()) {
            System.out.println("-- " + resources.nextElement());
        }
    }
}

このようなプログラムの実行結果が、Java 9 以後では異なる。

Run with Java 8

JVM: 25.201-b09
sun.misc.Launcher$AppClassLoader@2a139a55
-- file:/Users/tokuhirom/work/urlclassloader-behavoiour/build/classes/java/main/

https://docs.oracle.com/javase/8/docs/api/java/lang/ClassLoader.html#getResources-java.lang.String-

Run with Java 11

JVM: 11.0.1+13-LTS
jdk.internal.loader.ClassLoaders$AppClassLoader@799f7e29
-- file:/Users/tokuhirom/work/urlclassloader-behavoiour/build/classes/java/main/
-- jar:file:/Users/tokuhirom/.gradle/caches/modules-2/files-2.1/net.bytebuddy/byte-buddy-agent/1.10.2/fbfe9bf099287c35b8336ea9da194f301a112a11/byte-buddy-agent-1.10.2.jar!/META-INF/versions/9/

https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/ClassLoader.html#getResources(java.lang.String)

こんな感じ。

Created: 2019-10-29 14:58:57 +0900
Updated: 2019-10-29 14:58:57 +0900

【解決済み】 Boot 2.2 で AbstractRoutingDataSource しかない場合にアプリケーションが起動しない問題について

https://github.com/spring-projects/spring-boot/issues/18661

Boot 2.2 で scan 対象に AbstractRoutingDataSource しかない場合に、アプリケーションが起動しないという問題を見つけたので報告したところ、シュッと対応してくれた。 次回のリリースで治る見込み。

https://github.com/spring-projects/spring-boot/commit/c5138c56ff4c4fa7ec6c4ff2823e2b86bc7e0ef1

待てない人は、management.health.db.enabled=false を設定すれば良いとのこと。

ただ、本来は AbstractRoutingDataSource の先の DataSource がある場合はそれを DI 対象にしておくのが良いです。

Created: 2019-10-24 08:09:00 +0900
Updated: 2019-10-24 08:09:00 +0900
Next page