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

ソフトウェア開発に関する話を書きます。 最近は主に Android アプリ、Windows アプリ (UWP アプリ)、Java 関係です。

まじめなことを書くつもりでやっています。 適当なことは 「一角獣は夜に啼く」 に書いています。

読んだ: Effective Android

Effective Android

Effective Android

  • 作者: TechBooster,小太刀御禄,出村成和,重田大助,西岡靖代,宮川大輔,柏本和俊,あんざいゆき,八木俊広,木村尭海,小林慎治,有山圭二,中西良明,わかめまさひろ,新井祐一,桝井草介,久郷達也,寺園聖文,shige0501,山下智樹,前田章博,秋葉ちひろ,末広尚義,中澤慧,日高正博,塚田翔也,井形圭介,中川幸哉,山崎誠,山下武志,なまそで,橋爪香織,さとうかずのり,l_b__,ゼロハチネット,長汐祐哉
  • 出版社/メーカー: インプレスジャパン
  • 発売日: 2014/01/17
  • メディア: 単行本(ソフトカバー)
  • この商品を含むブログ (7件) を見る

読みました。 タイトルからは 『Effective C++』 や 『Effective Java』 が連想されますね。 副題として 「アプリケーション開発を効率化する 39 のテクニック集」 と表紙に書かれています。

内容紹介

Androidの機能・端末バリエーションは年々巨大化しています。おぼろげな理解でも試行錯誤によってある程度のことが実現出来ますが、安定動作するアプリ、使っていて気持ちの良いアプリに仕上げる上では、依然きちんと理解する必要のあることが多く存在します。

本書は、Androidアプリ開発へ携わる著者総勢20名によるデザイン/開発上のポイント集です。

日々の開発中にぶつかった問題を掘り下げたもの、Androidソースコードを読み解くことで得られたもの、多くの端末サイズ/解像度へと対応する中で得られたもの、Googleサービス群と連携する中で得られたものなど、日々のアプリ開発を一歩先へと進めるヒントに満ちていることでしょう。

Effective Android - 達人出版会

上記内容紹介にかかれているように、本書は複数人によって書かれた書籍です。 もともと同人誌として発行されていたものなので、わりと各自が好きなことを書いてるようで、基本的には章ごとの体系だった流れのようなものはありません。 ある程度分野ごとに章はまとまっていますし、関連する章が前後に並んでいたりはしますが、基本的にはそれぞれの章を独立に読む、という感じの読み方になるでしょう。

カード UI の実現の仕方や、カード UI にアニメーションを付ける方法、といったすぐに使える UI 上のチップスもあれば、Eclipse の設定ファイルの話や Gradle の話といった開発環境周りの話、SQLiteNFC といったミドルウェア (?) 的な話、便利ライブラリの紹介、それから NDK などのプラットフォーム周りの話といった感じで、内容は多岐にわたっています。

以前、Maven Central Repository への AAR パッケージのアップロード方法を書きましたが、それと同様の内容も本書に収録されてました。

さらには、Git についての話や Java 7、Java 8 の話も書かれています。 Git については、write-tree コマンドや rev-parse コマンドといったマニアックなコマンドが紹介されていて、普段 Git を使っている人でも 「ほえー」 ってなるかもしれません *1Java 7 の話については、API level 19 以降では Java 7 の構文をフルで使えるようになった *2 といったことが書かれていて、そういうことを知らない人にはいろいろ得るところがあると思いますし、Java 8 についてもいろいろ書かれていて勉強になります *3

感想

内容が多岐にわたっており、また、結構マニアックな話題も多いので、いろいろ視野が広がって良かったです。 たとえば、NFC タグの話や SQLiteDatabase の WAL の話、オーディオ周りの話などは 「へー」 という感じで読みました。 普段業務で Android アプリを開発していたり、個人で Android アプリを開発している人で、自分が普段関わらないようなところも含めてチップス集を読みたい、という気持ちがあれば本書はオススメです。 すぐさま業務に活かせるようなチップスもありますし (そうでないものもあります)、読み物としても興味深く読めるでしょう。

一方で、体系だった章立てになっていないという点や、全体的に誰しもにすぐ役立つ情報が多くないという点から、一通り Android アプリ開発できるようになった人に 「とりあえず読め!」 って感じで薦められる本ではないです。 あえてこういうことを書くのは、『Efefctive C++』 や 『Effective Java』 とタイトルが似てるからです *4

読み物的な感じで Android アプリに関して視野を広げたい、って人にお勧めです。

EFFECTIVE JAVA 第2版 (The Java Series)

EFFECTIVE JAVA 第2版 (The Java Series)

『Effective Java』 もお薦めです。

*1:私はなりました。

*2:あくまで構文であり、Java SE 7 のすべての Java API が使えるわけではありません。 まあこれは以前の Java 6 サポートの時からそうでしたが。

*3:Java 8 は今の Android アプリ開発では全く使えないので、Android アプリ開発には活かせませんが。

*4:これらの本は、一通り C++Java を書けるようになった人に 「とりあえず読め!」 って感じで薦められる本です。

Annotations Support Library が Android Studio 0.5.5 でサポートされた

Annotations Support Library の概要

ちゃんとしたドキュメントが見当たらないのですが、 *1 Android Support library のリビジョン 19.1.0 から、新たに Annotations Support Library が追加されました。 このライブラリは、その名のとおり Android アプリ開発時に用いることができるアノテーションの集まりです。 例えば、@NonNull@Nullable といったアノテーションが含まれています。

さらに、Android Studio ではバージョン 0.5.5 からこれらのアノテーションをサポートしており、アノテーションを使うことでいろいろと警告を出してくれるようになっています。

Support for the new annotations which shipped with the most recent version of the support library, such as @NonNull and @Nullable, as well as annotations to declare resource types and valid constants. Add a dependency on com.android.support:support-annotations:+ to use these in your projects. In the upcoming 0.10.x version of the Android Gradle plugin, the plugin will extract these annotations into your libraries' AAR files such that clients of your library can get the same resource type checks as is shown above for the SDK APIs.

Android Studio 0.5.5 Released - Android Tools Project Site

Android Support library については前に記事を書きましたので、合わせて参照ください。

Support Annotation についての公式的なドキュメントは次のページをご覧ください。

Annotations Support Library の使い方

ビルドシステムに Gradle を使っている場合についての説明です。

Android SDK Manager で 「Android Support Repository」 (リビジョン 5 以上) をインストールしたうえで、build.gradle に次のように記述することで Annotations Support Library を使用できます。

dependencies {
    compile 'com.android.support:support-annotations:22.2.0' // バージョン番号は必要に応じて変更してください。
}

使用できるアノテーション紹介

どういうアノテーションがあるのかを紹介します。 バージョン 19.1.0 時点での情報ですので、新しいバージョンでは使用できるアノテーションが増えているかもしれません。

@NonNull@Nullable

これらは、メソッドの返り値が null になりうるかどうかや、メソッドのパラメータとして null を許容するかどうか、といったことを表すのに用いられます。

    private void displayName(@NonNull String name) {
        // ...
    }

例えば、引数として null を許容しないメソッドを定義する場合、上のように @NonNull アノテーションを用いて null を許容しないことを表現できます。

そして、そのように定義されたメソッドの呼び出し時に null を引数として渡すようなコードを書くと、Android Studio 上で次のように警告が表示されます。

f:id:nobuoka:20140510013210p:plain

私は null になりうる変数には xxxOrNull みたいな名前を付けるといった命名規則などで null 周りのバグを減らすように気を付けたりしているのですが、アノテーションIDE によるサポートがあると便利で良さそうですね。

どの種類のリソースを参照するための int 値なのかを示すアノテーション

Android アプリで使用する各種リソースは int 値で参照されます。 どの種類のリソースでも同じ int 型で表されるので、Drawable のリソース ID を受け取るメソッドに、Drawable 以外のリソースの ID を渡すといったことや、そもそもリソースの ID でない単なる数値を渡すといったことも (コード上は) 可能です。

Annotations Support Library には、どの種類のリソースの ID なのかを示すためのアノテーションも含まれています。 例えば、Drawable リソースであることを示すアノテーション@DrawableRes アノテーション です。

    private void receiveDrawableRes(@DrawableRes int resId) {
        // ...
    }

例えば、引数として Drawable リソースの ID を受け取るメソッドを定義する場合、上のように @DrawableRes アノテーションを付けて、引数が Drawable リソースの ID であることを示せます。

このメソッドに Drawable 以外のリソースの ID を渡すと、次のように Android Studio がエラー表示してくれます。

f:id:nobuoka:20140510014441p:plain

@DrawableRes アノテーションの他にも、@AnimRes@ColorRes@StringRes といった、各種リソースに対応したアノテーションが存在します。

@IntDef@StringDef

定数として定義したいくつかの int 型 (あるいは String 型) の値のうちのいずれかを引数として受け取るメソッドを書きたい、ということがままあります。 そんなときに便利なのがこれらのアノテーションです。

普通にメソッドを定義すると、任意の int 値を受け取れるようになってしまいますが、これらのアノテーションを用いて独自のアノテーションを定義することで、メソッドが指定の定数のみを受け取ることを示すことができます。

@IntDef アノテーションを用いて、独自のアノテーション (@NavigationMode アノテーション) を定義する例は次のような感じです。

    @IntDef({NAVIGATION_MODE_STANDARD, NAVIGATION_MODE_LIST, NAVIGATION_MODE_TABS})
    public @interface NavigationMode {}
    public static final int NAVIGATION_MODE_STANDARD = 0;
    public static final int NAVIGATION_MODE_LIST = 1;
    public static final int NAVIGATION_MODE_TABS = 2;

そして、上で定義されたアノテーションを使い、NAVIGATION_MODE_STANDARDNAVIGATION_MODE_LISTNAVIGATION_MODE_TABS のいずれかの値を受け取るメソッドであることを次のように示せます。

    private void navigate(@NavigationMode int navMode) {
        // ...
    }

呼び出し時には定数を使って値を指定しないと、次のようにエラーが表示されます。

f:id:nobuoka:20140510021304p:plain

まとめ

Android Support library のリビジョン 19.1.0 で Annotations Support Library が追加され、Android Studio 0.5.5 でそれらのアノテーションがサポートされました。

著しく開発効率が上がったり、本質的な機能の向上があるわけではなく、あくまで開発の補助に使用できるものではありますが、地味に便利だと思います。 せっかく Android Studio でこのようなアノテーションがサポートされたのですから使っていきましょう!

Effective Android

Effective Android

  • 作者: TechBooster,小太刀御禄,出村成和,重田大助,西岡靖代,宮川大輔,柏本和俊,あんざいゆき,八木俊広,木村尭海,小林慎治,有山圭二,中西良明,わかめまさひろ,新井祐一,桝井草介,久郷達也,寺園聖文,shige0501,山下智樹,前田章博,秋葉ちひろ,末広尚義,中澤慧,日高正博,塚田翔也,井形圭介,中川幸哉,山崎誠,山下武志,なまそで,橋爪香織,さとうかずのり,l_b__,ゼロハチネット,長汐祐哉
  • 出版社/メーカー: インプレスジャパン
  • 発売日: 2014/01/17
  • メディア: 単行本(ソフトカバー)
  • この商品を含むブログ (8件) を見る

変更履歴

  • 2015-06-13 : 「support-annotations ライブラリ」 と記述していたのを 「Annotations Support Library」 に変更。

*1:最近公式的なドキュメントも書かれました。

読んだ: 高速スケーラブル検索エンジン ElasticSearch Server

高速スケーラブル検索エンジン ElasticSearch Server

高速スケーラブル検索エンジン ElasticSearch Server

2014 年 3 月末に発売された Elasticsearch の本を読み終えました。 私が知る限り、現在のところ唯一の日本語で書かれた Elasticsearch に関する書籍です。 書籍の題では 「ElasticSearch」 という表記が使われていますが、これはバージョン 0.90.x 系までの表記で、バージョン 1.0 からは 「Elasticsearch」 (s が小文字) という表記になっているようです。

本書は、ElasticSearch 0.90.11 を対象として書かれていますが、基本的にはバージョン 1.0 以降でも通用します。

対象読者、全体的な内容

本書の序文にも書かれているように、全文検索の初心者、あるいは Elasticsearch の初心者向けの書籍です。

Elasticsearch とは何か、どうやって使用するのか、という最初の一歩の部分からはじまり、データのインデキシングの方法や検索クエリの組み立て方といった検索機能全般について、クラスタ監視やシャードとレプリカの配置制御といったインフラ寄りの話、それからプラグインについての話など、Elasticsearch の基礎的なことが網羅的に記述されています。

コマンドラインから curl コマンドを実行することができて、JSON を知っている、というぐらいの知識さえあれば、本書を読み進めていくことができると思います。

感想

私自身は去年 (2013 年) から Elasticsearch を使っていました。 去年の段階では本書も発売されていませんでしたし、他に良い書籍もありませんでしたので、公式サイトのリファレンスを見て学んでいました。

しかしながら、主にクエリ DSL について調べていたという理由や、英語であるためざっと流し読みするということが難しかったという理由などもあり、公式リファレンスだけでは網羅的な Elasticsearch の知識を得ることができていませんでした。

そんなわけなので私はそこそこ公式リファレンスの知識を持った状態で本書を読み始めたのですが、初心者向けに書かれているだけあって本書の方が公式リファレンスよりもわかりやすく書かれているように思いました。 (日本語だからというのもあるとは思いますが。) 訳も読みやすくて、基本的にはよくわからなくて困るということもないでしょう。

(ただ、下の部分だけはいまだによくわかっていません。 そのうちちゃんと調べます...。)

本書を最初から最後まで読むことで、Elasticsearch の基礎について網羅的に学べました。 これから Elasticsearch を使うから基礎的なことを網羅的に学びたい、という人は本書を読むといいと思います!

JAX-RS アプリケーションで PreMatching フィルタを使ってリクエスト URL を書きかえる

JAX-RS アプリケーションを書いているときに、リクエストされた URI のパスを書きかえて、対応するリソースを書き替えたい場合があります。 そのような時には、PreMatching フィルタを使用できます。

例えば、リクエスト URI のパスがスラッシュで終わっている場合に、パスの末尾に 「.index」 などの文字を追加したいとしましょう。 その場合は次のようなフィルタを書けばよいです。

package info.vividcode.example;

import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerRequestFilter;
import javax.ws.rs.container.PreMatching;
import javax.ws.rs.core.UriBuilder;
import javax.ws.rs.core.UriInfo;
import javax.ws.rs.ext.Provider;

/**
 * リクエスト URI のパスがスラッシュで終わっている場合に、パスの末尾に 「.index」 を追加するフィルタ。
 * 末尾のスラッシュの有無に応じて、ディスパッチされるリソースを別にするため。
 */
@Provider
@PreMatching
public class IndexPathAddingFilter implements ContainerRequestFilter {
    @Override
    public void filter(ContainerRequestContext requestContext) {
        UriInfo uriInfo = requestContext.getUriInfo();
        if (uriInfo.getPath(false).endsWith("/")) {
            UriBuilder uriBuilder = UriBuilder.fromUri(uriInfo.getRequestUri());
            uriBuilder.path(".index");
            requestContext.setRequestUri(uriBuilder.build());
        }
    }
}

JAX-RS では、パスの末尾にスラッシュがあってもなくても同じリソースにマッチするので、パスの末尾にスラッシュがあるかどうかでマッチするリソースを変えたい場合には上のようにするのも 1 つの手だと思います。

JAX-RS アプリケーションの 404 Not Found のカスタマイズ (リソースが見つからない場合)

JAX-RS アプリケーションでリソースが見つからない場合に表示される 404 Not Found のレスポンスの内容を変更したい場合にどうすればいいか、という話。

リソースが見つからない場合: NotFoundException が投げられる

まずは、そもそもの話として、リソースが見つからなかった場合に内部的にどういう処理が行われているのか見てみます。

JAX-RS 2.0 のドキュメントを見ると、3.7.2 節 「Request Matching」 において、リソースクラスやリソースメソッドの選択について書かれています。 そこには、リクエストにマッチするリソースクラスがなかった場合の処理として、次のように書かれていました。

(d) If E is empty then no matching resource can be found, the algorithm terminates and an implementation MUST generate a
NotFoundException (404 status) and no entity

マッチするリソースクラスが存在しない場合、NotFoundException が投げられるようです。 マッチするリソースメソッドがなかった場合も、同様に NotFoundException が投げられると書かれています。

例外をレスポンスにマッピングする: ExceptionMappter<T>

さて、内部的には例外が発生していることがわかりましたので、その例外をうまく扱いたいところです。

JAX-RS には、例外をレスポンスにマッピングする Exception Mapping Provider という仕組みがあります。 JAX-RS 2.0 のドキュメントの 4.4 節 「Exception Mapping Providers」 に次のように書かれています。

Exception mapping providers map a checked or runtime exception to an instance of
Response. An exception mapping provider implements the ExceptionMapper<T>
interface and may be annotated with @Provider for automatic discovery. When choosing an exception mapping provider to map an exception, an implementation MUST use the provider whose generic type is the nearest superclass of the exception

NotFoundException を適当なレスポンスにマッピングするための Exception Mappging Provider を書くことで、リソースが見つからない場合の 404 Not Found をカスタマイズできます。 (もちろん、リソースが見つからない場合のエラー以外にも適用できます。)

サンプルコード

カスタマイズ前

以下のように、JAX-RS 実装として Jersey を使用し、Grizzly 上で JAX-RS アプリケーションを動かしているとします。

// 必要な import 文
import java.net.URI;
import javax.ws.rs.core.UriBuilder;
import org.glassfish.grizzly.http.server.HttpServer;
import org.glassfish.jersey.grizzly2.httpserver.GrizzlyHttpServerFactory;
import org.glassfish.jersey.server.ResourceConfig;

// 処理
URI baseUri = UriBuilder.fromUri("http://localhost/").port(10082).build();
ResourceConfig config = new ResourceConfig();
HttpServer server = GrizzlyHttpServerFactory.createHttpServer(baseUri, config);

上のコードでは、リソースクラスを 1 個も登録していないので、ブラウザで http://localhost:10082/ にアクセスしても 404 Not Found が返ってきます。 (ページ自体は真っ白。)

カスタマイズ後

以下のような Exception Mapping Provider を書いてみます。 単に 「404 Not Found!!!」 という文字列を表示するだけのレスポンスです。

import javax.ws.rs.NotFoundException;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import javax.ws.rs.ext.ExceptionMapper;
import javax.ws.rs.ext.Provider;

@Provider
public class NotFoundExceptionMapper implements ExceptionMapper<NotFoundException> {

    @Override
    public Response toResponse(NotFoundException exception) {
        return Response.status(Status.NOT_FOUND).entity("404 Not Found!!!").build();
    }

}

そして、以下のように ResourceConfig に登録します。

URI baseUri = UriBuilder.fromUri("http://localhost/").port(10082).build();
ResourceConfig config = new ResourceConfig();
config.register(NotFoundExceptionMapper.class);
HttpServer server = GrizzlyHttpServerFactory.createHttpServer(baseUri, config);

これで、リソースが見つからなかった場合にカスタマイズされた 「404 Not Found!!!」 という文字列が返されるようになります。