equalsとhashcodeを実装する(Eclipseで)
今日発見して感動したのでメモ。
EclipseでequalsメソッドとhashCodeを簡単に実装できる。
手順
public class Book { /** ISBN */ private String isbn = ""; /** タイトル */ private String title = ""; /** 著者 */ private String author = ""; }
↑このクラスに対する実装するとして・・・。
private String author = "";
の次の行にカーソルを移動し、「ファイルメニュー > ソース > hashCode() および equals()の生成」をクリック。
出てきたダイアログで、equalsとhashCodeに使用するフィールドを選択する。
たったこれだけで、equals()とhashCode()が実装される。
public class Book { /** ISBN */ private String isbn = ""; /** タイトル */ private String title = ""; /** 著者 */ private String author = ""; /* (非 Javadoc) * @see java.lang.Object#hashCode() */ @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((author == null) ? 0 : author.hashCode()); result = prime * result + ((isbn == null) ? 0 : isbn.hashCode()); result = prime * result + ((title == null) ? 0 : title.hashCode()); return result; } /* (非 Javadoc) * @see java.lang.Object#equals(java.lang.Object) */ @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (!(obj instanceof Book)) { return false; } Book other = (Book) obj; if (author == null) { if (other.author != null) { return false; } } else if (!author.equals(other.author)) { return false; } if (isbn == null) { if (other.isbn != null) { return false; } } else if (!isbn.equals(other.isbn)) { return false; } if (title == null) { if (other.title != null) { return false; } } else if (!title.equals(other.title)) { return false; } return true; } }
いかにも自動生成しましたって感じのソースだけど(特にequals
メソッド)、十分実用に耐えうると思う。
ずっと放置していたWebサービスを公開してみる - Ninewords
このサービスは現在休止中です
Nine Words - Daily "9" hot words
戯言
人気RSSランキングページを追加しました
Amazon新着/人気RSSジェネレータにランキングページを追加しました。
デザインセンスをどうにかしたい><
日記のデザインを変えました
今更ながら公開デザイン一覧の存在を知りました。
素晴らしいデザインがたくさんありました。
GAE + Maven2 + Eclipseの連携 (2010/09最新)
GAE + Maven2 + Eclipseの連携で参考にさせていただいた記事が更新されていたのでメモ。
どうやらEclipse3.6の登場でm2eclipseプラグインに変更があったたため*1、以前の方法が使えなくなったらしい。
新しいバージョンではプロジェクトを作成するmvn
コマンドのarchetypeVersion
が1.1.2
から1.3.1
に変更された。
mvn org.apache.maven.plugins:maven-archetype-plugin:2.0-alpha-4:generate -DarchetypeGroupId=org.beardedgeeks -DarchetypeArtifactId=gae-eclipse-maven-archetype -DarchetypeVersion=1.3.1 -DarchetypeRepository=http://beardedgeeks.googlecode.com/svn/repository/releases
参照先の記事では既存のプロジェクトに対するMavenビルダーの変更方法も紹介されている。
ちなみに、プロジェクト直下のwarフォルダ(targetフォルダへのリンク)は廃止されたらしい。
GAEをJUnitで単体テストするときにはまった3つの罠
はまりまくって貴重な祝日が台無しになったので憂さ晴らしエントリ。
やろうとしたことは、GAEのURLFetchService
を使って取得したHTTPResponseをいじくりまわすロジックのテスト。
罠1:そのまま実行できない
何も考えずにJUnitでテストコードを書いて実行するとException
が発生する。
The API package 'urlfetch' or call 'Fetch()' was not found.
実行したのは以下のようなテストコード。デバッグしてみると、service.fetch(url)
の部分で例外が発生している模様。
import static org.junit.Assert.fail; import java.net.URL; import org.junit.Test; import com.google.appengine.api.urlfetch.HTTPResponse; import com.google.appengine.api.urlfetch.URLFetchService; import com.google.appengine.api.urlfetch.URLFetchServiceFactory; public class UrlFetchServiceTest { @Test public void test() { doTest(); } private void doTest() { try { URL url = new URL("http://feeds.feedburner.com/hatena/b/hotentry"); URLFetchService service = URLFetchServiceFactory.getURLFetchService(); HTTPResponse response = service.fetch(url); // ← ここで例外が発生してしまう // responseをいじくりまわすメソッドを呼び出す } catch (Exception e) { fail(e.getMessage()); } } }
考えてもわからないのでとりあえずGoogleの公式ドキュメント(日本語版)を見たところ、ローカルの実行環境構築にはApiProxy.Environment
をimplements
したTestEnvironment
クラスを作成した上でApiProxy
に設定すれば良いらしい。
ApiProxy.setEnvironmentForCurrentThread(new TestEnvironment()); ApiProxy.setDelegate(new ApiProxyLocalImpl(new File(".")){});
見よう見まねでTestEnvironment
クラスを作った。ここまではうまくいった。
ところが、ApiProxy.setDelegate(new ApiProxyLocalImpl(new File(".")){});
を記述しようと思ったら・・・。
罠2:日本版のドキュメントが古い*1
ApiProxyLocalImpl
クラスのコンストラクタが呼び出せない><
どうやらSDKのバージョンアップでApiProxyLocalImpl
コンストラクタがpublic
→private
に変わったらしい*2。
途方に暮れつつググってたら、英語版のドキュメントを発見。曰く、
The most important class in this package is
com.google.appengine.tools.development.testing.LocalServiceTestHelper
, which handles all of the necessary environment setup and gives you a top-level point of configuration for all the local services you might want to access in your tests. In order to write a test that accesses a specific local service, create an instance ofLocalServiceTestHelper
with acom.google.appengine.tools.development.testing.LocalServiceTestConfig
implementation for that specific local service, then callsetUp()
on yourLocalServiceTestHelper
instance before each test andtearDown()
after each test.
つまり、テストコード内でLocalServiceTestHelper
を使いたいサービスでもってインスタンス化し、テスト前とテスト後にそれぞれhelper#setUp
とhelper#tearDown
を呼び出せと。
これを踏まえて前のコードを変更すると、
import static org.junit.Assert.fail; import java.net.URL; import org.junit.After; import org.junit.Before; import org.junit.Test; import com.google.appengine.api.urlfetch.HTTPResponse; import com.google.appengine.api.urlfetch.URLFetchService; import com.google.appengine.api.urlfetch.URLFetchServiceFactory; import com.google.appengine.tools.development.testing.LocalServiceTestHelper; import com.google.appengine.tools.development.testing.LocalURLFetchServiceTestConfig; public class UrlFetchServiceTest { // UrlFetchServiceTestを使うのでLocalURLFetchServiceTestConfigでインスタンス化する private final LocalServiceTestHelper helper = new LocalServiceTestHelper(new LocalURLFetchServiceTestConfig()); @Before public void setUp() { helper.setUp(); } @After public void tearDown() { helper.setUp(); } @Test public void test() { doTest(); } // .... 以下は前のコードと同じ }
日本語版で書いてあった古いバージョンの方法よりかなりシンプルになっている。
コンパイルに必要なappengine-testing.jar
はMavenリポジトリにインストールされていれば
<dependency> <groupId>com.google.appengine</groupId> <artifactId>appengine-testing</artifactId> <version>1.3.7</version> <type>jar</type> <scope>test</scope> </dependency>
を記述するだけで追加できる。まだインストールしていない場合はこのサイトで入手できる。
で、いざ実行!
The API package 'urlfetch' or call 'Fetch()' was not found.
・・・同じエラーが出た。
3.ランタイムライブラリが必要
まぁこれはドキュメントに書いてあるのを見逃していただけなんだけど、ランタイムライブラリにappengine-api-stubs.jar
*3が必要らしい。
<dependency> <groupId>com.google.appengine</groupId> <artifactId>appengine-api-stubs</artifactId> <version>1.3.7</version> <type>jar</type> <scope>test</scope> </dependency>
ライブラリを追加したら無事動いた。
感想
解決して良かった。そしてこれからは英語ドキュメントを先に読もう、と心に誓った。
その他メモ
LocalServiceTestHelper
のコンストラクタは可変引数になっているため、複数サービスを含むテストをするときはまとめてインスタンス化できる。
// 例)Webサイトをスクレイピングしてデータベースに格納するロジックのテストを行う。 private final LocalServiceTestHelper helper = new LocalServiceTestHelper(new LocalURLFetchServiceTestConfig(), new LocalDatastoreServiceTestConfig() );
LocalServiceTestHelper
の引数に指定可能なTestConfig
クラスは以下があることを確認。LocalBlobstoreServiceTest
LocalCapabilitiesServiceTest
LocalChannelServiceTest
LocalDatastoreServiceTest
LocalImagesServiceTest
LocalMailServiceTest
LocalMemcacheServiceTest
LocalTaskQueueTest
LocalURLFetchServiceTest
LocalUserServiceTest
LocalXMPPServiceTest
ウェブユーザビリティの法則について
自分用メモ。ウェブユーザビリティの法則 改訂第2版を途中まで読んだ。
ユーザーは"実際には"どんな風にウェブを使っているのか
- 人はページ内の文章を読まない。ざっと見るのみ
- 人は最良の選択に時間をかけるよりも、ある程度満足できるところで妥協する
- 最善なものを選ぶ(最適化)ではなく、最初に出会った妥当なものを選ぶ(満足化)
各ページのナビゲーション
どのページでも以下がわかるようにする
- サイトID
- ページ名
- セクション、サブセクション
- ローカルナビゲーション
- 「現在地」表示
- 検索
トップページ
以下がわかるようにする
- サイトのポイント
- タグラインをつけるなど。
- どこから始めればよいか。