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
configprops は constructor の引数を見ている。何も指定しないと java と同じく arg0 とかになって acutuator で設定が見れない。
↓gradle の場合は以下のようにオプションを指定しよう。
compileKotlin {
kotlinOptions {
jvmTarget = "1.8"
allWarningsAsErrors = true
javaParameters = true // ←これ!
}
}
#!/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 $_;
}
lateinit var foo: String
である時に、lateinit 変数が初期化ずみか調べるには ::foo.isInitialized
とすると良い
MEMBER; added in 8.0.17 (reserved); became nonreserved in 8.0.19
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}")
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;
}
}
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)
と書けるようになっているから、これを利用するのが良さそう(意図が明確なので)。
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}")
}
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 にして一旦置いといても良かったように思うのだが。。
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)
こんな感じ。
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 対象にしておくのが良いです。
ざっくりいうと
Jackson 2.10 は Jackson 3 のインターフェースを含みつつ 2 系の旧インターフェースを新インターフェースを @Deprecated
扱いで含んだリリース
Spring Boot 2.2 は Jackson 2.10 に依存している
Boot 2.2 にした段階で、Deprecation Warnings でまくるからシュッと Jackson 3 にしたほうが良さそう。
Jackson 2.10 features - @cowtowncoder - Medium を参考のこと。
Jackson 2.10 は、Jackson 3 に向けての Migration 用のリリースになっている。2.9までのインターフェースも @Deprecated
状態で残しつつ、3以後のあたらしいインターフェースも実装されている。今のうちに新しいインターフェースに移行しておくと後々楽になる、と思う。
(Spring Boot 2.2 は Jackson 2.10 に依存している)
2.10 では以下の3つのメジャーなイシューを解決している。
デシリアライズ時におけるセキュリティイシューの根本解決
3.0 における新しいインターフェースへの移行促進
module-info.class 関連
で、1 はまあいいとして、2 が重要だなと思っている。新しいインターフェースがどういうものかというと以下のような感じ。
Builder Pattern ベースになっている
特定のフォーマット固有のオプションとそうじゃないものの分離
の2点が新しいインターフェースの特徴。mutable な deserializer とか、最近は流行らないからね。
Jackson 3.0 以後では ObjectMapper は configuration 系のメソッドは持たない。
Spring Framework 5.2 がリリースされた。
Support for Kotlin Coroutines.
も大きいのだが、、個人的には以下に注目したい。
Refinements to WebClient API to make the retrieve() method useful for most common cases, specifically adding the ability to retrieve status and headers and addition to the body. The exchange() method is only for genuinely advanced cases, and when using it, applications can now rely on ClientResponse#createException to simplify selective handling of exceptions.
これまで、Webclient を利用した場合、.retreive().bodyToMono(String.class)
などとして response body のみを取得するメソッドしかなく、異常に使いづらかった。
HTTP Status Code が 2xx 以外の場合には例外が上がる設計になっているのはいいのだが、現実的にはどの HTTP Status Code かは例外ではなく通常の処理としてハンドリングしたいというケースも多いのである。
Spring Framework 5.2 以後では以下のように記述可能になった。
WebClient client = WebClient.create();
Mono<ResponseEntity<String>> responseEntityMono = client.get()
.uri(url)
.retrieve()
.toEntity(String.class);
ResponseEntity<String> responseEntity = responseEntityMono.block();
assert responseEntity != null;
log.info("url={} status={} headers={} body={}",
url,
responseEntity.getStatusCodeValue(),
responseEntity.getHeaders(),
responseEntity.getBody());
便利。
from datetime import datetime, timedelta
def to_jst(src):
return str(datetime.strptime(src, '%d %b %Y %H:%M:%S %Z') + timedelta(hours=9)) + " JST"
print(to_jst('26 Sep 2019 03:56:25 GMT'))
依存とかなしでやる。
select text from table where dt='20190911' and text rlike '[\\uD800-\\uDFFF]'
とかでとりあえず良さそう。