2014年5月24日土曜日

[他]WebAPIを疎通する

今どきのWebAPIは、Rest形式でかつGETで動作するため、ブラウザで簡単に疎通確認できます。
 しかし、SOAPなどPOST形式のI/Fもあります。これを、疎通するためにアプリケーションが必要になる場合があります。 また、テスト用のHTMLを置けないケースもあるでしょう。
 Windows環境において、インタフェースまでの通信経路に問題がないかを確認するためには、 VBスクリプトを使うのが気軽でよいです。でコードはこんな感じ。
Dim objXML
Dim intRet
Dim strURL
Dim strKey

strURL = "http://jlp.yahooapis.jp"
strKey = "sentence=%e7%a9%ba%e5%89%8d%e7%b5%b6%e5%be%8c"

MsgBox ("url=" & strURL)

MsgBox (strKey)

Set objXML = CreateObject("MSXML2.ServerXMLHTTP")
objXML.Open "POST", strURL, False
objXML.setRequestHeader "Content-Type", " application/x-www-form-urlencoded"
objXML.setRequestHeader "Content-Length", "length"
objXML.send strKey

intRet = objXML.Status
MsgBox ("stat=" & intRet)
MsgBox (objXML.responseText)
まぁ今どきはPS(パワーシェル)を使うんでしょうけど。。。

2014年4月20日日曜日

[他]windows8.1にADBドライバをインストールする

Windows8.1にadbドライバをインストールしようとすると、

「指定されたカタログファイルにファイルのハッシュがありません。ファイルが壊れているか、改ざんされた可能性があります。」

って出てきてドライバを設定することができません。

で、これを回避するためには、「ドライバー署名の強制を無効化」なる手続きをする必要があります。この手順がたいへんかったるいというか、google先生に聞いてもバージョンによって微妙に手順が異なり、簡単にはたどり着けません。

でも、世の中には面倒なことを2度としたくない人たちがいます。その面倒な処理をワンクリックで行ける用にしてくれるつーるがこちら。

15 seconds ADB Installer 

私のマシンでは15秒かかりませんでした。。。
唯一気になるのが、どこに何がインストールされたかよくわからない点。

とはいえ、XDAの人たち。すごいですねぇ。


2014年1月24日金曜日

[他]広告費を寄付しました

このページにある、広告(Google AdSense)の広告費が今日振り込まれました。
収益が支払可能になるまで約一年かかりました。
もらった広告費は、そのままユニセフに寄付しました。

広告費と言っても微々たるものですが、また収益が上がったら寄付する予定です。
ということで、安心して広告をクリックして下さい。

2013年8月23日金曜日

[Java]google gsonのはまりポイント

JSONをアノテーションでPOJOにバインディングするgsonは、JSONObjectでパースする原始的な処理?より、はるかに楽ができます。 最初使ったときは感動しましたね。こういうライブライがつかえないプロジェクトでは、同様の処理を実現するためにリフレクションであれして。。。なんていう残念な結末が目に浮かびます。

しかし、そのgsonにも、これはないんじゃない?的な結果になることがいくつかあります。
そのいくつかはこんな感じ。
  1. <T> T Gson#fromJson(String json, Type typeOfT) で第一引数にnull渡すと結果がnull
  2. <T> T Gson#fromJson(String json, Type typeOfT) で第一引数にから文字渡すと結果がnull
  3. <T> T Gson#fromJson(Reader json, Class<T> classOfT) で第一引数がのReaderが即EOFになると結果がnull
そうなんです。解析できない系のインプットが入ると、結果がnullになっちゃうんです。
1は、妥当だと思いますが、2,3は例外はくかデフォルトで生成したオブジェクト返せよ!って感じがします。
ということで結果のnullチェックが必要になるという残念な感じになっています。
これ気に入らないなら、Null Object Supportを使えよって話ですね。しかしこれではインプットがnullだからそうなっているのか、空文字系("")だからそうなるのかわかりません。
個人的な考えでは、前者はバグで後者はデータ不正ですね。


ここまでは気を付けるよの話なんですが、問題は

  • JSON構文エラーの際に発生する構文エラーがRuntime系の例外

です。そうなんです。コンパイラーでのチェックができないという残念な結果になります。
・・・外部からインプットするJSONの構文チェックは当然すべきであり、これがランタイムになるというのはちょっと理解できないです。
みなさん、こういうのってどうしてるんでしょうか。

2013年7月25日木曜日

[Java]数値のラッパー型をintに変換する

引数で何らかの数値ラッパー型がObjectで引き渡される。それをintとして利用したい的なことありませんか? ありませんね。
でも、汎用的な変換ライブラリなどではそんなことあるかもしれませんね。 instanceofを全部の数値ラッパー型に適応して。。。涙が出そうになります。ということで調べてみるとNumberというインタフェースがあり、これが使えることがわかりました。 IntegerやDoubleのリファレンスを見るとわかるとおり、ラッパー型のクラスはみんなNumberを継承しているんです。 コードはこんな感じ。

public static void main(String[] args) {
	Object d = Double.valueOf(3.5d);
	System.out.println("3.5d=" + toInt(d));
 
	Object f = Float.valueOf(2.5f);
	System.out.println("2.5f=" + toInt(f));
 
	Object l = Long.valueOf(20l);
	System.out.println("20l=" + toInt(l));
 
	Object b = Byte.valueOf((byte) 20);
	System.out.println("20b=" + toInt(b));
 
	Object s = Short.valueOf((short) 20);
	System.out.println("20s=" + toInt(s));
 
	Object bd = new BigDecimal(4.5);
	System.out.println("4.5bd=" + toInt(bd));
 
	Object al = new AtomicLong(21);
	System.out.println("21al=" + toInt(al));
 }
 
/**
 * int変換.
 * 
 * 数値ラッパーをintに変換する。
 * 
 * @param obj
 * @return 変換した数値
 */
public static int toInt(Object obj) {
	if (!(obj instanceof Number)) {
		throw new IllegalArgumentException("not number!!");
	}
	return ((Number) obj).intValue();
}
実行結果はこんな感じ。

3.5d=3
2.5f=2
20l=20
20b=20
20s=20
4.5bd=4
21al=21

2013年7月23日火曜日

[Java]JSONをPOJOにバインドするとき、オリジナルの変換を行う

JSONからPOJO(Bean)に変換する処理はめんどくさいです。たとえば、
  • JSONは文字列で、Java側はEnum
このケースでは、文字列=Enumの定義名という式が成り立てば、自動で変換されます。下のstep1がそれに該当します。しかし文字列がenumと一致しない場合、正しく変換されません。おそらく初期値になってしまうでしょう。以下の例ではnullになってしまっています(enumはnullを許容するんです)。
次に、
  • JSON上は数値なんだけど、Java上はEnum
この場合、自動的な変換では明らかに無理です。こういう場合、JsonDeserializer<T>を使います。 以下の例では、数値をenumにしています。こちらも存在しない値の場合、nullを返却しています。 実装した例はこんな感じ。

public class GsonEnum {
    public static void main(String[] args) {
        Gson gson = new Gson();

        // タイプを取り出す(List)
        Type type = new TypeToken<List<Signal>>() {
        }.getType();

        // JSON->List<Signal>
        List<Signal> signal = gson.fromJson(new InputStreamReader(
                GsonMap.class.getResourceAsStream("signal2.json")), type);

        System.out.println("---step1---");
        System.out.println(signal);

        // JSON->List<Signal>
        // #1 TypeAdapterを設定したGsonを生成する
        Gson gson2 = new GsonBuilder().registerTypeAdapter(SignalStat.class,
                new SignalStatDeserializer()).create();
        List<Signal> signal2 = gson2.fromJson(new InputStreamReader(
                GsonMap.class.getResourceAsStream("signal3.json")), type);

        System.out.println("---step2---");
        System.out.println(signal2);
    }

    /**
     * 解析結果を受け取るクラス
     */
    static class Signal {
        private SignalStat stat;
        private String message;
        private SignalStat next;

        @Override
        public String toString() {
            StringBuffer sb = new StringBuffer();
            sb.append("[");
            sb.append("stat=").append(stat);
            sb.append(" message=").append(message);
            sb.append(" next=").append(next);
            sb.append("]");

            return new String(sb);
        }
    }

    /**
     * ステータスの表現.
     */
    enum SignalStat {
        Red, Yellow, Blue;

        // #2 変換用のMAP(int -> SignalStat)
        static Map<Integer, SignalStat> CONVERTER = new HashMap<Integer, SignalStat>();

        static {
            for (SignalStat stat : SignalStat.values()) {
                CONVERTER.put(stat.ordinal(), stat);
            }
        }
    }

    /**
     * SignalStat用Deserializer.
     */
    static private class SignalStatDeserializer implements
            JsonDeserializer<SignalStat> {

        @Override
        public SignalStat deserialize(JsonElement json, Type typeOfT,
                                      JsonDeserializationContext context) throws JsonParseException {
            // #3 int -> SignalStat
            return SignalStat.CONVERTER.get(json.getAsInt());
        }
    }
}
ポイントは以下の通り
  • #1:TypeAdapterを設定したGsonを生成するためにGsonBuilderをnewしregisterTypeAdapterでDeserializerを指定する
  • #2:enumの中に、変換用Mapを用意しておく。staticでOKです
  • #3:JsonDeserializerを実装する。#2の変換用Mapを使ってint->enumを実現している
入力データはこんな感じ(signal2.json)

[
    {
        "stat": "Red",
        "message": "とまれ",
        "next": "Blue"
    },
    {
        "stat": "Yellow",
        "message": "とまっとけ",
        "next": "Red"
    },
    {
        "stat": "Invalid",
        "message": "すすんでもいいよ",
        "next": "Yellow"
    }
]
入力ry (signal3.json)

[
    {
        "stat": 0,
        "message": "とまれ",
        "next": 2
    },
    {
        "stat": 1,
        "message": "とまっとけ",
        "next": 0
    },
    {
        "stat": 100,
        "message": "すすんでもいいよ",
        "next": 1
    }
]
出力結果はこんな感じ
step1ではInvalidは存在しないのでnullとなり、step2では100は存在しないのでnullになっています。

---step1---
[[stat=Red message=とまれ next=Blue], [stat=Yellow message=とまっとけ next=Red], [stat=null message=すすんでもいいよ next=Yellow]]
---step2---
[[stat=Red message=とまれ next=Blue], [stat=Yellow message=とまっとけ next=Red], [stat=null message=すすんでもいいよ next=Yellow]]

2013年7月22日月曜日

[Android]透明なアクティビティ

テーマ設定で透明なアクティビティが作れます。えぇまぁ AndroidManifest.xmlに書くだけです。

<activity android:name="com.hoge.TransparentActivity"
 android:theme="@android:style/Theme.Translucent"
 android:label="Transparent"/>