ひだまりソケットは壊れない

id:nobuoka が情報系の話を書いたり日常の話を書いたりします

まじめなことを書くつもりでやっています。 適当なことは 「えっちなのはいけないと思います」 に書いています。

Windows ストアアプリの JS で文字列をエンコードするために Windows Runtime コンポーネントを作成する

前置き: JS での Windows ストアアプリ開発時に C# の機能を使いたい

Windows ストアアプリを JS + HTML で開発する場合、たまに JS の非力さに困ることがあります。 例えば、文字列を UTF-8エンコードしてバイト列を得たいという場合。 JS だけでエンコードするのは難しいですよね。 JS での文字列のエンコードの現状としては、WHATWG の Encoding StandardTextEncoder インターフェイスが定義されていて、FirefoxChromeOpera では使えるようになっているようです。 しかし、残念ながら Windows ストアアプリでは使えません (Windows 8.1 時点)。

Windows ストアアプリで使える一つの方法として、エンコード処理を全て JS で記述するという方法があります。 JS の文字列を UTF-8エンコードして得られたバイト列を Uint8Array オブジェクトとして得る関数 (strToUTF8Arr 関数) のサンプルコードが MDN にあります。

このような関数を用意してもよいのですが、Windows ストアアプリ開発をする場合は C# の力を借りるということが簡単にできるので C# の力を借りるのが良いでしょう。 (C# だけでなく Visual BasicC++ も使用できますが、他の言語を選択する理由が特にないのであれば C# を使うのが楽だと思います。)

Windows Runtime コンポーネント (WinRT コンポーネント)

Windows ストアアプリの JS からは Windows Runtime API を触ることはできますが、ネイティブの C++ のライブラリを直接使用したり、.NET Framework のクラスライブラリを直接使用したりすることはできません。 JS から C++ .NET Framework の機能を使用するためには Windows Runtime を使ってコンポーネントを作成する必要があります。 Windows Runtime コンポーネントは、C#C++Visual Basic のいずれかの言語で作成できます。 作成された Windows Runtime コンポーネントは、JS からも使用できますし、当然他の言語 (C#C++Visual Basic) からも使用できます。

Windows Runtime コンポーネントの概要は次の記事が参考になります。

公式のドキュメントとしては次を見ると良いと思います。

MS によるブログエントリも参考になります。

実際の作り方

C#Windows Runtime コンポーネントを記述するには、次のチュートリアルを見るのが良いでしょう。

Visual Studio Professional (または Community) 2013 を使っていれば、上のチュートリアル通りに進めることで Windows Runtime コンポーネントを作成し、JS から使用するということができるはずです。

配列の扱いなどの注意すべき点は次の文書を読むと良いでしょう。 (日本語だとタイトルが 「C++ および〜」 となっていますが、正しくは 「C# および〜」 です。)

サンプル

例として、文字列を UTF-8 エンコーディングエンコードしたり、逆にデコードしたりするための Windows Runtime コンポーネントを作成して、JS から使用してみます。

まず、新たに C# 用の Windows Runtime Componenet プロジェクトテンプレートを使って、新しいプロジェクトを作成します。 今回は 「WindowsRuntimeComponentSample」 というプロジェクト名にしました。 そして、次のようなクラス (WindowsRuntimeComponentSample.Utf8Encoding クラス) を作成しました。

using System;
using System.Runtime.InteropServices.WindowsRuntime;
using System.Text;

namespace WindowsRuntimeComponentSample
{
    public sealed class Utf8Encoding
    {
        public static byte[] encode(String str)
        {
            return Encoding.UTF8.GetBytes(str);
        }

        public static String decode([ReadOnlyArrayAttribute] byte[] bytes)
        {
            return decode(bytes, 0, bytes.Length);
        }

        public static String decode([ReadOnlyArrayAttribute] byte[] bytes, int index, int count)
        {
            return Encoding.UTF8.GetString(bytes, index, count);
        }
    }
}

そしてこのプロジェクトを JS のプロジェクト (プロジェクト名 「App1」) から参照するように設定します。 ソリューションの構成は次のようになりました。

f:id:nobuoka:20150329213852p:plain

これで JS から WindowsRuntimeComponentSample.Utf8Encoding クラスが使用できます。

// 文字列を UTF-8 でエンコードする。 (返り値は Uint8Array オブジェクト。)
WindowsRuntimeComponentSample.Utf8Encoding.encode("あ");
// バイト列 (Uint8Array オブジェクト) を UTF-8 でデコードする。
WindowsRuntimeComponentSample.Utf8Encoding.decode(new Uint8Array([0xE3, 0x81, 0x82]));

JS での string 型は C# では System.String 型になります。 また、C# での byte[] 型は JS では Uint8Array オブジェクトとして扱われます。

TypeScript で扱う際に型情報を自前で用意する必要があるのがちょっと面倒だなーと思いました。 *1

おわりに

UTF-8 での文字列エンコーディングを例にしましたが、文字列のエンコード・デコード処理以外でも JS では書きにくい処理を C# などで実装して JS から呼び出すということがさほど難しくなく実現できます。

Windows アプリ開発時にどの言語 (JS、C#C++Visual Basic) を選択するか考える際に 「基本的に JS で大丈夫だけど、JS で書きにくい処理を書く必要が出てきたらどうしよう」 と悩むこともあるかもしれません。 このエントリで見たように、そのような処理は C# などで Windows Runtime コンポーネントとして書いて、JS から呼び出す、ということが可能です。 言語選択の参考にしてください。

*1:もしかしたら自動で生成される機能があったりするかもしれないけど知らないです。

読んだ: Java エンジニア養成読本

2014 年 12 月に発売された 『Java エンジニア養成読本 [現場で役立つ最新知識、満載!]』 を読みました。 これだけを読んで Java がわかるわけではないけど、歴史から Java EE、周辺技術に至るまで説明されていて、Java 初心者が全体を俯瞰するのに良さそうだと思いました!

内容紹介

本書は、複数の著者による共著になっています。

まず、巻頭記事がきしださんによる 「誰も教えてくれない Java の世界」。 Java の歴史や、Java のエディション (Java SE、EE、ME について)、JDKJREJCP、JSR の紹介や各種 IDE や有名なフレームワークの紹介など、Java を使い始めてみたけど世界観がよくわからない、という人に役立つ情報が凝縮されています。 「お前に Sun が救えるか」 といったネタも紹介されています。

続く特集 1 が irof さんによる 「Java 入門」。 もちろん Java の構文の細かいところまでは説明されていませんが、クラス定義についてや例外処理、標準ライブラリについてのプラクティスなどが紹介されています。

特集 2 は bitter_fox さんによる 「Java SE 8 時代のデータ処理入門」。 Java SE 8 で導入されたラムダ式や Stream API について説明されます。 私もここら辺のことはまだ詳しくは知らなかったのでためになりました。

特集 3 はキクタローさんによる 「現場で役立つ Java EE」。 Java 初心者にとっては Java EE とは何者なのか良くわからない存在だと思いますが、この特集を読むことでなんとなく何者であるかはわかると思います。 Java EE と一口に言ってもその技術要素は多岐に渡りますが、この特集では ServletJSFJAX-RSJPACDIEJB といったわりと良く使われる技術要素について主に説明されます。 私も JSFEJB については詳しくなかったので、本書を読んで勉強になりました。

特集 4 は渡辺さんによる 「現場で役立つチーム開発入門」。 Git や MavenJUnit によるテストや Jenkins といった、開発現場で良く使われている周辺技術が説明されます。

最後に 「イマドキの Java 受託開発の現場で求められる知識」 というタイトルで、提案や設計について、「web 開発の現場では Java の知識だけでなく、HTML や CSS、JS の知識なども必要である」 みたいな話や、テストやデプロイについて説明されます。

感想

Java 初心者が Java を使った web アプリケーション開発について学ぶのにちょうど良い書籍になっていると思います。 もちろん、前半は web アプリケーション開発とは関係なく Java について学べますし、Java を使うなら (web アプリケーション開発をするつもりがなくても) 読むと良いでしょう。

文体がいいのか構成がいいのかムックという本の形態が良いのかわかりませんが、技術書としては読みやすかったです。

既に Java について深い造詣があるならこの本を読む必要はないと思います *1 が、これから Java を使っていきたい人や最近 Java を学び始めた人は、この本を早い段階で呼んでおくと後々の学習が捗ると思います。 Java の良書はいろいろありますが、重量級なものも多いですので、まずは軽く本書から読んでみる、というのをオススメします。

あなたと Java エンジニア養成読本、今すぐ購入!

Kindle 版もあるようですよ!

Javaエンジニア養成読本 [現場で役立つ最新知識、満載!] (Software Design plus)

Javaエンジニア養成読本 [現場で役立つ最新知識、満載!] (Software Design plus)

Javaエンジニア養成読本[現場で役立つ最新知識、満載!]

Javaエンジニア養成読本[現場で役立つ最新知識、満載!]

*1:Java 8 周りはまだ、ということであれば 「Java SE 8 時代のデータ処理入門」 は役立つでしょう

Espresso 2.0 が Android support library の一部としてリリースされた

上記エントリにあるように、Espresso 2.0 がリリースされた。 Espresso は Android アプリの自動テストのためのライブラリである。 ほぼ上のエントリに書かれている内容であるが、Espresso 2.0 のリリースについて紹介する。

変更内容など

一番大きな変更は、Android support library の一部になったことだと思われる。 (上のエントリにもそう書かれている。) *1 そのおかげで、Android SDK で 「Android Support Repository」 をインストールしておけば (JAR をダウンロードしたりせずに) 簡単に使用できるようになった。

API 的には、パッケージ名の変更以外は大きな変更点はなさそうである。 とはいえ一部非互換な変更が加わっているので、そこら辺は気を付ける必要がある。 変更内容はリリースノートを見ると良い。

また、Instrumentation テストランナーとして GoogleInstrumentationTestRunner にいくつかの機能を追加した AndroidJUnitRunner が含まれている。 JUnit 4 サポートも含まれていて、これを使うことで JUnit 4 を使ったテストを書けるようになる。

ドキュメント

2015 年には Android Developers の方にドキュメントが移される予定のようだが、今のところはまだ android-test-kit でホストされている。

各モジュールの Javadoc は以下。

サンプルコード

サンプルプロジェクトが GitHub にホストされている。 JUnit 4 を使ったテストの例などもあり、参考になる。

また、私が公開している Espresso を使用したテストの例も Espresso 2.0 に対応させた。

Espresso を使って PreferenceActivity の自動 UI テストを行う」 のエントリを書いたときに作ったサンプルプロジェクトである。

*1:早く Volley も support library の一部にならないかな。

【Retrofit を読む】 利用者が定義したインターフェイスに実装を提供する Java ライブラリの作り方 【リフクレション】

この記事は、はてなエンジニアアドベントカレンダー 2014 の 15 日目のエントリです。 昨日は id:chris4403 による 「開発合宿で何を考えてどう作ったか」 でした。

このエントリでは、Android アプリおよび Java アプリケーション用の REST クライアントライブラリである Retrofit のコードを参照しながら、利用者が定義したインターフェイスの実装を提供するようなライブラリの実装方法について説明します。 主に Java のリフレクションの話になります。

注意点など

  • 本記事中に掲載されている Retrofit のコードは、Apache License, Version 2.0 のもとで公開されているものです。
  • 記事執筆時点の master ブランチの最新のコミットを参照しています。
  • Android アプリ開発者で Retrofit のコードを読みたい人は Android Studio で Retrofit のプロジェクトを開くのが楽で良いと思います。

Retrofit の紹介

Retrofit について簡単に紹介します。 詳しい話は公式サイトの方を見てください。

Retrofit は Square によって開発されている REST クライアントライブラリです。 HTTP リクエストを実行するためのメソッドを持ったインターフェイスを定義すると、Retrofit がそのインターフェイスの実装を提供してくれます。 アノテーションにより、HTTP メソッドの指定やどの引数がなんのパラメータであるか、あるいはリクエストボディであるかといったことを指定できます。

下記は Groovy スクリプトはてなハイクの公開タイムラインを取得する REST クライアントのサンプルコード *1 です。 HTTP メソッドの種類とリクエスト先のパスを GET アノテーション で指定しています。 そして、リクエストごとにクエリパラメータを変更できるように、クエリパラメータの値を引数として受け取るようになっています。

@Grab('com.squareup.retrofit:retrofit:1.8.0')

import retrofit.RestAdapter
import retrofit.http.GET
import retrofit.http.Query

// HTTP リクエストを投げるメソッドを持つインターフェイスを定義する。
interface HaikuService {
    /** はてなハイクの公開タイムラインを取得する */
    @GET("/api/statuses/public_timeline.json")
    List<?> getPublicTimeline(@Query("page") int page, @Query("count") int count)
}

// 定義したインターフェイスの実装を取得。
RestAdapter restAdapter = new RestAdapter.Builder()
    .setEndpoint("http://h.hatena.ne.jp")
    .build()
HaikuService haiku = restAdapter.create(HaikuService.class)

// 取得した実装を使用してハイクの公開タイムラインの内容を表示。
def statuses = haiku.getPublicTimeline(1, 10)
for (def status : statuses) {
    println '---'
    println status.user.name
    println status.text
}

利用者側がインターフェイスを定義して、そのインターフェイスの実装をライブラリが提供する、というのが特徴的ですね。

なお、HTTP 通信の実装や、リクエストボディおよびレスポンスボディと Java オブジェクトの変換機能の実装については Retrofit 自体が持っているわけではありません。 (デフォルトで HTTP 通信の実装はプラットフォームに応じたものが使われ、変換機能には Gson が使われますが、好みに応じてそれらは変更できます。)

利用者が定義したインターフェイスに対して実装を提供するために必要な技術

さて、Retrofit のように利用者が定義したインターフェイスに対して実装を提供するようなライブラリを書くことを考えましょう。 Java では、リフレクションを使用することで実現可能です。

任意のインターフェイスに対して実装を提供するために、Proxy クラス を使用することができます。 そして、実行されたメソッドの情報を取得するために、リフレクションのための各種メソッドを使用できます。 この 2 つについて順番に説明します。

Proxy クラス

Proxy クラスは、動的プロキシクラス (実行時に指定されたインターフェイスを実装するクラス) を生成するためのクラスであり、また、動的クラスのスーパークラスにもなるものです。 実際のメソッド呼び出しの処理は InvocationHandler インターフェイス を実装したクラスのインスタンスが担います。 Proxy クラスを使うことで、実行時に任意のインターフェイスに実装を提供することができます。

Retrofit では、retrofit.RestAdapter#create(Class) メソッド の中で動的プロキシクラスのインスタンス生成が行われます。

  /** Create an implementation of the API defined by the specified {@code service} interface. */
  @SuppressWarnings("unchecked")
  public <T> T create(Class<T> service) {
    Utils.validateServiceClass(service);
    return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
        new RestHandler(getMethodInfoCache(service)));
  }

retrofit.RestAdapter#create(Class<T>) メソッド

上記コードを見ればわかるように、指定されたインターフェイスの実際のメソッド呼び出しを処理するのは retrofit.RestAdapter.RestHandler クラスです。

リフレクションによるメソッド情報の取得

メソッドが呼ばれた際に実行される HTTP リクエストの内容は、各メソッドに付けられたアノテーションや返り値の型、仮引数の情報によって決まります。 すなわち、メソッドの情報を実行時に見る必要があります。 メソッドの情報を実行時に得るには、Method クラス に定義されている各種メソッドが使用できます。

Retrofit ではどのような処理になっているのか見ていきましょう。 retrofit.RestAdapter.RestHandler#invoke(Object, Method, Object[]) メソッドの実装は次のようになっています。

  @SuppressWarnings("unchecked") //
  @Override public Object invoke(Object proxy, Method method, final Object[] args)
  throws Throwable {
    /* (略) */
    // Load or create the details cache for the current method.
    final RestMethodInfo methodInfo = getMethodInfo(methodDetailsCache, method);
    if (methodInfo.isSynchronous) {
      try {
        return invokeRequest(requestInterceptor, methodInfo, args);
      } catch (RetrofitError error) {
    /* (略) */

retrofit.RestAdapter.RestHandler#invoke(Object, Method, Object[]) メソッド

まず、getMethodInfo(Method) メソッド呼び出しにより指定のメソッドの情報を RestMethodInfo オブジェクトとして受け取り、その後 invokeRequest メソッドを呼び出して実際の HTTP リクエスト処理に入ります。 実際には、同期実行か非同期実行か、あるいは RxJava を使っているかで処理が分かれたりしますが、ここではそこら辺の詳細には立ち入りません。

例えば、HTTP リクエストの結果の受け取り方は RestMethodInfo#parseResponseType() メソッドで解析されます。

  private ResponseType parseResponseType() {
    // Synchronous methods have a non-void return type.
    // Observable methods have a return type of Observable.
    Type returnType = method.getGenericReturnType();

    // Asynchronous methods should have a Callback type as the last argument.
    Type lastArgType = null;
    Class<?> lastArgClass = null;
    Type[] parameterTypes = method.getGenericParameterTypes();
    if (parameterTypes.length > 0) {
      Type typeToCheck = parameterTypes[parameterTypes.length - 1];
      lastArgType = typeToCheck;
      if (typeToCheck instanceof ParameterizedType) {
        typeToCheck = ((ParameterizedType) typeToCheck).getRawType();
      }
      if (typeToCheck instanceof Class) {
        lastArgClass = (Class<?>) typeToCheck;
      }
    }
    /* (略) */

retrofit.RestMethodInfo#parseResponseType() メソッド

同期実行の場合はメソッドの返り値として HTTP リクエストの結果が返され、非同期実行の場合はコールバックオブジェクトが引数に渡されるようになっているので、下記のメソッドを呼ぶことでメソッドの返り値と仮引数との両方を確認しています。

他にも、メソッドに付けられたアノテーション一覧を取得するために getAnnotations() メソッド が使われたり、仮引数につけられたアノテーションを取得するために getParameterAnnotations() メソッド が使われたりしています。

まとめと参考文献

  • Proxy クラスと InvocationHandler インターフェイスを使用することで、任意のインターフェイスに対して動的プロキシ・クラスを生成することができる。
  • リフレクションにより、メソッドの返り値の型などの情報を実行時に取得することができる。
  • これらの機能を使うことで、利用者が定義したインターフェイスに実装を提供するライブラリを記述できる。

リフレクションについては次のドキュメントを参考にすると良いでしょう。

おわりに

この記事では、Retrofit の実装を参照しながら Java のリフレクション機能について紹介しました。 バグの原因になりがちなのでアプリケーションコード中で直接リフレクションを使用するのはできるだけ避けた方がいいと思いますが、リフレクションにより Retrofit のような便利なライブラリを実現することも可能ですので、いい感じに使っていきたいですね。

*1:サンプルコードなのでエラー処理などちゃんと行っていません。

google-http-java-client 入門

Java で HTTP 通信するときのクライアントライブラリを何にするかいつも悩むのですが、最近 google-http-java-client が気になってたのでちょっと使ってみました。 汎用的に HTTP 通信ができればよい、というような用途にはちょうど良さそうです。

数年前からベータ版や RC 版としては存在していましたが、正式にリリースされたのは今年のようです。

google-http-java-client について

Google によって書かれた Java の HTTP クライアントライブラリです。

HTTP トランスポートの抽象化がされており、実際の HTTP 通信を行う低層のライブラリを選択できるのが特徴です。 例えば java.net.HttpURLConnection を使ったり、Apache HTTP Client を使ったりできます。

また、リクエストやレスポンスのコンテンツボディの XMLJSON のパースやシリアライズを行う機能も含まれており、便利です。

使用できる環境は、Java 5 以降の Java SE 環境や Java EE 環境、Android 1.5 以降などです。

ざっくりとした使い方

準備

使用するためには JAR ファイルをライブラリパスに追加するとか、Maven の依存関係管理に追加するとかする必要があります。 2014 年 11 月 8 日現在の最新バージョンは 1.19.0 で、Maven Central Repository に置かれています。

Gradle を使っているならば次のように依存関係を記述すればよいです。

repositories {
    mavenCentral()
}

dependencies {
    compile 'com.google.http-client:google-http-client:1.19.0'
}

HTTP リクエストを行う処理の全体の流れ

  1. HttpTransport オブジェクトを用意する。
    • これはアプリケーション全体で 1 つだけ存在すればよい。
  2. HttpTransportcreateRequestFactory メソッドを呼んで HttpRequestFactory オブジェクトを生成する。
  3. HttpRequestFactory から HttpRequest を生成する。
  4. HttpRequestexecute メソッドを呼び出してリクエスト実行、レスポンスとして HttpResponse を取得。
  5. レスポンスを処理したあと、終了処理。

サンプルコード

GET リクエストを投げてレスポンスボディを表示する例を Gist に置いてあります。 バージョン 1.19.0 を使用しています。

レスポンスのパース

HttpRequest#setParser メソッド を使って ObjectParser インターフェイスを実装したインスタンスをパーサーとして登録しておくと、レスポンスのパースを任せることができます。

ライブラリに含まれている ObjectParser の実装としては、JsonObjectParser クラスUrlEncodedParser クラス があります。

サンプルコード

/* 必要な import 文
import com.google.api.client.http.GenericUrl;
import com.google.api.client.http.HttpResponse;
import com.google.api.client.http.UrlEncodedParser;
import com.google.api.client.util.GenericData;
*/

// HttpRequest オブジェクトにパーサーを設定しておく。
// (req は HttpRequest オブジェクト)
req.setParser(new UrlEncodedParser());
// リクエスト実行。
HttpResponse res = req.execute();
try {
    // レスポンスのパースを行う。 (上で設定した UrlEncodedParser が使われる。)
    GenericData d = res.parseAs(GenericData.class);
} finally {
    // (以下略)

レスポンスのパース後のクラスを作る

上の例ではパース後のクラスとして GenericData を使用しましたが、どういうパラメータが渡ってくるかわかっている場合、それを受け取るためのクラスを用意しておいて、フィールドに値を設定させることもできます。

例えば、OAuth 1.0 Protocol の Temporary Credentials を取得するためのリクエストのレスポンスをパースする場合を考えてみましょう。 レスポンスの形式は 「oauth_token=xxxxx&oauth_token_secret=xxxxx&oauth_callback_confirmed=true」 というものであることはわかっているので、次のようなクラスでレスポンスを受け取ることができます。 @Key アノテーション をフィールドに付けることで、パースした結果を受け取るフィールドであることを示しています。

/* 必要な import 文
import com.google.api.client.util.GenericData;
import com.google.api.client.util.Key;
*/

// 必ずしも GenericData を継承する必要はないが、継承しておけばフィールドで定義されていないパラメータも受け取ることができる。
public class OAuthTemporaryCredentialResponse extends GenericData {
    @Key("oauth_token")
    public String identifier;
    @Key("oauth_token_secret")
    public String sharedSecret;
    @Key("oauth_callback_confirmed")
    public String callbackConfirmed;
}

そして、パース時にこのクラスを指定することでパース結果を OAuthTemporaryCredentialResponse オブジェクトとして受け取ることができます。

    OAuthTemporaryCredentialResponse d = res.parseAs(OAuthTemporaryCredentialResponse.class);
    System.out.println("identifier: " + d.identifier); // フィールドアクセスによりレスポンスの値にアクセスできる。

関連