Wicket8 の LambdaModel の setter の書き方

Wicket8 になって登場した LambdaModel

IModel<T> LambdaModel.of(SerializableSupplier<T> getter, SerializableConsumer<T> setter

Pageクラスに変数とsetter/getter を用意すればメソッド参照で、

queue(new TextField<String>("item", LambdaModel.of(this::getItem, this::setItem) ));

と書けるわけだが、setter/getter を書かなければ、、、

queue(new TextField<String>("item", LambdaModel.of(()->item, t->item=t) ));

と書くことになり、これで良いかと思うと、、コンパイルが通らない!
「メソッド of(SerializableSupplier, SerializableConsumer) は型 LambdaModel であいまいです」
と怒られてしまう。

setter のところを、t->item=t ではなく、t->{item=t;}
以下のようにすればコンパイルも通り、きちんと動く

queue(new TextField<String>("item", LambdaModel.of(()->item, t->{item=t;} ) ));

Wicket8 の LambdaModel - Oboe吹きプログラマの黙示録

Java10 の Optional orElseThrowメソッド

元々、Java8 以降で、Optional get() を使うことは、Optional の目的、性質からしてあまりなかった。
Java10 になっても、get() は、Deprecated アノテーションはついてない。
https://bugs.openjdk.java.net/browse/JDK-8160606
と、OpenJDK でこの先、Deprecated がはっきり示されたのかというと、
https://bugs.openjdk.java.net/browse/JDK-8140281
で、ひっくり返ったみたい。
そこで、Java10 で登場したのが、orElseThrowメソッド
↓ これはよく説明されるコード、、

Optional<Integer> anyOddInStream = Stream.of(2, 4, 6, 8)
.filter(x->x % 2 == 1)
.findAny();
int value = anyOddInStream.orElseThrow();

orElseThrow() と書くと直感的に get() よりも値が取得できないリスクを見やすい。

「見た目」だけの話のような気もするけど、単純にそれで充分なのかも。。

orElseThrow() は、値が無い時、NoSuchElementException で、RuntimeException 系あることも注意点だ。

Optional.orElseThrow(Supplier<? extends X> exceptionSupplier)

という Supplier であることも、便利かも。

Java8 の頃の、、、

Optional<Object> item;
item.<Runnable>map(e->()->{ 
    // 存在する時の処理 
}).orElse(()->{
    // 存在しない時の処理
})
.run();

Java9 からの、、

Optional.ofNullable(object).ifPresentOrElse(e->{
   // NULLでない時の処理、Consumer
}, ()->{
   // NULL の時の Runnableメソッド
});

ClassNotFoundException WicketFilter

Eclipse 4.8 (Photon) 、Tomcat9 、Java10 、Wicket 8.0.0
で、Web起動しようとしたら、何か設定をミスったのか、抜けがあって、
ClassNotFoundException: org.apache.wicket.protocol.http.WicketFilter
で起動しない。

どうもMaven で環境作った WEB-INF/lib を読む設定が抜けてしまった。。
プロジェクトのプロパティ設定→デプロイメント・アセンブリ
WEB-INF/lib がパスから抜けている。

「追加」で 「Maven依存関係」を選択する。
これでOK
f:id:posturan:20180731144705j:plain

CSV書込み lineterminator の指定でハマる

import csv
csv.register_dialect("MyDialect", quoting=csv.QUOTE_ALL, lineterminator='\n')

と書いて、

with open("sample.csv", "w", encoding="utf-8") as f:
   w = csv.writer(f, "MyDialect")
   w.writerow(header_list)
   w.writerows(array_list)

と書いて実行したら、行区切りが、\r\n のままで、どうして?と困惑した。。

書込み先 OPEN で、newline="" の指定が抜けてる。
付けると期待どおりの 、行区切りが、\n になる。

with open("sample.csv", "w", encoding="utf-8", newline="") as f:
   w = csv.writer(f, "MyDialect")
   w.writerow(header_list)
   w.writerows(array_list)

でも、これは Windows PC で実行した時の話であって、

with open("sample.csv", "w") as f:

で、Linux では open は、newline や encoding の指定を書かない
=================================
ダブルクォート全て付ける

cf = csv.writer(f, quoting=csv.QUOTE_ALL)

ダブルクォートを必要に応じてつける

cf = csv.writer(f, quoting=csv.QUOTE_MINIMAL)

非数値なら、ダブルクォートでくくる

cf = csv.writer(f, quoting=csv.QUOTE_NONNUMERIC)

クォート括りなし

cf = csv.writer(f, quoting=csv.QUOTE_NONE)

=====================
あまりCSVでシングルクォートで括るということはしないが、
もしも、指定するなら、csv.writer で、
quotechar='\''

getResource から、配下の全てのファイルの操作

絶対の例外発生しないけど例外 throwable 宣言にメソッドを使用するのにわざわざ、try~catch ハンドリングを
書きたくなくて用意した、、、Throwable~ 関数型インターフェース
Throwable~ 関数型インターフェースを使う - Oboe吹きプログラマの黙示録
と、
FileCollection - Oboe吹きプログラマの黙示録

を組み合わせると、実行中のリソース配下のファイルを走査する処理を簡単に書けます。

まず、その前に簡単なコードの理解、、

URL url = ClassLoader.getSystemClassLoader().getResource("");

ここから、toURI() が、どうしても URISyntaxException の捕捉処理を必要としているので。。

File f = new File(Optional.of(ThrowableSupplier.to(()->url.toURI()).get()).get());

では、リソース配下のファイルを走査しましょう。

FileCollection fc = FileCollection.of(Optional.of(
      ThrowableSupplier.to(()->ClassLoader.getSystemClassLoader().getResource("").toURI()).get()
   ).get()
   .getPath()
);
fc.scan().stream().filter(e->e.isFile() && e.canRead())
.map(e->e.getAbsolutePath()).forEach(System.out::println);

.forEach(System.out::println); の代わりに実践の処理を書くことになると思います。
filter に書く Predicate も適時、仕様に沿った処理をすれば良いでしょう。

fc.scan().stream().filter(e->e.isFile() && e.canRead()).map(e->e.getAbsolutePath()).forEach(f->{
   // ファイルに対する処理
});

Properties 読込みを考え直す。

Java の Properties 、properties ファイル読込みは古くから存在して過去、
設定ファイル地獄で皆、苦しんだ歴史がある。そして、convention over configuration が提唱され
それでも日本の多くのシステム屋は、うまくバランスを持ってきたとは言い難い。。
properties ファイルの使用と保守は、完全に消滅することはないだろう。

properties ファイルを読むのに、直接 ResourceBundle で読む方法と、あくまでもファイルIOとして
Properties の load メソッドを使う方法、あるだろう。
それから、複数の properties ファイルがある場合に、どう読み込んで管理するとなると、
これもシステムによって様々な方法になってしまう。

直接 ResourceBundle で、読む方法
例えば、システムクラスローダのPATHが通ったとろで、
message.properties というファイルのプロパティを読む、(2バイト文字も読めるようにする)

ResourceBundle rs = ResourceBundle.getBundle("message", new ResourceBundle.Control(){
   @Override
   public ResourceBundle newBundle(String baseName, Locale locale, String format
, ClassLoader loader, boolean reload)
   throws IllegalAccessException, InstantiationException, IOException{
      try(InputStreamReader sr = new InputStreamReader(
      loader.getResourceAsStream(
toResourceName(toBundleName(baseName, locale), "properties")), "UTF-8");
BufferedReader reader = new BufferedReader(sr)
      ){
         return new PropertyResourceBundle(reader);
      }
   }
});

Properties p = new Properties();
for(String key : rs.keySet()){
   p.setProperty(key,rs.getString(key));
}

こんな感じになる。。。
そこで、今まで Properties の読込みはいくつも過去に書いてきたし整理したくもなり、
まとめた。。。
Properties · yipuran/yipuran-core Wiki · GitHub
このライブラリを使用して、、、
実践的には、Properties 読込み使用の処理を書いていくので、、、
サンプルとしては、、、

import java.util.Properties;
import javax.inject.Inject;
import org.yipuran.env.PropertyInject;

public class Logic{
   @Inject @PropertyInject private Properties prop;
   
   public Properties getProperties(){
      return prop;
   }
}

という、PropertyInject アノテーションで指定する Properties へのインジェクションを

import org.yipuran.env.PropertyBindModule;
import com.google.inject.Guice;
import com.google.inject.Injector;
Injector injector = Guice.createInjector(new PropertyBindModule("message"));
Logic logic = injector.getInstance(Logic.class);

Properties p = logic.getProperties();

この PropertyBindModule で、message.properties に結びつくように、簡潔にするように
yipuran-core ライブラリが提供する処理で実装している

さらに、複数の properties ファイルが存在するケースへの対応を考えて、、

public interface MLogic{
   public String getValue(String key);
}
import java.util.Optional;
import java.util.Properties;
import javax.inject.Inject;
import org.yipuran.env.PropertyInject;

public class LogicImpl implements MLogic{
   @Inject @PropertyInject("aaa") private Properties propA
   @Inject @PropertyInject("bbb") private Properties propB;

   @Override
   public String getValue(String key){
      return Optional.ofNullable(propA.getProperty(key)).orElse( propB.getProperty(key, "not value" ) );
   }
}

これで、aaa.properties と bbb.properties 両方を読み込み、aaa.properties に存在しなかったら、
bbb.properties の方の値を探して返す。
という対応をする。

import org.yipuran.env.PropertyBindModule;
import com.google.inject.Guice;
import com.google.inject.Injector;
Injector injector = Guice.createInjector(new PropertyBindModule());
MLogic logic = injector.getInstance(LogicImpl.class);

logic.getValue(key) で Properties の 値を取得

Python で今月の日数分のループ

メモ書き。。。

# -*- coding: utf-8 -*-
import datetime
import calendar

today = datetime.datetime.today()
for ix in range(calendar.monthrange(today.year, today.month)[1]):
    d = datetime.datetime(today.year, today.month, (ix+1))
    print(d)