ラベル Java の投稿を表示しています。 すべての投稿を表示
ラベル Java の投稿を表示しています。 すべての投稿を表示

2016年8月1日月曜日

POIで絵文字を出力するためのハック

この記事では、POIを使ってExcel(xlsx)ファイルへ絵文字を出力するためのハックを紹介します。
「ハック」と表現したように、あまりお行儀のいい方法ではないと思っているので、もっとスマートな方法を御存知でしたらコメントなどで教えていただけると嬉しいです。

POIで絵文字を出力しようとすると、そのままでは「??」と文字化けしたようになってしまいます。
これは、Apache XMLBeansのTextSaver(org.apache.xmlbeans.impl.Saver.TextSaver)クラスのisBadCharメソッドが絵文字に対してtrueを返すからです。
Apache XMLBeansはすでに開発が終了しています。isBadCharメソッドはprivateで定義されているので、オーバーライドもできません。私はクラスを上書きする方法を選択しました。

まずは、Apache XMLBeansのソースを取得します。
svn export http://svn.apache.org/repos/asf/xmlbeans/trunk/ xmlbeans

次に、xmlbeans\src\store\org\apache\xmlbeans\impl\Saver.javaをプロジェクトへコピーします。必要なディレクトリ(org\apache\xmlbeans\impl)を作成し、その配下へコピーします。

最後に、isBadCharメソッドを書き換えます。書き換え後は次のようになります。
        private boolean isBadChar ( char ch )
        {
            if (Character.isHighSurrogate(ch) ||
                Character.isLowSurrogate(ch))
                return false;
            return ! (
                (ch >= 0x20 && ch <= 0xD7FF ) ||
                (ch >= 0xE000 && ch <= 0xFFFD) ||
                (ch >= 0x10000 && ch <= 0x10FFFF) ||
                (ch == 0x9) || (ch == 0xA) || (ch == 0xD)
                );
        }
OptimizedForSpeedSaverにも同様のメソッドがあるので、ついでに書き換えておきます。

以上で絵文字を出力できるようになります。

2015年6月1日月曜日

Javaの正規表現で後方参照を使用する

テキスト処理で重要になる正規表現と後方参照。
Javaで実装するサンプルを2つ紹介します。

$nを使用する方法
Matcher#replaceAllメソッドや、Matcher#replaceFirstメソッドは$nで後方参照を使用できます。
String regex = "\\[([0-9]+)\\]";
String src = "[1] [2] [3] [4] [5]";
 
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(src);
String  result1 = matcher.replaceAll("($1)");
System.out.println(result1);
// => (1) (2) (3) (4) (5)


Matcher#groupを使用する方法
Matcher#groupメソッドを使用する方法は多少複雑です。
正規表現にマッチする部分は、Matcher#startメソッドとMatcher#endから取得できます。
この部分文字列を置き換えてしまえばいいというわけです。
こちらの方法では、後方参照で取得した文字列を元にして、編集を加えられるというメリットがあります。
サンプルではアラビア数字から漢数字へ置き換えています。
String regex = "\\[([0-9]+)\\]";
String src = "[1] [2] [3] [4] [5]";
String[] kan = {"一", "ニ", "三", "四", "五"};
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(src);
StringBuilder result2 = new StringBuilder();
int lastEnd = 0;
String outOfMatch = "";
while(matcher.find()) {
    outOfMatch = src.substring(lastEnd, matcher.start());
    String group = matcher.group(1);
    int n = Integer.parseInt(group);
    String kanN = kan[n-1];
    result2.append(outOfMatch);
    result2.append("(" + kanN + ")");
    lastEnd = matcher.end();
}
outOfMatch = src.substring(lastEnd);
result2.append(outOfMatch);
System.out.println(result2);
// => (一) (ニ) (三) (四) (五)

以下、サンプルソース全体です。

2015年5月11日月曜日

Javaで文字列を表示した時の幅を取得する

FontオブジェクトとFontMetricsオブジェクトを使用して、簡単に取得できます。
簡単なのでいきなりサンプルプログラムです。
import java.awt.Font;
import java.awt.FontMetrics;
import sun.font.FontDesignMetrics;

public class Program {

    public static void main(String[] args) {
        // Fontオブジェクトをインスタンス化する
        // FontオブジェクトからFontMetricsオブジェクトを取得する
        // FontMetrics#stringWidthメソッドで文字列の幅を取得する
        Font font = new Font("Monospace", Font.PLAIN, 12);
        FontMetrics fontMetrics = FontDesignMetrics.getMetrics(font);
        String data = "Hello FontMetrics";
        int width = fontMetrics.stringWidth(data);
        System.out.println(width);
    }
}

※このプログラムをコンパイルすると警告が出ます。

2015年4月27日月曜日

JavaのExecutorServiceのサンプル

Javaでスレッドを使用するには、ExecutorService#invokeAllを呼ぶのが簡単です。ExecutorService#inokeAllは別スレッドで実行するCallableオブジェクトのコレクションを引数として受け取り、処理がすべて完了するまで現在のスレッドをブロックします。処理の結果はFutureのリストとして返ります。
サンプルとして、複数のホストに対してpingコマンドを発行するプログラムを作成しました。
import java.util.List;
import java.util.ArrayList;
import java.util.concurrent.Callable;
import java.util.concurrent.Executors;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;

public class Program {
    
    public static void main(String[] args) throws Exception {

        ExecutorService svc = Executors.newFixedThreadPool(3);

        try {
            List<Callable<Integer>> listCallable = new ArrayList<>();
            for (String ipAddress : args) {
                listCallable.add(new PingCommand(ipAddress));
            }
            List<Future<Integer>> listFuture = svc.invokeAll(listCallable);
            for (Future<Integer> future : listFuture) {
                System.out.println(future.get());
            }
        } finally {
            svc.shutdown();
        }
    }

    private static class PingCommand implements Callable<Integer> {
        private final String ipAddress;

        private PingCommand(String ipAddress) {
            this.ipAddress = ipAddress;
        }

        public Integer call() {
            try {
                String[] args = {"ping", ipAddress, "-c", "3"};
                Process proc = new ProcessBuilder(args).start();
                return proc.waitFor();
            } catch (Exception e) {
                e.printStackTrace();
                return -1;
            }
        }
    }
}

参考
ExecutorService
Callable
Future

2014年7月28日月曜日

Javaでクラス図(1クラスだけ!)を書いてみた

グラフを書くためのライブラリの一つに、Graphvizというものがあります。
調べてみたところ、クラス図を書くこともできるようなので、Javaのリフレクションを使ってクラス図を書いてみました。

まだ単体のクラスを出力できるだけですが、関連を出力できるようになるとなかなかおもしろそうです。

参照
Graphviz
UML Diagrams Using Graphviz DOT

2014年3月31日月曜日

FilterでHTTP通信のGZIP圧縮に対応する

HTTP/1.1では仕様に電文の圧縮が盛り込まれています。
今回はサーブレットフィルタでGZIP圧縮に対応してみたいと思います。

必要なクラス
圧縮されたHTTPリクエストの解凍と、HTTPレスポンスの圧縮を実現するには、次の5つのクラスが必要です。

  1. GZIPFilter - Filterを実装します。HTTPヘッダを確認し、圧縮/解凍をするかどうか判断します。
  2. GZIPRequest - HttpServletRequestWrapperを継承します。GZIPServletInputStreamを返します。
  3. GZIPServletInputStream - HTTPリクエストを解凍するInputStreamです。
  4. GZIPResponse - HttpServletResponseWrapperを継承します。GZIPServletOutputStreamを返します。
  5. GZIPServletOutputStream - HTTPレスポンスを圧縮するOutputStreamです。
ほか、リクエストをそのままレスポンスするEchoServletを準備します。

2012年12月6日木曜日

WicketでWebSocketを使ってみた

Wicketの6からWebSocketに対応したらしいので使ってみた。

  • 作ったもの
  • 感想
  • 引っかかったところ
作ったもの
簡単にいうと、チャットアプリケーション。
メッセージをAjaxで受け取り、チャット参加者へWebSocketでpush通知する。
クライアント側はjQueryで受け取ったメッセージをDOMへ追加する。

引っかかったところ
IWebSocketConnectionにはComponentをaddできない。送信できるのは文字列またはbyte配列。WebSocketRequestHandlerにはaddできるので、WebSocketBehaviorのonMessageで実装すればよいが、それってAjaxとなにが違うのかな?

web.xmlで、サーブレットコンテナに対応したfilterを設定しなければならない。wikiのCustom WicketFilterを参照。

JavaScriptの依存関係を設定しなければいけない。サンプルを参照。

感想
IWebSocketConnectionで送受信できるデータが文字列かバイト配列なので、実際はJSONを送受信することになると思われる。Javaオブジェクトとの相互変換を考慮する必要があると思う。

push通知が動作するまでは、手間がかかる割に動作はAjaxと変わらないのでモチベーションが上がらなかった。が、push通知で画面が更新されるようになると一気に楽しくなった。

やや話はそれるが、JavaScriptのライブラリがjQueryになったのも大きいと思う。

2012年7月30日月曜日

DropDownChoiceでenumを使用する

突然ですが、enumって便利ですよね。
業務で使用する場面としては、"○○区分"というものを表現するのによく使います。
そしてそれを画面では<select>として表示することもよくあります。
このとき、画面に表示するテキストをenum自身から分離するための方法です。

enumを定義する

普通にenumを定義します。

アプリケーションのプロパティファイルに表示する文字列を定義する

型名.フィールド名=文字列の形式で定義します。

DropDownChoiceのコンストラクタにEnumChoiceRendererを渡す


画面ごとに表示するテキストを変えたい場合、以下のようにします。

  1. 画面ごとにプロパティファイルを作成する
  2. EnumChoiceRendererのコンストラクタにPageのインスタンスを渡す



2012年3月23日金曜日

WicketTesterで独自のSessionを使用するには

アプリケーションで独自のSessionを使用するには、WebApplication.newSessionをオーバーライドします。
WicketTesterで単体テストをするときも、そのApplicationをコンストラクタに渡せば、そのSessionを使ってテストができます。
しかしこれは単体テストとしては今ひとつ。できればApplicationに依存しないテストを書きたい。Applicationのテストをしたいのではなく、Componentのテストをしたいのだ–。

MockApplicationを使う
何か適当な解決策はないものか、と考えたところで思いついたのが、MockApplicationを継承して使うという方法でした。
MockApplicationはWicketTesterのデフォルトコンストラクタが呼ばれたときに使用されるApplicationのため、もっともシンプルな解決策ではないかと考えました。
というわけで、MockApplication.newSessionをオーバーライドすれば独自のSessionが使えることを確認する試験を書きました。WicketTesterを起動した後、Sessionを取得して型を検査しています。

これでまたTDDの道を極めたぜ。

2012年3月18日日曜日

Javaのtrimについて

Javaで末尾の全角/半角スペースをトリムする
気になったことがあったので僕も実験してみた。
気になったのは、次の2つ。
  1. 正規表現のコンパイルを一回にしたらどれくらい改善できるのか
  2. 末尾から空白を検索した方が早くね?
というわけでメソッドを2つ追加して実験してみた。
結果は、
  1. trim2と同じか少し遅いくらいまで改善
  2. trim3と同じか少し早いくらい
  3. trim1はダントツで遅い
といった感じになりました。String.replaceAllは遅いですけど書きやすいので、問題を把握した上で使いましょう。

2012年2月6日月曜日

MyBatisの検索結果としてインターフェイスのリストを返す

Guiceをシステムに採用して半年がたち、すっかりインターフェイスが体に馴染みました。
こうなってくると永続化層のMyBatisにもインターフェイスを返して欲しくなります。
しかし、MyBatisは初期状態ではデフォルトコンストラクタがないクラスには対応していません。

ObjectFactoryの実装とバインド
この問題を解決するには、ObjectFactoryを実装し、MyBatisModule#bindObjectFactoryTypeメソッドでバインドします。
ObjectFactoryへProviderを注入
せっかくGuiceを採用しているのですから、ObjectFactoryへProviderを注入し、オブジェクトの生成を委譲しましょう。
実装したものが次のクラスです。



2011年12月23日金曜日

WicketTesterでAjaxをテストする

Ajaxまわりのtestができなくて悩んでいる話にて、
お仕事で作っているwebアプリケーションはAjaxごりっごり取り入れているのですが、残念ながらWicketTesterでAjaxまわりのテストはできないのです。
と、あるのですが、WicketTesterからAjaxまわりをテストする方法はあります。Wicketのユーザーの端くれとして、誤解をといておこうと思います。

サンプルは以下3つのファイルで構成されています。

  1. MyPage.html
  2. MyPage.java
  3. MyPageTest.java
MyPage.html
引用元と同じく、TextFieldとLabelが1つずつの画面です。JavaScriptを書かずにAjaxを実現するのがWicketのいいところ。

MyPage.java
MyPage.htmlに対して、コンポーネントを割り当てていきます。ここでAjaxイベントも定義します。

MyPageTest.java
MyPage.javaの単体テストです。Ajaxをテストするには、BaseWicketTester.executeAjaxEventを使います。
Javadoc:BaseWicketTester.executeAjaxEvent

これでAjaxもテストできます。よかったですね。