System.out を close したと騙して再利用する。

try-with-resources 文で、PrintWriter pw = new PrintWriter(System.out) を書いて、
try-with-resources文の finally を実行した後ろで、System.out.print を実行しても
既に close しているのだから、print / println は機能しない。

でも、再度、System.out.print . System.out.println が働くようにする方法がある。

java - System.out closed? Can I reopen it? - Stack Overflow

この方法を見て思わず唸ってしまった。

import java.io.FilterOutputStream;
import java.io.IOException;
import java.io.OutputStream;

public class UnclosableOutputStream extends FilterOutputStream {
   public UnclosableOutputStream(OutputStream out) {
      super(out);
   }
   @Override
   public void close() throws IOException {
      out.flush();
   }
}

という、FilterOutputStream 継承して、close() のオーバライドで、flush を代わりに実行する方法だ。

PrintWriter pw = new PrintWriter(new UnclosableOutputStream(System.out));
pw.print(body);
pw.close();

System.out.println("test");

見事に、body を標準出力して close() 実行を見せかけて、次に "test" を標準出力する。

Gsonで未整形JSON を人が見やすいように整形する。

Google gson の JsonWriter の seyIndent の方法ではなく、gson インスタンスを生成する前の
GsonBuilder で、setPrettyPrinting を実行する方法、

既に存在するJSON 文字列から、整形する場合。

文字列→整形した文字列

String json = "{\"a\":\"A\",\"b\":[10,11,12], \"c\":{\"d\":\"e\",\"f\":null}}";

String body = new GsonBuilder().serializeNulls().setPrettyPrinting().create()
              .toJson(JsonParser.parseString(json));

body を標準出力すると

{
  "a": "A",
  "b": [
    10,
    11,
    12
  ],
  "c": {
    "d": "e",
    "f": null
  }
}

これは、JsonParser.parseString が、Google gson の JsonElement を求めるのを利用して
gson の toJson で整形文字列を求める方法である。

JsonParser には、parseReader(Reader reader)  つまり、Java.io.Reader から同じように JsonElement を求める
static メソッドもあり、
toJson も、public void toJson(JsonElement jsonElement, Appendable writer)

Appendable writer つまり、
FileWriter, OutputStreamWriter, PipedWriter, PrintStream, PrintWriter, StringBuffer, StringBuilder, StringWriter, Writer
を指定できるので、
未整形JSONを読込む Reader から、整形して、Wrtier に書込みということが、
この JsonParser → JsonElement → gson toJson → 整形済JSON
出力できるということである。

JSON path 指定して部分的にプリントする。

yipuran-gsonhelper/JSonValue.java at master · yipuran/yipuran-gsonhelper · GitHub

を使用して、プリントする

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import org.yipuran.gsonhelper.JSonValue;
try(InputStream in = new FileInputStream("sample.json");
   ByteArrayOutputStream bo = new ByteArrayOutputStream()){
   
   JSonValue jsonvalue = new JSonValue(new InputStreamReader(in, StandardCharsets.UTF_8));
   jsonvalue je = jsonvalue.get("aaa.bbb.ccc");

   try(ByteArrayOutputStream bo = new ByteArrayOutputStream()){
      
      JsonWriter writer = new JsonWriter(new PrintWriter(bo));
      Gson gson = new GsonBuilder().serializeNulls().setPrettyPrinting().create();
      gson.toJson(je, writer);
      writer.flush();
      
      // JSON path "aaa.bbb.ccc" が指すオブジェクトを文字列化
      String result = bo.toString();

   }catch(IOException e){
      e.printStackTrace();
   }
}catch(Exception e){
   e.printStackTrace();
}

目的の String result を求めることができる。

JsonPattern バリデーションチェックの強化

https://json-schema.org/ が示す JSOMスキーマによるバリデーションチェックは、
わざわざ、スキーマ記述ルールで書いたスキーマのJSONを用意して、
バリデーションチェックを実行する。→ 記述ルールを憶えるのが面倒くさい。

書式サンプルなるJSONがあってそのサンプルが示すようにバリデーションチェックができれば良いのであって、
JSONスキーマなるデータ記述の規則をわざわざ書くなどは、管理の面でも賛成できない。

中途半端ではあるが、前に、GitHub - yipuran/yipuran-gsonhelper: Google gson use library
の中で、JsonPattern というのを書いていて、
必須有無の簡単なレベルでのチェックをするのを書いていた。
思い直して、もっときちんとサンプルJSONと、追加メソッドだけでバリデーションチェックが
できるようにと以下の点を強化した。

  • 書式のサンプルJSONで書いたもの対して省略可能を指定できるようにすること。
  • 正規表現によるチェックをバリデーション実行時に働かせるように、正規表現を追加するメソッド
  • 数値の場合、最小値、最大値チェックを バリデーション実行時に働かせるように、追加するメソッド

https://github.com/yipuran/yipuran-gsonhelper/blob/master/src/main/java/org/yipuran/gsonhelper/JsonPattern.java

yipuran-gsonhelper Version 4.18  である。

Arctic Code Vault Contributor

自分が書いたプログラムコードを置いた Git-hub で、

Arctic Code Vault Contributor

なる、星形のマークがついている。

北極点の保管庫送りだと!、馬鹿にしてるのか讃えてるのか、わけわからん。。。

archiveprogram.github.com

Generate a JSON schema using Jython !?

JSON schema の Draft 7 JSON Schema Draft-07 Release Notes | JSON Schema
に沿ったバリデータを探していて、
JSON schema を生成するのに、Python でというのは、よくあるアーキテクトと思うが、、
今更、Jython ?。。。天下のOracle のページで目にしたのが、
https://docs.oracle.com/cd/E65459_01/dev.1112/e65461/content/content_schema_json.html

2020年3月にリリース進んでたのか。。。
https://www.jython.org/news

Jython 速くなったのかな?

YAML 配列を読込む場合のルール

昨日書いた YAML に追加で、、、
 https://oboe2uran.hatenablog.com/entry/2020/07/24/124904
以下のように、clist  キーに配列がある場合、

address:
  group:
    info1: A
    info2: 120
  clist:
    - 21
    - 22
    - 23
aaa:
  bbb: ABC

この clist を読むための List を、@Value アノテーションで指定できるかと思ったら、
どうしてもできない。
次のように、あくまでも、clist の上のキーを prefix にした @ConfigurationProperties
付与したクラス定義の元、同じ名称の List フィールドでしか読めず、
更に、List 宣言で初期化までやらないとならない。

@Value{"${address.clist}") というアノテーションを付与した List で読むというのは、
SpringBoot ではできないのである。

以下のように、しないとならない。

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
 * Setting
 */
@ConfigurationProperties(prefix="address")
@Component
public class Setting{
   public Map<String, Object> group;

   @Value("${aaa.bbb}")
   public String name;

   private List<Integer> clist = new ArrayList<>();

   public List<Integer> getClist(){
      return clist;
   }

   public void setGroup(Map<String, Object> m) {
      group = m;
   }
   public Map<String, Object> getGroup(){
      return group;
   }
}

@Value を書かせたり、書くとダメだったり、こういう辻褄の合わないところが、
Spring が嫌いなところだ。

Spring 信仰者からは、辻褄が合わないんじゃなくて、
いやそれはこうい理由だと提示されるかもしれないけど。。。