アジョブジ星通信

進捗が出た頃に更新されるブログ。

AndroidでJEXLを使う

Androidで使えるクエリ言語ってなかなか見つからないものです。
javax.scriptはAndroidでは使えないし。。

そんなところでこんな記事を見つけて、Java Expression Language (JEXL)を試してみました。

ソースコード azyobuzin/JexlSample · GitHub

今回は http://commons.apache.org/jexl/ にならって、コレクションにEnumerable.Whereをかけるようなのを作ってみました。

//txtQuery - クエリ入力欄
//sourcePreview - コレクションのプレビュー用ListView

//省略

private void run() {
    try {
        String query = txtQuery.getText().toString();
        
        if (query.isEmpty())
            return;
        
        //エンジンの作成・式の組立
        JexlEngine engine = new JexlEngine();
        Expression expr = engine.createExpression(query);
        
        ListAdapter adapter = sourcePreview.getAdapter();
        
        ArrayList<Object> resultItems = new ArrayList<Object>();
        
        for (int i = 0; i < adapter.getCount(); i++) {
            Object item = adapter.getItem(i);
            
            //変数を挿入
            JexlContext ctx = new MapContext();
            ctx.set("item", item);
            
            //実行!
            Object result = expr.evaluate(ctx);
            
            if (result instanceof Boolean) {
                if ((Boolean)result)
                    resultItems.add(item);
            } else {
                new AlertDialog.Builder(this)
                    .setTitle(R.string.result)
                    .setIcon(android.R.drawable.ic_dialog_alert)
                    .setMessage(R.string.result_is_not_boolean)
                    .setPositiveButton(android.R.string.ok, emptyListener)
                    .show();
                return;
            }
        }
        
        String resultString = "";
        for (Object item : resultItems) {
            resultString += item.toString() + "\n";
        }
        
        new AlertDialog.Builder(this)
            .setTitle(R.string.result)
            .setIcon(android.R.drawable.ic_dialog_info)
            .setMessage(resultString)
            .setPositiveButton(android.R.string.ok, emptyListener)
            .show();
    } catch (Exception ex) {
        new AlertDialog.Builder(this)
            .setTitle(R.string.result)
            .setIcon(android.R.drawable.ic_dialog_alert)
            .setMessage(ex.getClass().getName() + "\n\n" + ex.getMessage())
            .setPositiveButton(android.R.string.ok, emptyListener)
            .show();
    }
}

//省略

createExpressionで文法が間違っているときに、evaluateで実行に失敗したときに例外を吐かれるので、落ちない保証がないときはcatchしてあげましょう。

そして、実行するとこんな感じになります
f:id:azyobuzin:20120225202026p:image:w500

はい、ちゃんと動きました。

で、これの使い道ですが、ラムダ式として使えればなぁとか考えてたり。あと、Twitterクライアントの振り分けとかに使いたいです。そこまで作れるかが問題ですが。。