java.lang.reflect.Type インスタンスを生成する方法

総称型orクラスを知りたい時、知らせたい時に java.lang.reflect.Type を伝える為の
Type インスタンスを生成する方法
Google guice を使用している前提で2通りある。

com.google.common.reflect.TypeToken

import com.google.common.reflect.TypeToken;
TypeToken.of(Integer.class).getType();

TypeToken は、guice の依存先である Google guava Android の common にある。
guava/android at master · google/guava · GitHub

com.google.inject.TypeLiteral

import com.google.inject.TypeLiteral;
TypeLiteral.get(Integer.class).getType();

TypeLiteral は、guice 本体のJARの中に含まれる。

Wicket Bootstrap navbar と pagenation

Wicket で、Bootstrap を採用して navbar と Wicket の DataView で描画するページング
Bootstrap の Pagenation にするようにした時、
デザイン作業中は問題ないのですが、
z-index の指定をしないと、 navbar のドロップメニューが Pagenation の下に隠れてしまいます。
f:id:posturan:20190326200641j:plain

これは困ります。
f:id:posturan:20190326200743j:plain
期待するのは、以下です。
f:id:posturan:20190326200841j:plain
HTML

<div>
   <nav class="navbar navbar-expand-lg navbar-dark bg-info">
      <a class="navbar-brand" href="#">Navbar</a>
      <button class="navbar-toggler" type="button"
 data-toggle="collapse"   data-target="#sample_Navbar"
 aria-controls="sample_Navbar" aria-expanded="false"
 aria-label="Toggle navigation">
         <span class="navbar-toggler-icon"></span>
      </button>
      <div id="sample_Navbar" class="collapse navbar-collapse">
         <ul class="navbar-nav mr-auto">
            <li class="nav-item active">
               <a class="nav-link" href="#">Home<span class="sr-only">(current)</span></a>
            </li>
            <li class="nav-item"><a class="nav-link" href="#">Link</a></li>
            <li class="nav-item dropdown">
               <aclass="nav-link dropdown-toggle" href="#" id="navbarDropdown"
                role="button" data-toggle="dropdown" aria-haspopup="true"
               aria-expanded="false"> Dropdown </a>
               <div class="dropdown-menu" aria-labelledby="navbarDropdown">
                  <a class="dropdown-item" href="#">Action 1</a> <a
                     class="dropdown-item" href="#">Action 2</a> <a
                     class="dropdown-item" href="#">Action 3</a> <a
                     class="dropdown-item" href="#">Action 4</a> <a
                     class="dropdown-item" href="#">Another action</a>
                  <div class="dropdown-divider"></div>
                  <a class="dropdown-item" href="#">Something else here</a>
               </div></li>
            <li class="nav-item"><a class="nav-link disabled" href="#"
                tabindex="-1" aria-disabled="true">Disabled</a></li>
         </ul>
         <form class="form-inline my-2 my-lg-0">
            <input class="form-control mr-sm-2" type="search"
               placeholder="Search" aria-label="Search">
            <button class="btn btn-outline-dark btn-sm" type="submit">Search</button>
         </form>
      </div>
   </nav>
</div>
<div wicket:id="paging" id="paging">
   <nav>
      <ul class="pagination">
         <li class="page-item">
            <a class="page-link" href="#" aria-label="Previous" disabled="disabled">
             <span aria-hidden="true">&laquo;</span>
             <span class="sr-only">Previous</span>
            </a>
         </li>
         <li class="page-item"><a class="page-link" href="#" disabled="disabled">1</a></li>
         <li class="page-item"><a class="page-link" href="#">2</a></li>
         <li class="page-item"><a class="page-link" href="#">4</a></li>
         <li class="page-item"><a class="page-link" href="#">5</a></li>
         <li class="page-item"><a class="page-link" href="#">6</a></li>
         <li class="page-item"><a class="page-link" href="#">7</a></li>
         <li class="page-item"><a class="page-link" href="#">8</a></li>
         <li class="page-item"><a class="page-link" href="#">9</a></li>
         <li class="page-item"><a class="page-link" href="#">10</a></li>
         <li class="page-item">
            <a class="page-link" href="#" aria-label="Next">
            <span aria-hidden="true">&raquo;</span>
            <span class="sr-only">Next</span>
            </a>
        </li>
      </ul>
   </nav>
</div>

対処していないCSS

.navbar a.dropdown-toggle:focus, .navbar a.dropdown-toggle:hover{
   color: #ffffff;
   background-color: #128091;
   box-shadow: 0 0 0 0.2rem rgba(227, 144, 169, 0.25);
}
.dropdown-item:active{
   color: #ffffff;
   background-color: #17a2b8;
}
.dropdown-item:hover{
   color: #ffffff;
   background-color: #17a2b8;
}

(解決方法)
navbar に、z-index: 1000; を指定します。
デフォルト z-index; 1000; だと思いますが敢えて明示的に指定する。

.navbar{
   z-index: 1000;
}

Pagenation の方を、z-index で低く、
確実に指定するので、!important まで付けます。

.pagination{
    z-index: 1 !important;
}

あるいは、Wicket ID と id 属性まで指定して pagination より
上位層の id="paging" につけても
良いでしょう。

#paging{
    z-index: 1 !important;
}

MalformedException の捕捉処理を書き易くする。

Google gson fromJson JsonParser で発生する JSON書式エラー、MalformedException の捕捉を
するとして、try~ctach 文の中に書いてもいいのですが、
1つのロジックで何回もJSON読込みの必要な処理があって、毎回 catch文の中で
MalformedException の捕捉を書くのはナンセンスです。
そこで、ラムダで宣言してcatch文の Exception を読み込ませるというのを作りました。

JsonMalformed check = JsonMalformed.of((l, c, p)->{
    System.out.println("line   = " + l );
    System.out.println("column = " + c );
    System.out.println("path   = " + p );
}, u->{
    System.out.println("unknown :" + u.getMessage() + " "+u.getClass().getName());
});
try{
   JsonReader reader	 = new JsonReader(new StringReader(str));
   new JsonParser().parse(reader);
}catch(Exception e){
  if (check.confirm(e)){
      // TODO 書式エラー以外のエラー
  }
}

malformedcatch · yipuran/yipuran-gsonhelper Wiki · GitHub

GitHub - yipuran/yipuran-gsonhelper: Google gson use library

JSONの書式チェック

Google gsonfromJson JsonParser 生成は、次のようなJSONであると

{
   "A": "12",
}

com.google.gson.JsonSyntaxException:
com.google.gson.stream.MalformedJsonException:
Expected name at line 3 column 2 path $.A

と例外を発生してくれます。

JSONテキストを事前にチェックする機能を考えた時、すぐに思いつくのが、、

JsonReader reader = new JsonReader(new StringReader(jsonstr));
try{
   new JsonParser().parse(reader);
}catch(JsonSyntaxException e){
   String causemessage = Optional.ofNullable(e.getCause())
   .filter(t->t instanceof MalformedJsonException).map(t->t.getMessage())
      .orElse("Unknown Error");
}

↑は、JSON文字列 jsonstr が NULL でなければ、想定どおり JsonSyntaxException で catch して動くのですが、
JsonParser で parse 対象が NULLだったり、try の中の状況によっては、これはダメです。

 .filter(t->t instanceof MalformedJsonException).

でいきなり限定しているのも好ましくないです。
そこで、以下のような static メソッドを用意します。

public static boolean parseFormat(String str, Consumer<String> malform
                                 , BiConsumer<Throwable, String> unknowns){
   try{
      JsonReader reader    = new JsonReader(new StringReader(str));
      new JsonParser().parse(reader);
      return true;
   }catch(JsonSyntaxException e){
      Throwable cause = e.getCause();
      if (cause==null){
         unknowns.accept(e, e.getMessage());
      }else if(cause instanceof MalformedJsonException){
         malform.accept(cause.getMessage());
      }else{
         unknowns.accept(cause, cause.getMessage());
      }
   }catch(Exception e){
      unknowns.accept(e, e.getMessage());
   }
   return false;
}

こうすれば、、

if (parseFormat(jsonstr, m->{
   // m = MalformException の getMessafe()
   // TODO 書式エラーの処理
}, (t, m)->{
   // t = MalformExceptionでない他の Throwable
   // m = t の getMessage()
   // TODO 読込エラーの処理
})){
   // JSON 文字列 jsonstr が書式で問題なく Gson fromJson を実行できる
}

と整理できます。
この static メソッドを使い回せるようにしたいと思います。

配列型に対するmybatis の TypeHandler よく使いそうなものを作った

先日書いた int[] → ArrayTypeHandler - Oboe吹きプログラマの黙示録
に刺激されて、String[ ] , LocalDate[ ] , LocalDateTime[ ] , double[ ] とのマッピング
もあるべきと思い、
GitHub - yipuran/yipuran-mybatis: mybatis used application
の方で公開しました。
簡単に使い方を書いたのが、
arraytypehandler · yipuran/yipuran-mybatis Wiki · GitHub

LocalDate は、java.sql.Date からデータ抽出
LocalDateTime は、java.sql.Timestamp からデータ抽出

ということになりました。
いずれも、org.apache.ibatis.type.BaseTypeHandler を継承して作成しています。
このコードを書いていて、

       Array array;
          :
      Timestamp[] ary = (Timestamp[])array.getArray();

こういう配列のキャストを書くのにすごく抵抗があったのですが、動作はします。

配列型を扱えるDBでないとなりませんが、これら Array TypeHandler が必要なことは滅多にないと思います。

int[] → ArrayTypeHandler

SQLクエリの結果から、int [ ]で受け取るための mybatis  ArrayTypeHandler

先日、PostgreSQL 再帰クエリの結果から、INTEGER型 配列を Integer[] で取得するものを
書きました。
oboe2uran.hatenablog.com

Integer [ ] ではなくて、やはり、int [ ] で取得したい場合のタイプハンドラは、以下のように用意します。

import java.sql.Array;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
/**
 * int[] → ArrayTypeHandler
 */
public class IntArrayTypeHandler extends BaseTypeHandler<int[]>{
   @Override
   public void setNonNullParameter(PreparedStatement ps, int i, int[] parameter, JdbcType jdbcType) throws SQLException{
      Connection conn = ps.getConnection();
      Object[] po = new Object[parameter.length];
      int x = 0;
      for(int p:parameter){
         po[x] = Integer.valueOf(p);
         x++;
      }
      Array array = conn.createArrayOf("integer", po);
      ps.setArray(i, array);
   }

   @Override
   public int[] getNullableResult(ResultSet rs, String columnName) throws SQLException{
      return getArray(rs.getArray(columnName));
   }

   @Override
   public int[] getNullableResult(ResultSet rs, int columnIndex) throws SQLException{
      return getArray(rs.getArray(columnIndex));
   }

   @Override
   public int[] getNullableResult(CallableStatement cs, int columnIndex) throws SQLException{
      return getArray(cs.getArray(columnIndex));
   }

   private int[] getArray(Array array){
      if (array==null){
         return null;
      }
      try{
         Object[] ary = (Object[])array.getArray();
         int[] rtn = new int[ary.length];
         int i = 0;
         for(Object o:ary){
            rtn[i] = Integer.valueOf(o==null ? "0" : o.toString());
            i++;
         }
         return rtn;
      }catch(Exception e){
      }
      return null;
   }
}

mybatis は、resultMap のタイプハンドラ定義したハンドラの getNullableResult(ResultSet rs, String columnName) を
呼び出すので、
この返却値が、int[] になるように BaseTypeHandler の継承を用意すればいいのです。

このハンドラをSQLMap で記述する resultMap の result typeHandler 属性で指定します。

<result column="aryid"   property="aryid"
     typeHandler="sample.IntArrayTypeHandler"
     jdbcType="INTEGER"  javaType="int" />

jdbcType="ARRAY" と書くべきなのかもしれませんが、INTEGER でも、NUMERIC でも
実際は動作します。
jdbcType、javaType、両方ともに省略しても動作します。

ヘッダ有りCSV をPython で読む時(メモ)

読出し → 行 row[1:] スライス for ~ in で処理する。

例)

name, point
A, 3
B, 2
C, 1
import csv
import codecs

with codecs.open('sampledata.csv', 'r', 'utf-8') as fp:
    reader = csv.reader(fp)
    row = [row for row in reader]
    for row in row[1:]:
        print("name=%s  point = %d" % (row[0], int(row[1])) )
name=A  point = 3
name=B  point = 2
name=C  point = 1