<?xml version="1.0" encoding="UTF-8" ?> <rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>デバッグ</title><link>http://blogs.wankuma.com/nagise/category/1445.aspx</link><description>デバッグ</description><managingEditor>凪瀬</managingEditor><dc:language>ja-JP</dc:language><generator>.Text Version 0.95.2004.102</generator><item><dc:creator>凪瀬</dc:creator><title>ボクシング変換とMapのキー</title><link>http://blogs.wankuma.com/nagise/archive/2009/03/02/169096.aspx</link><pubDate>Mon, 02 Mar 2009 21:59:00 GMT</pubDate><guid>http://blogs.wankuma.com/nagise/archive/2009/03/02/169096.aspx</guid><wfw:comment>http://blogs.wankuma.com/nagise/comments/169096.aspx</wfw:comment><comments>http://blogs.wankuma.com/nagise/archive/2009/03/02/169096.aspx#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://blogs.wankuma.com/nagise/comments/commentRss/169096.aspx</wfw:commentRss><trackback:ping>http://blogs.wankuma.com/nagise/services/trackbacks/169096.aspx</trackback:ping><description>&lt;p&gt;今日はまったバグ。&lt;/p&gt;

&lt;p&gt;&lt;code&gt;
&lt;font color="#000000"&gt;Map&amp;lt;Long,&amp;nbsp;String&amp;gt;&amp;nbsp;map&amp;nbsp;=&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;new&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;HashMap&amp;lt;Long,&amp;nbsp;String&amp;gt;&lt;/font&gt;&lt;font color="#000000"&gt;()&lt;/font&gt;&lt;font color="#000000"&gt;;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#000000"&gt;map.put&lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#990000"&gt;1L&lt;/font&gt;&lt;font color="#000000"&gt;,&amp;nbsp;&lt;/font&gt;&lt;font color="#2a00ff"&gt;&amp;#34;1&amp;#34;&lt;/font&gt;&lt;font color="#000000"&gt;)&lt;/font&gt;&lt;font color="#000000"&gt;;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#000000"&gt;System.out.println&lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;map.get&lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#990000"&gt;1&lt;/font&gt;&lt;font color="#000000"&gt;))&lt;/font&gt;&lt;font color="#000000"&gt;;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#000000"&gt;System.out.println&lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;map.get&lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#990000"&gt;1L&lt;/font&gt;&lt;font color="#000000"&gt;))&lt;/font&gt;&lt;font color="#000000"&gt;;&lt;/font&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;キーに1 (ボクシング変換でIntegerになる)を渡した場合と1Lを渡した場合で挙動が異なるというオチ。Map.get()の引数がObjectなので両方受け付けちゃうんですね。&lt;/p&gt;&lt;img src ="http://blogs.wankuma.com/nagise/aggbug/169096.aspx" width = "1" height = "1" /&gt;</description></item><item><dc:creator>凪瀬</dc:creator><title>Seaserのホットデプロイとリフレクション</title><link>http://blogs.wankuma.com/nagise/archive/2008/06/17/144134.aspx</link><pubDate>Tue, 17 Jun 2008 15:39:00 GMT</pubDate><guid>http://blogs.wankuma.com/nagise/archive/2008/06/17/144134.aspx</guid><wfw:comment>http://blogs.wankuma.com/nagise/comments/144134.aspx</wfw:comment><comments>http://blogs.wankuma.com/nagise/archive/2008/06/17/144134.aspx#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://blogs.wankuma.com/nagise/comments/commentRss/144134.aspx</wfw:commentRss><trackback:ping>http://blogs.wankuma.com/nagise/services/trackbacks/144134.aspx</trackback:ping><description>&lt;p&gt;Seaserのホットデプロイは開発向けにはなかなか便利ですが、これを使えるようにフレームワークの構成を考えるのはかなりしんどいものがあります。今回はハマったポイントとしてリフレクションを取り上げます。&lt;/p&gt;

&lt;h4&gt;Seaserのホットデプロイ&lt;/h4&gt;

&lt;p&gt;Seaserの&lt;a href="http://s2container.seasar.org/2.4/ja/DIContainer.html#SMARTdeploy"&gt;ホットデプロイ&lt;/a&gt;は
実行時に特定箇所でクラスローダを毎回新しくするというシンプルなものです。&lt;/p&gt;

&lt;p&gt;結構、割り切った作りになっているなぁというのが感想ですが、そのシンプルさと原理からいろいろと制限事項も生まれてしまう。&lt;/p&gt;

&lt;p&gt;今回、私がハマったところはフレームワーク内でリフレクションをする際に、クラスローダの違いからClassCastExceptionを出したり、NoSuchMethodExceptionを出したりしたことでした。&lt;/p&gt;

&lt;h4&gt;クラスローダの基礎知識&lt;/h4&gt;

&lt;p&gt;まず、基礎知識としてクラスローダが違う場合、同じClassでも代入互換性がありません。Classの同一性は、Class自身とそのクラスローダによって定められます。&lt;/p&gt;

&lt;p&gt;次に、クラスローダは階層構造をなしていて、まず親クラスローダにロード処理が移譲されます。&lt;/p&gt;

&lt;p&gt;&lt;a href="http://java.sun.com/javase/ja/6/docs/ja/api/java/lang/ClassLoader.html"&gt;ClassLoader&lt;/a&gt;
&lt;blockquote&gt;
ClassLoader クラスは、委譲モデルを使ってクラスとリソースを探します。ClassLoader の各インスタンスは、関連する親クラスローダーを持ちます。クラスまたはリソースを見つけるために呼び出されると、ClassLoader インスタンスはそれ自体でクラスまたはリソースの検索を試みる前に、その検索を親クラスに委譲します。「ブートストラップクラスローダー」と呼ばれる仮想マシンの組み込みクラスローダーはそれ自体では親を持たず、ClassLoader インスタンスの親として動作します。
&lt;/blockquote&gt;
&lt;/p&gt;

&lt;p&gt;このため、親が同じである場合は、同じクラスローダ(つまるところ親)で読み込まれることで代入互換を持つことがあります。&lt;/p&gt;

&lt;h4&gt;クラスローダを跨ぐ場合のClassCastException&lt;/h4&gt;

&lt;p&gt;Seaserのホットデプロイは&lt;a href="http://s2container.seasar.org/2.4/s2-framework/ja/apidocs/org/seasar/framework/container/hotdeploy/HotdeployUtil.html"&gt;
HotdeployUtil&lt;/a&gt;のstart()とstop()の間でクラスローダが変わることで実現しています。&lt;/p&gt;

&lt;p&gt;なので、この区間の中と外ではクラスローダが異なります。そのため、戻り値のClassCastExceptionが発生することがあります。&lt;/p&gt;

&lt;p&gt;&lt;code&gt;
&lt;font color="#000000"&gt;SingletonS2ContainerFactory.init&lt;/font&gt;&lt;font color="#000000"&gt;()&lt;/font&gt;&lt;font color="#000000"&gt;;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#000000"&gt;S2Container&amp;nbsp;container&amp;nbsp;=&amp;nbsp;SingletonS2ContainerFactory.getContainer&lt;/font&gt;&lt;font color="#000000"&gt;()&lt;/font&gt;&lt;font color="#000000"&gt;;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#000000"&gt;HotdeployUtil.start&lt;/font&gt;&lt;font color="#000000"&gt;()&lt;/font&gt;&lt;font color="#000000"&gt;;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#000000"&gt;Object&amp;nbsp;o&amp;nbsp;=&amp;nbsp;container.getComponent&lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#2a00ff"&gt;&amp;#34;testLogic&amp;#34;&lt;/font&gt;&lt;font color="#000000"&gt;)&lt;/font&gt;&lt;font color="#000000"&gt;;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#000000"&gt;System.out.println&lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;o.getClass&lt;/font&gt;&lt;font color="#000000"&gt;()&lt;/font&gt;&lt;font color="#000000"&gt;.getClassLoader&lt;/font&gt;&lt;font color="#000000"&gt;())&lt;/font&gt;&lt;font color="#000000"&gt;;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#000000"&gt;Hoge&amp;nbsp;hoge&amp;nbsp;=&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;Hoge&lt;/font&gt;&lt;font color="#000000"&gt;)&lt;/font&gt;&lt;font color="#000000"&gt;o;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#000000"&gt;HotdeployUtil.stop&lt;/font&gt;&lt;font color="#000000"&gt;()&lt;/font&gt;&lt;font color="#000000"&gt;;&lt;/font&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;
log4j:WARN No appenders could be found for logger (org.seasar.framework.container.factory.S2ContainerFactory).&lt;br&gt;
log4j:WARN Please initialize the log4j system properly.&lt;br&gt;
org.seasar.framework.container.hotdeploy.HotdeployClassLoader@6e70c7&lt;br&gt;
Exception in thread "main" java.lang.ClassCastException: test.logic.impl.TestLogicImpl cannot be cast to test.Hoge&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;at test.LoaderTest.main(LoaderTest.java:19)
&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;こうした再読込をおこなうタイプのクラスローダは親クラスローダへの委譲を行わないことで実現できます。親へ委譲してしまうと読み込み済みのクラスをリフレッシュすることができません。&lt;/p&gt;

&lt;p&gt;しかし、この場合、クラスローダ越境ができなくなります。通常は、親への委譲を先に行うことで、共通して読み込まれるクラスには互換があったわけですが、クラスをロードしなおすために、親への委譲を行わないようにすると、上記例のようにClassCastExceptionとなってしまうのです。&lt;/p&gt;

&lt;h4&gt;リフレクションの際のメソッドシグネチャにも注意！&lt;/h4&gt;

&lt;p&gt;こうしたクラスローダを跨いだ箇所でリフレクションを行っていると、わかりにくいバグに遭遇することがあります。&lt;/p&gt;

&lt;p&gt;&lt;code&gt;
&lt;font color="#000000"&gt;SingletonS2ContainerFactory.init&lt;/font&gt;&lt;font color="#000000"&gt;()&lt;/font&gt;&lt;font color="#000000"&gt;;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#000000"&gt;S2Container&amp;nbsp;container&amp;nbsp;=&amp;nbsp;SingletonS2ContainerFactory.getContainer&lt;/font&gt;&lt;font color="#000000"&gt;()&lt;/font&gt;&lt;font color="#000000"&gt;;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#000000"&gt;HotdeployUtil.start&lt;/font&gt;&lt;font color="#000000"&gt;()&lt;/font&gt;&lt;font color="#000000"&gt;;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#000000"&gt;Object&amp;nbsp;o&amp;nbsp;=&amp;nbsp;container.getComponent&lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#2a00ff"&gt;&amp;#34;testLogic&amp;#34;&lt;/font&gt;&lt;font color="#000000"&gt;)&lt;/font&gt;&lt;font color="#000000"&gt;;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#000000"&gt;Method&lt;/font&gt;&lt;font color="#000000"&gt;[]&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;ms&amp;nbsp;=&amp;nbsp;o.getClass&lt;/font&gt;&lt;font color="#000000"&gt;()&lt;/font&gt;&lt;font color="#000000"&gt;.getMethods&lt;/font&gt;&lt;font color="#000000"&gt;()&lt;/font&gt;&lt;font color="#000000"&gt;;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#000000"&gt;System.out.println&lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;Arrays.toString&lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;ms&lt;/font&gt;&lt;font color="#000000"&gt;))&lt;/font&gt;&lt;font color="#000000"&gt;;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#000000"&gt;Method&amp;nbsp;m&amp;nbsp;=&amp;nbsp;o.getClass&lt;/font&gt;&lt;font color="#000000"&gt;()&lt;/font&gt;&lt;font color="#000000"&gt;.getMethod&lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#2a00ff"&gt;&amp;#34;setHoge&amp;#34;&lt;/font&gt;&lt;font color="#000000"&gt;,&amp;nbsp;Hoge.&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;class&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;)&lt;/font&gt;&lt;font color="#000000"&gt;;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#000000"&gt;HotdeployUtil.stop&lt;/font&gt;&lt;font color="#000000"&gt;()&lt;/font&gt;&lt;font color="#000000"&gt;;&lt;/font&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;
log4j:WARN No appenders could be found for logger (org.seasar.framework.container.factory.S2ContainerFactory).&lt;br&gt;
log4j:WARN Please initialize the log4j system properly.&lt;br&gt;
[&lt;strong&gt;public void test.logic.impl.TestLogicImpl.setHoge(test.Hoge)&lt;/strong&gt;, public test.Hoge test.logic.impl.TestLogicImpl.getHoge(), public native int java.lang.Object.hashCode(), public final native java.lang.Class java.lang.Object.getClass(), public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException, public final void java.lang.Object.wait() throws java.lang.InterruptedException, public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException, public boolean java.lang.Object.equals(java.lang.Object), public java.lang.String java.lang.Object.toString(), public final native void java.lang.Object.notify(), public final native void java.lang.Object.notifyAll()]&lt;br&gt;
Exception in thread "main" java.lang.NoSuchMethodException: test.logic.impl.TestLogicImpl.setHoge(test.Hoge)&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;at java.lang.Class.getMethod(Unknown Source)&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;at test.LoaderTest.main(LoaderTest.java:24)
&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;ご覧のように、setHoge(Hoge)が存在しているにも関わらず、NoSuchMethodExceptionが投げられsetHoge(Hoge)はない！と言われてしまうのです。これは、getMethod()の引数に渡すHoge.classと、読み込まれたコンポーネントのHoge.classでクラスローダが異なるためです。&lt;/p&gt;

&lt;h4&gt;開発用と割り切って全体を囲ってしまう&lt;/h4&gt;

&lt;p&gt;クラスローダの越境は非常に厄介ですので、処理の頭からお尻までまるごとクラスローダを差し替えるように使うのが無難です。&lt;/p&gt;

&lt;p&gt;Servletであれば、ホットデプロイ用の
&lt;a href="http://s2container.seasar.org/2.4/s2-framework/ja/apidocs/org/seasar/framework/container/hotdeploy/HotdeployFilter.html"&gt;HotdeployFilter&lt;/a&gt;
が用意されていますのでそちらでリクエストの全体で差し替えるほうがよいでしょうね。&lt;/p&gt;&lt;img src ="http://blogs.wankuma.com/nagise/aggbug/144134.aspx" width = "1" height = "1" /&gt;</description></item><item><dc:creator>凪瀬</dc:creator><title>タスクマネージャではJavaのメモリ使用量は測れない</title><link>http://blogs.wankuma.com/nagise/archive/2007/12/04/111707.aspx</link><pubDate>Tue, 04 Dec 2007 15:30:00 GMT</pubDate><guid>http://blogs.wankuma.com/nagise/archive/2007/12/04/111707.aspx</guid><wfw:comment>http://blogs.wankuma.com/nagise/comments/111707.aspx</wfw:comment><comments>http://blogs.wankuma.com/nagise/archive/2007/12/04/111707.aspx#Feedback</comments><slash:comments>70</slash:comments><wfw:commentRss>http://blogs.wankuma.com/nagise/comments/commentRss/111707.aspx</wfw:commentRss><trackback:ping>http://blogs.wankuma.com/nagise/services/trackbacks/111707.aspx</trackback:ping><description>&lt;p&gt;&lt;a href="http://www.atmarkit.co.jp/bbs/phpBB/viewtopic.php?topic=42518&amp;forum=12"&gt;@ITより&lt;/a&gt;。
Javaのメモリ消費量について調査する際にWindowsのタスクマネージャでJava VMの使用しているメモリ量を
見ても駄目だという話。&lt;/p&gt;

&lt;p&gt;メモリリークの調査だとか、使用する資源量の調査だとか、いろいろな理由があってメモリ消費量を
計測したいという話はあちこちで見かけます。ことJavaの場合、メモリはOSから直接供給されるのではなく
VMが間に入って管理を行うためOSからプロセスの消費しているメモリ量を見ても実態がつかめないことを
まず理解せねばなりません。&lt;/p&gt;

&lt;h4&gt;オブジェクトがGCされてもメモリ消費量が減らない！と騒ぐ前に&lt;/h4&gt;

&lt;p&gt;JavaのVMはメモリが必要になったときにその都度OSにメモリを供給してもらうわけでは&lt;strong&gt;ありません&lt;/strong&gt;。&lt;/p&gt;

&lt;p&gt;ある程度まとまった量のメモリをOSから貰い、それをプールとして、オブジェクトがnewされるたびに分割して供給するわけです。
そして、オブジェクトの参照がなくなってGC(ガーベッジコレクション)によって回収された場合にも、
プールに戻すだけでOSに細かく返していくわけではありません。&lt;/p&gt;

&lt;p&gt;そのため、オブジェクトを作ったり解放したりを繰り返しているJavaプログラムを動かしていても、
Windowsのタスクマネージャから見るとメモリ量は変わらないことがあります。
タスクマネージャから見ているのはVM全体が確保しているメモリだからです。&lt;/p&gt;

&lt;h4&gt;JavaのVM内でのメモリの使用状況を確認するには&lt;/h4&gt;

&lt;p&gt;簡素な方法としては、
&lt;a href="http://java.sun.com/j2se/1.5.0/ja/docs/ja/api/java/lang/Runtime.html#freeMemory()"&gt;java.lang.Runtime#freeMemory()&lt;/a&gt;を使う手法です。&lt;br&gt;
この値をSystem.out.println()で出力することで、そのときの空き容量を得られますから
コードを直接いじりながらデバッグしているような段階では手軽に計測できますね。&lt;/p&gt;

&lt;p&gt;ツールを使う場合は
&lt;a href="http://java.sun.com/j2se/1.5.0/ja/docs/ja/guide/management/jconsole.html"&gt;jconsole&lt;/a&gt;
を用います。これはJDKに付属しているツールですので別途ダウンロードする必要はありません。&lt;/p&gt;&lt;img src ="http://blogs.wankuma.com/nagise/aggbug/111707.aspx" width = "1" height = "1" /&gt;</description></item><item><dc:creator>凪瀬</dc:creator><title>ミニマムコードの書き方</title><link>http://blogs.wankuma.com/nagise/archive/2007/12/02/111385.aspx</link><pubDate>Sun, 02 Dec 2007 19:37:00 GMT</pubDate><guid>http://blogs.wankuma.com/nagise/archive/2007/12/02/111385.aspx</guid><wfw:comment>http://blogs.wankuma.com/nagise/comments/111385.aspx</wfw:comment><comments>http://blogs.wankuma.com/nagise/archive/2007/12/02/111385.aspx#Feedback</comments><slash:comments>7</slash:comments><wfw:commentRss>http://blogs.wankuma.com/nagise/comments/commentRss/111385.aspx</wfw:commentRss><trackback:ping>http://blogs.wankuma.com/nagise/services/trackbacks/111385.aspx</trackback:ping><description>&lt;p&gt;技術系のコミュニケーションにはミニマムコードは欠かせません。
現象を100の言葉を並べて説明するよりも動作するプログラムを1回動かしてもらう方がよく理解してもらえるのです。
まさに百聞は一見に如かずといったところでしょう。&lt;/p&gt;

&lt;h4&gt;ミニマムコードに求められること&lt;/h4&gt;

&lt;p&gt;ミニマムコードとはなんでしょうか？「ミニマム」＋「コード」ですから、最小限のコードといった意味合いです。
最小限だけれども、それだけで動作する完全なプログラムである必要があります。
該当部分のコードの抜粋とは違うのです。&lt;/p&gt;

&lt;p&gt;&lt;ul&gt;
&lt;li&gt;それだけで動作するコードであること
&lt;li&gt;テーマを再現できること
&lt;li&gt;テーマ以外が極力含まれないコードであること
&lt;/ul&gt;&lt;/p&gt;

&lt;p&gt;テーマと言っているのは、その時々で話題にしている議題のことです。
ある現象について話しているならその現象を起こせるコードということです。
コードは余計なものが含まれていないことが理想的です。&lt;/p&gt;

&lt;p&gt;余計なコードがあると、本来テーマにしたい部分が埋もれてしまいます。
コードを隠すならコードの中というわけです。論点をはっきりさせるために、関係ないところはそぎ落とします。
設定ミスなどの場合、そぎ落としていく過程で何が悪かったのかが分かることがあります。
最小限だと動くのに、本番のコードは動かないとなれば、その差分の部分にバグがあるわけです。&lt;/p&gt;

&lt;h4&gt;科学実験に学ぶ検証手法&lt;/h4&gt;

&lt;p&gt;あるコードがうまく動かないとしましょう。問題がどこにあるのかを検証するには、科学の実験の手法が踏襲します。
&lt;strong&gt;該当の箇所に問題があるか、ないかを知りたければ、ターゲット以外が全く同じ状態で検証を行う&lt;/strong&gt;のです。&lt;/p&gt;

&lt;p&gt;一度にいくつもの部分に修正を入れると、どれが作用したのかわからなくなってしまいます。
また、外的要因によって結果が違っているのかもしれません。
そういった場合に正しく問題個所を絞り込むことができなくなってしまいます。&lt;/p&gt;

&lt;p&gt;こういった科学実験の基礎は理学や工学系の大学に行くと学生実験という形で学びます。
大学以前の学校での理科の実験なども基本的には同じですが、
それほど科学的検証を厳しく問われないので印象としては薄いかもしれません。
（厳しい大学だとレポートの再提出に学生は苦しむ）&lt;/p&gt;

&lt;p&gt;オカルトなどでは、因果関係を正しく掴まないことによるものが多くあります。
とくに、結果ありきでの実験のレポートは見るに堪えません。
結論付けたい事柄があって、そのことに都合がよいように実験をしてはいけません。
プログラムのバグの検証も、頭の中で「XXが悪いに違いない」などと強く思うと
堂々巡りでなかなか解決できないところに迷い込むかもしれません。&lt;/p&gt;

&lt;h4&gt;部品単位で検品を行う&lt;/h4&gt;

&lt;p&gt;プログラムはパーツパーツで動作確認をとって組み上げる必要があります。
小さなパーツが正しく動くかどうかテストすることは簡単です。
しかく、組み合わさって大きな機能になると、動作確認は格段に難しい。&lt;/p&gt;

&lt;p&gt;boolean値がひとつ増えるだけでテストケースは2倍になるのです。
全部組み上げてから部品のテストを行うなどと考えてはいけません。
急がば回れということです。&lt;/p&gt;

&lt;p&gt;仕様がよくわからないといったときには、とにかくミニマムコードを書いて動かして検証しましょう。
もし、理解できない動きがあるのであれば、そのときはコードを示して質問するなどすればよい。&lt;/p&gt;

&lt;p&gt;問題の切り分けもできず、長いプログラムを掲示板に張り付けたところで、
労力をかけてまで読んでくれる人は稀です。
ミニマムコードにまでそぎ落としてあれば検証してくれる人はぐっと増えることでしょう。&lt;/p&gt;&lt;img src ="http://blogs.wankuma.com/nagise/aggbug/111385.aspx" width = "1" height = "1" /&gt;</description></item><item><dc:creator>凪瀬</dc:creator><title>プログラムにおける数学的帰納法の難しさ</title><link>http://blogs.wankuma.com/nagise/archive/2007/11/30/111136.aspx</link><pubDate>Fri, 30 Nov 2007 23:46:00 GMT</pubDate><guid>http://blogs.wankuma.com/nagise/archive/2007/11/30/111136.aspx</guid><wfw:comment>http://blogs.wankuma.com/nagise/comments/111136.aspx</wfw:comment><comments>http://blogs.wankuma.com/nagise/archive/2007/11/30/111136.aspx#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://blogs.wankuma.com/nagise/comments/commentRss/111136.aspx</wfw:commentRss><trackback:ping>http://blogs.wankuma.com/nagise/services/trackbacks/111136.aspx</trackback:ping><description>&lt;p&gt;επιστημη氏の&lt;a href="http://blogs.wankuma.com/episteme/archive/2007/11/29/110920.aspx"&gt;白箱試験&lt;/a&gt;にて簡単なプログラムを例に
ホワイトボックステストでは数学的帰納法の観点で境界値をピックアップしてテストケースを削減することを取り上げています。&lt;/p&gt;

&lt;p&gt;しかし、数学の場合の数学的帰納法と違って、コンピュータにおける数学的帰納法には落とし穴があるのです。&lt;/p&gt;

&lt;p&gt;&lt;code&gt;
//&amp;nbsp;引数を2倍して返す&lt;br&gt;
int&amp;nbsp;hoge(int x)&amp;nbsp;{&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;x&amp;nbsp;*&amp;nbsp;2;&lt;br&gt;
}
&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;一見すると、0で正常に動き、引数がnのとき、n+1でも成り立ちそうです。
負の値のときも動きそうですから、-1,0,1でテストすれば大丈夫そうに思えますね。&lt;/p&gt;

&lt;p&gt;しかし、0から順に初めて、1,2,3と進めていくと、ある値を超えたときにオーバーフローして値がおかしくなってしまいます。&lt;/p&gt;

&lt;p&gt;「でも、オーバーフローするまでの範囲では大丈夫なんだろう？テストの区間をうまく区切ればいいだけさ」&lt;/p&gt;

&lt;p&gt;では、どうやってうまく区切れていて、見落としがないことを証明できるのでしょうか？&lt;br&gt;
この困難さこそが、テストケースをうまく作ることの難しさなのです。&lt;/p&gt;&lt;img src ="http://blogs.wankuma.com/nagise/aggbug/111136.aspx" width = "1" height = "1" /&gt;</description></item><item><dc:creator>凪瀬</dc:creator><title>数学的帰納法で完全なテストを行えるか？</title><link>http://blogs.wankuma.com/nagise/archive/2007/11/29/110906.aspx</link><pubDate>Thu, 29 Nov 2007 15:00:00 GMT</pubDate><guid>http://blogs.wankuma.com/nagise/archive/2007/11/29/110906.aspx</guid><wfw:comment>http://blogs.wankuma.com/nagise/comments/110906.aspx</wfw:comment><comments>http://blogs.wankuma.com/nagise/archive/2007/11/29/110906.aspx#Feedback</comments><slash:comments>328</slash:comments><wfw:commentRss>http://blogs.wankuma.com/nagise/comments/commentRss/110906.aspx</wfw:commentRss><trackback:ping>http://blogs.wankuma.com/nagise/services/trackbacks/110906.aspx</trackback:ping><description>&lt;p&gt;以前、&lt;A href="http://blogs.wankuma.com/nagise/archive/2007/10/22/103276.aspx"&gt;完全なテストは不可能だ&lt;/a&gt;
という稿を書いたのですが、これに対して
&lt;a href="http://selfkleptomaniac.org/archives/379"&gt;反論しているページ&lt;/a&gt;
を見つけたので考察しておきます。&lt;/p&gt;

&lt;h4&gt;反論の骨子&lt;/h4&gt;

&lt;p&gt;該当ページの文章が短いので全文引用となってしまいますが、法的な引用の要件を満たせると思うので引用します。&lt;/p&gt;

&lt;p&gt;&lt;blockquote&gt;
&lt;p&gt;思うに、それは論理学でいうところの帰納法で解決できるのではなかろうか。&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;&lt;A href="http://blogs.wankuma.com/nagise/archive/2007/10/22/103276.aspx"&gt;完全なテストは不可能だ&lt;/a&gt;:&lt;br /&gt;
さて、プログラムの話に戻ります。intの引数を2個とる場合、その組み合わせは1600京ほどに なるということを先の稿で述べました。 そして、バグが「ある」ことを証明する場合、バグの例をひとつ探し出せばよいのに対し、 バグが「ない」ことを証明するにはこの1600京のパターンすべてを網羅して検査し、 全て正常に動いたということを提示しなければなりません。&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;数学でも、全ての数を計算したわけではないのに成立している定理は山ほどある。というかそうでないものの方が少ないはず。&lt;/p&gt;
&lt;p&gt;悪魔の証明、という目の付けどころは悪くないのに。まあ、ちょと前に自分でも&lt;a href="http://selfkleptomaniac.org/archives/359"&gt;取り上げた&lt;/a&gt;わけだが。&lt;/p&gt;
&lt;/blockquote&gt;&lt;/p&gt;

&lt;p&gt;つまり、帰納法を用いることで全てを演算することなく正しさを証明できるのではないか？という主張ですね。&lt;/p&gt;

&lt;h4&gt;帰納法とは何か？&lt;/h4&gt;

&lt;p&gt;まず帰納法とはなんでしょうか。概要を知るにはwikipediaがてっとり早いので該当項目を見て見ましょう。&lt;/p&gt;

&lt;p&gt;&lt;a href="http://ja.wikipedia.org/wiki/%E5%B8%B0%E7%B4%8D"&gt;http://ja.wikipedia.org/wiki/%E5%B8%B0%E7%B4%8D
&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;blockquote&gt;
&lt;p&gt;&lt;b&gt;帰納&lt;/b&gt;（&lt;b&gt;きのう&lt;/b&gt;、Induction）法とは、個別的・特殊的な事例から一般的・普遍的な規則を見出そうとする&lt;A href="http://blogs.wankuma.com/wiki/%E6%8E%A8%E8%AB%96" title="推論"&gt;推論&lt;/a&gt;方法のこと。対義語は&lt;b&gt;&lt;A href="http://blogs.wankuma.com/wiki/%E6%BC%94%E7%B9%B9" title="演繹"&gt;演繹&lt;/a&gt;&lt;/b&gt;法。演繹においては前提が&lt;A href="http://blogs.wankuma.com/wiki/%E7%9C%9F" title="真"&gt;真&lt;/a&gt;であれば結論も&lt;A href="http://blogs.wankuma.com/wiki/%E5%BF%85%E7%84%B6" title="必然"&gt;必然&lt;/a&gt;的に真であるが、帰納においては前提が真であるからといって結論が真であることは保証されない。&lt;/p&gt;&lt;/blockquote&gt;&lt;/p&gt;

&lt;p&gt;帰納法は真実を得られません。一部の事例から、全体を推論するのですが、論理の飛躍が含まれます。&lt;br&gt;
例えば、intを引数にとるメソッドに対し、-1,0,1の３つの値を入れた際にうまく動いたからといって、
すべての値に対して正しく動作するとは言えませんよね。&lt;/p&gt;

&lt;p&gt;帰納法とは3つうまくいったんだから、全部の値でうまくいくはずだという推論ですから、
帰納法を用いてメソッドの完全性を求めることはできません。&lt;/p&gt;

&lt;h4&gt;数学的帰納法という名の演繹法&lt;/h4&gt;

&lt;p&gt;「数学でも、全ての数を計算したわけではないのに成立している定理は山ほどある。」と述べていることから、
「帰納法」といっているのは多分、数学的帰納法のことを指しているのではないかと思われます。&lt;/p&gt;

&lt;p&gt;さて、数学的帰納法というのは帰納法という名が付いていますが、実際には演繹法（えんえきほう）です。&lt;/p&gt;

&lt;p&gt;&lt;a href="http://ja.wikipedia.org/wiki/%E6%95%B0%E5%AD%A6%E7%9A%84%E5%B8%B0%E7%B4%8D%E6%B3%95"&gt;
http://ja.wikipedia.org/wiki/%E6%95%B0%E5%AD%A6%E7%9A%84%E5%B8%B0%E7%B4%8D%E6%B3%95&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;blockquote&gt;
&lt;p&gt;&lt;b&gt;数学的帰納法&lt;/b&gt;（&lt;b&gt;すうがくてききのうほう&lt;/b&gt;）とは、有限回の議論で&lt;A href="http://blogs.wankuma.com/wiki/%E5%8F%AF%E7%AE%97%E6%BF%83%E5%BA%A6" title="可算濃度"&gt;可算&lt;/a&gt;無限個の対象に対する命題を証明するための&lt;A href="http://blogs.wankuma.com/wiki/%E6%95%B0%E5%AD%A6" title="数学"&gt;数学&lt;/a&gt;の論法である。次のような手順で&lt;A href="http://blogs.wankuma.com/wiki/%E8%87%AA%E7%84%B6%E6%95%B0" title="自然数"&gt;自然数&lt;/a&gt;全体に関する&lt;A href="http://blogs.wankuma.com/wiki/%E5%91%BD%E9%A1%8C" title="命題"&gt;命題&lt;/a&gt; P(&lt;i&gt;n&lt;/i&gt;) (&lt;i&gt;n&lt;/i&gt;∈&lt;b&gt;N&lt;/b&gt;) が&lt;A href="http://blogs.wankuma.com/wiki/%E7%9C%9F" title="真"&gt;真&lt;/a&gt;であることを&lt;A href="http://blogs.wankuma.com/wiki/%E8%A8%BC%E6%98%8E" title="証明"&gt;証明&lt;/a&gt;する論法である。&lt;/p&gt;
&lt;dl&gt;
&lt;dd&gt;
&lt;ol&gt;
&lt;li&gt;P(0) は真である。&lt;/li&gt;
&lt;li&gt;任意の自然数 &lt;i&gt;k&lt;/i&gt; に対し，P(&lt;i&gt;k&lt;/i&gt;) が真であれば，P(&lt;i&gt;k&lt;/i&gt;+1) も真である。&lt;/li&gt;
&lt;/ol&gt;
&lt;/dd&gt;
&lt;dd&gt;よって任意の自然数 &lt;i&gt;n&lt;/i&gt; について P(&lt;i&gt;n&lt;/i&gt;) は真である。&lt;/dd&gt;
&lt;/dl&gt;
&lt;p&gt;イメージとしては、2 により次々と次の命題の正しさが伝播されていくことになる。つまり、1 によりまず P(0) は正しく、P(0) と 2 により P(1) は正しく、P(1) と 2 により P(2) は正しく、以下これが果てしなく続いていく。このことによって任意の自然数 &lt;i&gt;n&lt;/i&gt; について P(&lt;i&gt;n&lt;/i&gt;) が正しいことが保証される。&lt;/p&gt;
&lt;p&gt;なお、数学的「&lt;A href="http://blogs.wankuma.com/wiki/%E5%B8%B0%E7%B4%8D" title="帰納"&gt;帰納&lt;/a&gt;法」という名前がつけられているが、数学的帰納法の解法プロセス自体は帰納法ではなく&lt;A href="http://blogs.wankuma.com/wiki/%E6%BC%94%E7%B9%B9" title="演繹"&gt;演繹&lt;/a&gt;法である。先に述べた、「&lt;i&gt;2 により次々と次の命題の正しさが伝播されてい&lt;/i&gt;」った結果証明されていく様子が帰納のように見えるためつけられたにすぎない。&lt;/p&gt;
&lt;/blockquote&gt;&lt;/p&gt;

&lt;p&gt;これは、学校で習いましたよね。&lt;br&gt;
数学的帰納法はドミノ倒しに似ています。&lt;/p&gt;

&lt;p&gt;&lt;ul&gt;
&lt;li&gt;あるドミノが倒れたら、次のドミノが倒れるようにしておく
&lt;li&gt;最初のドミノを倒す
&lt;/ul&gt;&lt;/p&gt;

&lt;p&gt;このふたつがポイントです。ドミノを倒すことで&lt;strong&gt;全ての数を計算する&lt;/strong&gt;のです。&lt;br&gt;
ですから、「数学でも、全ての数を計算したわけではないのに成立している定理は山ほどある」というのは
多分に誤解を含んでいます。数学的帰納法に拠らない証明で成立している定理もありますが、
&lt;strong&gt;数学的帰納法で証明されている定理に関して言えば全てを計算している&lt;/strong&gt;のです。&lt;/p&gt;

&lt;p&gt;ドミノが勝手に倒れてくれるので準備を整えたら無限のかなたまで手間無く一瞬で計算できるだけのことです。&lt;/p&gt;

&lt;h4&gt;テストに数学的帰納法を適用するには&lt;/h4&gt;

&lt;p&gt;ブラックボックステストで数学的帰納法を扱う術はありません。
あるドミノが倒れたら次のドミノも倒れるという証明ができないからです。&lt;br&gt;
ブラックボックステストでは実行した結果を仕様と照らし合わせて等しいかみる必要があります。
実行せずに正しい答えを返すことを証明することは不可能です。&lt;/p&gt;

&lt;p&gt;となれば、ホワイトボックステスト的な手法をとらざるを得ません。
それはもはや、プログラムのコードが正しく機能することを数学的に証明を導くことに等しい重労働です。&lt;/p&gt;

&lt;p&gt;このようなアプローチは
&lt;a href="http://ja.wikipedia.org/wiki/%E5%BD%A2%E5%BC%8F%E7%9A%84%E6%A4%9C%E8%A8%BC"&gt;形式的検証&lt;/a&gt;
と呼ばれています。&lt;/p&gt;

&lt;p&gt;このアプローチでプログラムの完全な正しさを証明しようとするのであれば、
数学者を大量に雇いいれ、幾千もあるメソッドに対してそれぞれ独自の証明を人力で解いていかないといけません。
複雑なメソッドの正しさを数学的に証明しようとした場合、それは世紀の難問にも等しい難度を誇ることでしょう。&lt;/p&gt;

&lt;p&gt;指摘もとのblogの言葉を借りるならば「帰納法、という目の付けどころは悪くないのに。」といったところでしょうか。&lt;/p&gt;&lt;img src ="http://blogs.wankuma.com/nagise/aggbug/110906.aspx" width = "1" height = "1" /&gt;</description></item><item><dc:creator>凪瀬</dc:creator><title>AOPトランザクション＋キャッシュの組み合わせは同期に気をつける</title><link>http://blogs.wankuma.com/nagise/archive/2007/10/06/100259.aspx</link><pubDate>Sat, 06 Oct 2007 15:08:00 GMT</pubDate><guid>http://blogs.wankuma.com/nagise/archive/2007/10/06/100259.aspx</guid><wfw:comment>http://blogs.wankuma.com/nagise/comments/100259.aspx</wfw:comment><comments>http://blogs.wankuma.com/nagise/archive/2007/10/06/100259.aspx#Feedback</comments><slash:comments>40</slash:comments><wfw:commentRss>http://blogs.wankuma.com/nagise/comments/commentRss/100259.aspx</wfw:commentRss><trackback:ping>http://blogs.wankuma.com/nagise/services/trackbacks/100259.aspx</trackback:ping><description>&lt;p&gt;先日遭遇した深い落とし穴を紹介します。
以下のようなシステムを開発している方は同様の問題がないかチェックしてください。&lt;/p&gt;

&lt;p&gt;&lt;/ul&gt;
&lt;li&gt;AOPでトランザクションを管理している
&lt;li&gt;一部のマスタテーブルをDBから読み込んだあとシステム内でキャッシュしている
&lt;li&gt;マスタメンテナンス画面などで更新があった場合にキャッシュをクリアしている
&lt;/ul&gt;&lt;/p&gt;

&lt;h4&gt;問題となるコード&lt;/h4&gt;

&lt;p&gt;Springや、SeasarといったDIコンテナなどに付随するAOPの機能を用いてトランザクション管理していると、
DBをいじる部分のメソッド内ではcommitとかrollbackとか記述する必要がありません。
これは非常に便利で、人的なコーディングでのcommit漏れ、rollback漏れがないので
バグも入り込みにくく効率のよいものです。&lt;/p&gt;

&lt;p&gt;私のやっているプロジェクトではSpringframeworkのAOPの機能を用いてトランザクション管理を行っています。&lt;/p&gt;

&lt;p&gt;そして、システム内でよく使われ、更新頻度の低いUserテーブルは、DBアクセスのオーバーヘッドを軽減するために
システム内でキャッシュしているのです。&lt;/p&gt;

&lt;p&gt;&lt;code&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#3f5fbf"&gt;/**&amp;nbsp;ユーザのキャッシュ&amp;nbsp;*/&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;Map&amp;lt;Integer,&amp;nbsp;User&amp;gt;&amp;nbsp;cache;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#3f5fbf"&gt;/**&amp;nbsp;ユーザ取得処理&amp;nbsp;*/&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;public&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;User&amp;nbsp;getUser&lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;int&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;userId&lt;/font&gt;&lt;font color="#000000"&gt;)&amp;nbsp;{&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;synchronized&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;this&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;.cache&lt;/font&gt;&lt;font color="#000000"&gt;)&amp;nbsp;{&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#3f7f5f"&gt;//&amp;nbsp;キャッシュにあればキャッシュされたUserを返す&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;if&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;this&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;.cache.containsKey&lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;userId&lt;/font&gt;&lt;font color="#000000"&gt;))&amp;nbsp;{&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;return&amp;nbsp;this&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;.cache.get&lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;userId&lt;/font&gt;&lt;font color="#000000"&gt;)&lt;/font&gt;&lt;font color="#000000"&gt;;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;}&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#3f7f5f"&gt;//&amp;nbsp;なければDBから読み込む&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;return&amp;nbsp;this&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;.userDao.getUser&lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;userId&lt;/font&gt;&lt;font color="#000000"&gt;)&lt;/font&gt;&lt;font color="#000000"&gt;;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;}&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;}&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#3f5fbf"&gt;/**&amp;nbsp;キャッシュの削除処理&amp;nbsp;*/&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;public&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;void&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;clearCache&lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;int&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;userId&lt;/font&gt;&lt;font color="#000000"&gt;)&amp;nbsp;{&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;synchronized&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;this&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;.cache&lt;/font&gt;&lt;font color="#000000"&gt;)&amp;nbsp;{&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;this&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;.cache.remove&lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;userId&lt;/font&gt;&lt;font color="#000000"&gt;)&lt;/font&gt;&lt;font color="#000000"&gt;;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;}&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;}&lt;/font&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;キャッシュの実装は上記のようなもので、内部で同期をとってあります。&lt;br&gt;
そして、UserのUPDATE処理では&lt;/p&gt;

&lt;p&gt;&lt;code&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;public&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;void&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;update&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;User&amp;nbsp;user&lt;/font&gt;&lt;font color="#000000"&gt;)&amp;nbsp;{&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#3f7f5f"&gt;//&amp;nbsp;UPDATE&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;this&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;.userDao.update&lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;user&lt;/font&gt;&lt;font color="#000000"&gt;)&lt;/font&gt;&lt;font color="#000000"&gt;;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#3f7f5f"&gt;//&amp;nbsp;キャッシュから更新対象のUserを削除&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#3f7f5f"&gt;//&amp;nbsp;次回Userを取得しようとした時にキャッシュに最新のUserが読み込まれる&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;clearCache&lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;user.getUserId&lt;/font&gt;&lt;font color="#000000"&gt;())&lt;/font&gt;&lt;font color="#000000"&gt;;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;}&lt;/font&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;といった作りにしていたのです。このupdateメソッドに対してAOPでトランザクションがかけられるわけですね。&lt;/p&gt;

&lt;h4&gt;Commit前、キャッシュクリア後の魔&lt;/h4&gt;

&lt;p&gt;前置きが長くなりました。問題が発生するのはこのupdateの際のキャッシュのクリアの後です。&lt;/p&gt;

&lt;p&gt;並列して走っているスレッドがあり、update後のキャッシュクリア後、しかしDBのcommitが完了する前のタイミングで
getUser()してしまったのです。&lt;br&gt;
すると、DBはcommitされる前ですから、更新前のUser情報が読み込まれ、キャッシュには古い情報が残り続けるというわけ。&lt;/p&gt;

&lt;p&gt;DBのトランザクションとキャッシュクリアは不可分に行わなければならないのです。&lt;br&gt;
しかし、AOPでトランザクションを管理している場合、メソッド境界を跨ぐことになるので
synchronized文で容易にくくってやることができない…。&lt;/p&gt;

&lt;p&gt;わざわざキャッシュ管理している場所だけ特殊なトランザクション処理を別途書いてAOPを適用してやる必要が出てきてしまいました。&lt;br&gt;
似たようなシステム構成をしている方、潜在的なバグを孕んでいる可能性があります。早急にチェックするほうがよいでしょう。&lt;/p&gt;&lt;img src ="http://blogs.wankuma.com/nagise/aggbug/100259.aspx" width = "1" height = "1" /&gt;</description></item><item><dc:creator>凪瀬</dc:creator><title>防衛的プログラミング - Javaのセッション管理</title><link>http://blogs.wankuma.com/nagise/archive/2007/10/02/99111.aspx</link><pubDate>Tue, 02 Oct 2007 14:24:00 GMT</pubDate><guid>http://blogs.wankuma.com/nagise/archive/2007/10/02/99111.aspx</guid><wfw:comment>http://blogs.wankuma.com/nagise/comments/99111.aspx</wfw:comment><comments>http://blogs.wankuma.com/nagise/archive/2007/10/02/99111.aspx#Feedback</comments><slash:comments>98</slash:comments><wfw:commentRss>http://blogs.wankuma.com/nagise/comments/commentRss/99111.aspx</wfw:commentRss><trackback:ping>http://blogs.wankuma.com/nagise/services/trackbacks/99111.aspx</trackback:ping><description>&lt;p&gt;Programming SHOT BARへようこそ。今回はWebアプリケーションでのセッション管理の際の防衛的プログラミングです。&lt;/p&gt;

&lt;p&gt;数日前にASP.NETでのセッション管理の話題がわんくま内で盛り上がっていましたが
(&lt;A href="http://blogs.wankuma.com/mymio/archive/2007/09/30/98792.aspx"&gt;
けろ様のページ&lt;/a&gt;がまとめになっているのかな？)、
.NET系は詳しくないのであまり口が挟めず&amp;#8230;。&lt;/p&gt;

&lt;p&gt;私の理解ではJavaの場合のセッション管理と概念は同じ、しかし、実装が違うという程度のようなので
本質的な問題は一緒なのではないかと捉えています(@ITの
&lt;a href="http://www.atmarkit.co.jp/fdotnet/entwebapp/entwebapp06/entwebapp06_01.html"&gt;
記事&lt;/a&gt;を参考にしました)。&lt;br&gt;
とりあえず、この稿ではJavaの大規模開発でセッションを扱う場合の防衛策に注視してお送りします。&lt;/p&gt;

&lt;h4&gt;セッションに値を格納するには&lt;/h4&gt;

&lt;p&gt;以下はセッションに値を格納する簡単なサンプルプログラムです。&lt;/p&gt;

&lt;p&gt;&lt;code&gt;
&lt;font color="#7f0055"&gt;&lt;b&gt;public&amp;nbsp;class&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;SampleServlet&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;extends&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;HttpServlet&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;{&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#3f5fbf"&gt;/**&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#3f5fbf"&gt;*&amp;nbsp;&lt;/font&gt;&lt;font color="#7f9fbf"&gt;@see&amp;nbsp;&lt;/font&gt;&lt;font color="#3f5fbf"&gt;javax.servlet.http.HttpServlet#doGet(javax.servlet.http.HttpServletRequest,&amp;nbsp;javax.servlet.http.HttpServletResponse)&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#3f5fbf"&gt;*/&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#646464"&gt;@Override&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;protected&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;void&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;doGet&lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;HttpServletRequest&amp;nbsp;request,&amp;nbsp;HttpServletResponse&amp;nbsp;response&lt;/font&gt;&lt;font color="#000000"&gt;)&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;throws&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;ServletException,&amp;nbsp;IOException&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;{&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;HttpSession&amp;nbsp;session&amp;nbsp;=&amp;nbsp;request.getSession&lt;/font&gt;&lt;font color="#000000"&gt;()&lt;/font&gt;&lt;font color="#000000"&gt;;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;session.setAttribute&lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#2a00ff"&gt;&amp;#34;test&amp;#34;&lt;/font&gt;&lt;font color="#000000"&gt;,&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;new&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;Object&lt;/font&gt;&lt;font color="#000000"&gt;())&lt;/font&gt;&lt;font color="#000000"&gt;;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;}&lt;/font&gt;&lt;br /&gt;
&lt;font color="#000000"&gt;}&lt;/font&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;HttpServletRequestオブジェクトからセッションを表すHttpSessionオブジェクトを取得していることがわかりますね。
これは、&lt;strong&gt;HttpServletRequestオブジェクトを参照できるあらゆる場所からセッションを操作される
可能性がある&lt;/strong&gt;ことを意味しています。&lt;/p&gt;

&lt;p&gt;セッションには無秩序になんでも格納すればよいというものではありません。
格納するのは使うことを想定して格納するわけです。
ところが、無秩序に格納してしまうと、どこで格納したものを参照しようとしているのか、
わからなくなってしまいます。
格納されているデータがどうもおかしい、となれば、出所を突き止めなければなりません。
しかし、誰もが自由にセッションでデータを置けるのだとしたら、
誰が置いたデータなのか出所が不明になってしまうわけです。これでは困ります。&lt;/p&gt;

&lt;h4&gt;人的運用でのセッションの管理の限界&lt;/h4&gt;

&lt;p&gt;業務でシステムを作る場合、少なくともどういうキーでどこのモジュールが何を格納するのか、
そして、それを参照するのはどこなのか(汎用データの場合は参照元は管理しないことが多いでしょう)
といったことを書類で管理します。&lt;/p&gt;

&lt;p&gt;しかし、書類でしか管理されていない場合、ひっそりとセッションに情報を格納しても、
何かよほどの機会でもない限り、発覚しないわけです。
しかも、大規模なシステム開発というのは100人以上の人が入り乱れて開発していたりしますから、&lt;br&gt;
「セッションへの値の格納には書面で報告し、許可を得ること」&lt;br&gt;
とお触れを出したところで行き渡らないこともあります。
全体会議を開いて注意事項を述べたとしても、人の入れ替わりも多いですから、
それ以後にプロジェクトに参加した人は「聞いていないよ、そんなこと」となってしまうこともあります。&lt;/p&gt;

&lt;p&gt;人に対する啓蒙活動を無駄だとは言いませんが、確実ではないことは(残念ながら)間違いないことなのです。&lt;/p&gt;

&lt;h4&gt;プログラムで防衛を試みる&lt;/h4&gt;

&lt;p&gt;人に守らせるという根性論ではうまくいかないとなれば、プログラムで機械的にはじく方法論を考えることになります。
故意にせよ、事故にせよ、管理外のセッション操作は検出して警告しないといけません。&lt;/p&gt;

&lt;p&gt;しかし、HttpSessionオブジェクトはHttpServletRequestから取得できるわけですし、
HttpServletRequestはインターフェースで実装はサーブレットコンテナによって作られ、
Servletの引数に渡される代物なのです。&lt;/p&gt;

&lt;p&gt;突破口はjavax.servlet.Filterにあります。&lt;br&gt;
FilterはServletの処理の前に噛ませることが出来る、文字通りフィルタなのです。
ここでHttpServletRequestをGoFデザインパターンのProxyパターンで
セッション操作に対して警告するように細工したHttpServletRequestに差し替えれば
システム全体でセッションをいじろうとした際に警告することが出来ます。&lt;/p&gt;

&lt;p&gt;まずFilterでは&lt;/p&gt;

&lt;p&gt;&lt;code&gt;
&lt;font color="#7f0055"&gt;&lt;b&gt;public&amp;nbsp;class&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;ReadOnlySessionFilter&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;implements&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;Filter&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;{&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;public&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;void&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;doFilter&lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;ServletRequest&amp;nbsp;request,&amp;nbsp;ServletResponse&amp;nbsp;response,&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;FilterChain&amp;nbsp;chain&lt;/font&gt;&lt;font color="#000000"&gt;)&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;throws&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;IOException,&amp;nbsp;ServletException&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;{&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;chain.doFilter&lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;new&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;HttpServletRequestProxy&lt;/font&gt;&lt;font color="#000000"&gt;((&lt;/font&gt;&lt;font color="#000000"&gt;HttpServletRequest&lt;/font&gt;&lt;font color="#000000"&gt;)&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;request&lt;/font&gt;&lt;font color="#000000"&gt;)&lt;/font&gt;&lt;font color="#000000"&gt;,&amp;nbsp;response&lt;/font&gt;&lt;font color="#000000"&gt;)&lt;/font&gt;&lt;font color="#000000"&gt;;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;}&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;public&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;void&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;init&lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;FilterConfig&amp;nbsp;config&lt;/font&gt;&lt;font color="#000000"&gt;)&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;throws&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;ServletException&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;{&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#3f7f5f"&gt;//&amp;nbsp;TODO&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;}&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;public&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;void&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;destroy&lt;/font&gt;&lt;font color="#000000"&gt;()&amp;nbsp;{&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#3f7f5f"&gt;//&amp;nbsp;TODO&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;}&lt;/font&gt;&lt;br /&gt;
&lt;font color="#000000"&gt;}&lt;/font&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;といったように、chain.doFilter()の引数の時点でHttpServletRequestに細工します。
HttpServletRequestの実装は&lt;/p&gt;

&lt;p&gt;&lt;code&gt;
&lt;font color="#7f0055"&gt;&lt;b&gt;public&amp;nbsp;class&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;HttpServletRequestProxy&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;implements&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;HttpServletRequest&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;{&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;private&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;HttpServletRequest&amp;nbsp;request;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;public&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;HttpServletRequestProxy&lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;HttpServletRequest&amp;nbsp;request&lt;/font&gt;&lt;font color="#000000"&gt;)&amp;nbsp;{&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;this&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;.request&amp;nbsp;=&amp;nbsp;request;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;}&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#3f5fbf"&gt;/**&amp;nbsp;ラップして返す&amp;nbsp;*/&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;public&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;HttpSession&amp;nbsp;getSession&lt;/font&gt;&lt;font color="#000000"&gt;()&amp;nbsp;{&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;return&amp;nbsp;new&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;HttpSessionProxy&lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;this&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;.request.getSession&lt;/font&gt;&lt;font color="#000000"&gt;())&lt;/font&gt;&lt;font color="#000000"&gt;;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;}&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#3f7f5f"&gt;//&amp;nbsp;以下各メソッドをthis.request.xxx()として委譲&lt;/font&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;と細工したHttpSessionを返すようにし、HttpSessionの実装では&lt;/p&gt;

&lt;p&gt;&lt;code&gt;
&lt;font color="#7f0055"&gt;&lt;b&gt;public&amp;nbsp;class&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;HttpSessionProxy&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;implements&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;HttpSession&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;{&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;private&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;HttpSession&amp;nbsp;session;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;public&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;HttpSessionProxy&lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;HttpSession&amp;nbsp;session&lt;/font&gt;&lt;font color="#000000"&gt;)&amp;nbsp;{&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;this&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;.session&amp;nbsp;=&amp;nbsp;session;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;}&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;public&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;void&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;setAttribute&lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;String&amp;nbsp;arg0,&amp;nbsp;Object&amp;nbsp;arg1&lt;/font&gt;&lt;font color="#000000"&gt;)&amp;nbsp;{&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;throw&amp;nbsp;new&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;UnsupportedOperationException&lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#2a00ff"&gt;&amp;#34;管理クラス以外からのセッション操作は禁じられています&amp;#34;&lt;/font&gt;&lt;font color="#000000"&gt;)&lt;/font&gt;&lt;font color="#000000"&gt;;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;}&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#3f5fbf"&gt;/**&amp;nbsp;同一パッケージ内の管理クラスから設定する場合に用いる迂回路&amp;nbsp;*/&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;void&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;setAttributeInner&lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;String&amp;nbsp;arg0,&amp;nbsp;Object&amp;nbsp;arg1&lt;/font&gt;&lt;font color="#000000"&gt;)&amp;nbsp;{&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;this&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;.session.setAttribute&lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;arg0,&amp;nbsp;arg1&lt;/font&gt;&lt;font color="#000000"&gt;)&lt;/font&gt;&lt;font color="#000000"&gt;;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;}&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#3f7f5f"&gt;//&amp;nbsp;以下各メソッドをthis.session.xxx()として委譲&lt;/font&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;といったように、UnsupportedOperationExceptionをthrowするように仕込んでおきます。
このままでは、セッションになにも格納できないのでアクセスレベルをパッケージプライベートにした
setAttributeInner()を作っておいて、管理クラスからのアクセスだけを受け付けるようにします。&lt;/p&gt;

&lt;p&gt;このような工夫をすることで、セッションへのデータの格納を検出し、警告することが出来ます。&lt;/p&gt;

&lt;h4&gt;問題点&lt;/h4&gt;

&lt;p&gt;このような細工をしてしまうと、フレームワークなどで暗黙にセッションにデータを格納したり
しているようなケースがあると動いてくれません。使えないケースもあると思います。&lt;/p&gt;

&lt;p&gt;また、サンプルではざっくり省略していますがHttpServletRequestもHttpSessionも
メソッド数の多いインターフェースであるため、Proxyクラスを作るのは結構大変です。
また、サンプルでは省略していますが、本当は他にもオーバーライドする必要のあるメソッドがあります。&lt;/p&gt;

&lt;p&gt;このようなクラスは開発時には意義がありますが、本番運用時には不要であるため、
テストの段階で取り除いてやる必要があるでしょう。&lt;/p&gt;

&lt;p&gt;大規模システムとなると、技術力も理解もさまざまな人が入り乱れて開発しますから、
こういった防衛策を地味に重ねることがトラブルを未然に防ぎ、全体の品質を向上させ、
開発効率を高めることとなります。&lt;/p&gt;&lt;img src ="http://blogs.wankuma.com/nagise/aggbug/99111.aspx" width = "1" height = "1" /&gt;</description></item><item><dc:creator>凪瀬</dc:creator><title>Objectよ、汝の出自を示せ</title><link>http://blogs.wankuma.com/nagise/archive/2007/08/20/91054.aspx</link><pubDate>Mon, 20 Aug 2007 12:04:00 GMT</pubDate><guid>http://blogs.wankuma.com/nagise/archive/2007/08/20/91054.aspx</guid><wfw:comment>http://blogs.wankuma.com/nagise/comments/91054.aspx</wfw:comment><comments>http://blogs.wankuma.com/nagise/archive/2007/08/20/91054.aspx#Feedback</comments><slash:comments>7</slash:comments><wfw:commentRss>http://blogs.wankuma.com/nagise/comments/commentRss/91054.aspx</wfw:commentRss><trackback:ping>http://blogs.wankuma.com/nagise/services/trackbacks/91054.aspx</trackback:ping><description>&lt;P&gt;いらっしゃいませ。&lt;BR&gt;某国産の食品の品質がいろいろといわれた昨今ですが、やはり、流通路というか出自というのは重要な情報ですよね。&lt;BR&gt;なお、当店の素材はできるだけ本家の厳選された素材に基づくようにしております。&lt;/P&gt;
&lt;H4&gt;スタックトレースでの追跡&lt;/H4&gt;
&lt;P&gt;デバッグの際に非常に役立つスタックトレース。活用していますか？&lt;BR&gt;これはスレッドの流れを示しています。いわば流通路のようなものです。&lt;/P&gt;
&lt;P&gt;メソッドに不正な引数が渡された場合、この流通路を遡ればどこの誰がばったもんを流したのか調査することが出来ます。犯人を見つけたらとっちめてやりましょう。&lt;/P&gt;
&lt;P&gt;しかし、キャッシュされるオブジェクトや、staticフィールドに保持されるオブジェクトなどスレッドの流れとは一旦隔絶される場合、トレースを追いかけても犯人をつかめないことがあります。&lt;/P&gt;
&lt;P&gt;&lt;code&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#3f5fbf"&gt;/**&amp;nbsp;Object置き場。ここに置いたのを処理する&amp;nbsp;*/&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;private&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;Object&amp;nbsp;object;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#3f5fbf"&gt;/**&amp;nbsp;置き場にObjectを置く&amp;nbsp;*/&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;public&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;void&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;setObject&lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;Object&amp;nbsp;object&lt;/font&gt;&lt;font color="#000000"&gt;)&amp;nbsp;{&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;this&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;.object&amp;nbsp;=&amp;nbsp;object;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;}&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#3f5fbf"&gt;/**&amp;nbsp;置き場のデータを処理するメソッド&amp;nbsp;*/&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;public&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;void&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;hoge&lt;/font&gt;&lt;font color="#000000"&gt;()&amp;nbsp;{&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;Object&amp;nbsp;o&amp;nbsp;=&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;this&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;.object;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#3f7f5f"&gt;//&amp;nbsp;置き場にあるデータを使って処理を進める&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#3f7f5f"&gt;//&amp;nbsp;...&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;}&lt;/font&gt;&lt;/code&gt;&lt;P&gt;

&lt;P&gt;このコードではhoge()メソッドの呼び出しに直接手渡しでオブジェクトが渡されるわけではありません。そのため、何時どこで誰がObject置き場にデータを置いたのか、スタックトレースからは追いかけることができません。&lt;/P&gt;
&lt;H4&gt;オブジェクトの出自&lt;/H4&gt;
&lt;P&gt;このスタックトレース、プログラムで扱うことができるようになっています。 Thread#getStackTrace()で対象スレッドの現時点でのスタックトレースを取得することが出来ます。&lt;BR&gt;オブジェクトの生成時にこれをとっておいたらどうでしょうか？&lt;/P&gt;

&lt;p&gt;&lt;code&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#3f5fbf"&gt;/**&amp;nbsp;インスタンス生成時のスタックトレース&amp;nbsp;*/&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;private&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;StackTraceElement&lt;/font&gt;&lt;font color="#000000"&gt;[]&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;createLog;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#3f5fbf"&gt;/**&amp;nbsp;コンストラクタ&amp;nbsp;*/&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;public&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;TraceTest&lt;/font&gt;&lt;font color="#000000"&gt;()&amp;nbsp;{&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#3f7f5f"&gt;//&amp;nbsp;カレントスレッドからスタックトレースを取得&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;this&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;.createLog&amp;nbsp;=&amp;nbsp;Thread.currentThread&lt;/font&gt;&lt;font color="#000000"&gt;()&lt;/font&gt;&lt;font color="#000000"&gt;.getStackTrace&lt;/font&gt;&lt;font color="#000000"&gt;()&lt;/font&gt;&lt;font color="#000000"&gt;;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;}&lt;/font&gt;&lt;/code&gt;&lt;/p&gt;

&lt;P&gt;このように、オブジェクトにスタックトレースの保管フィールドを用意し、コンストラクタの時点でスタックトレースをとっておきます。&lt;BR&gt;すると、デバッグ時にオブジェクトの作られた場所が分かるという寸法です。&lt;/P&gt;
&lt;P&gt;いかがでしょうか。これでデバッグの効率が上がると思いませんか？&lt;/P&gt;
&lt;H4&gt;環境ごとの注意点&lt;/H4&gt;
&lt;P&gt;Thread#getStackTrace()はJavaSE5.0からのサポートです。&lt;BR&gt;JDK1.4の場合はExceptionをnewして生成したExceptionからgetStackTrace()してやることで同様の効果を得られます。&lt;/P&gt;
&lt;P&gt;StackTraceElementクラスがJDK1.4からのサポートなので、JDK1.3以前の場合はExceptionをnewして printStackTrace(PrintStream)を利用し、ByteArrayOutputStreamか何かに繋げた PrintStreamを作成してそこにトレースを書き出すという手法を使います。文字列情報になってしまいますが、デバッグには十分でしょう。&lt;/P&gt;
&lt;P&gt;なお、C#でもほぼ同等のことができるようですね。具体的なやり方は&amp;#8230;誰かが書いてくれることを期待しましょう。&lt;/P&gt;&lt;img src ="http://blogs.wankuma.com/nagise/aggbug/91054.aspx" width = "1" height = "1" /&gt;</description></item></channel></rss>