Schema Namespace について
そろそろForce.comのバージョンもWinter' 14になる季節となりました。(あぁ!更新試験....)
それに先立って、ApexのリファレンスもVersion 29.0 となってますね。それにしても、v29.0になってリファレンスの構成も大幅に見直した模様で、v28.0までに慣れていると、欲しい情報がどこにあったかなーとすぐに見つけられません。。(まぁ、そのうち慣れるでしょう、ということで。)
さて、Reference Guideの章をみると、やたらと
〜 Namespace
とネームスペース名がついて説明されるようになってます。いよいよネームスペースを定義できるようになる日が近いのかな?と期待させるような展開ですねw
とにかくApexクラスファイルをフラットに管理するのをなんとかして欲しい
この中で、Schema NamespaceというNamespaceがありますが、先日、ココに書かれてない内容を知る機会がありました。
Account という名のApexクラス
@yonet77 いやw うちで作ってるパッケージで、Account ってApex Class作っちゃってて… 標準オブジェクトのnew Account() したいのにパッケージの方が参照されてしまう…
2013-10-01 16:57:48 via Echofon to @yonet77
Force.com では、Apexクラスの名前に標準オブジェクト名を付けることも可能ですし、その他標準で用意されているクラスの名前(SelectOptionとか)も可能です。そんなわけで、例えば"Account"という名前のApexクラスも作ることができます。
そういったApexクラスを作ったときに何が困るの?というハナシですが、こんなところで困るハメになります。
public class Account { public Account(){ } } //---------------------------- // Execute Anonymous.. //---------------------------- Account acc = new Account(); insert acc; // -> line 2, column 1: DML requires SObject or SObject list type: Account Account acc = new Account(Name='Test Account'); insert acc; // -> line 1, column 15: Invalid constructor syntax, name=value pairs can only be used for SObjects Account acc = [Select Name From Account limit 1]; // -> line 1, column 1: Illegal assignment from LIST to Account
なんとッ....!自前で作ったAccountクラスを参照してしまい、標準オブジェクトのDMLやSOQL文がエラーとなってしまうのです。。
思わず
なっ!何をするだァーーーッ!ゆるさんッ!
とジョナサン・ジョースターばりに怒りを爆発させてしまいそうです。
Schema Namespace...だと!
そんなところに救世主が。
@pomu0325 @yonet77 「Schema.Account account = new Schema.Account();」じゃだめですか ... ?
2013-10-01 17:40:59 via Janetter to @pomu0325
S...Schema Namespaceがそんなところにも使えるとは!
というわけで、試してみると...
Schema.Account accs = [Select Name From Account limit 1]; System.debug(accs.Name); // -> 00:44:05:031 USER_DEBUG [2]|DEBUG|University of Arizona Schema.Account acc = new Schema.Account(Name='TestAccount'); insert acc; System.debug(acc); // -> 00:47:37:613 USER_DEBUG [3]|DEBUG|Account:{Name=TestAccount, Id=0011000000cmMVvAAM}
ブラボー!おお・・・ブラボー!!
公開しているApexリファレンスには記載されていないのですが、確かにSchema Namespaceを使えば、上記の問題は解決されるというワケです!
これ、リファレンスにもちゃんと記載するべきなのでは・・?と思う今日この頃
良い子はマネしない
しかしそれでも完璧....ではないのが世の常。
たしかSchemaクラスも作れるので絶対安全とも言い切れない
【注意!!】URLは危険なパッケージのインストールURLですので、開く際には捨てても良いDev環境を準備してから、でお願いしますパッケージまで作ってたのでアップロードしてみたwww URL
相変わらずデストロイヤーな @mino0123 さんの危険なパッケージをインストールすると、
public class Schema { private Schema(){} @isTest private static void test() { Schema instance = new Schema(); } }
という危険なクラスが定義されていて、こうなると前述した"Schema.Account"も役に立たない。
見事なまでに破壊してくれます。そんなステキなパッケージ名は
BreakApex
というわけで、 @mino0123 先生の次回作に期待しつつ、Schema namespace の意外な使い方をおしまいにしたいと思います。
補足 (2013/10/07 追記)
@mino0123 先生からのコメントです。
個人的には標準オブジェクト使えなくなることよりSystem付けないと例外をキャッチできなくなるところの方が気に入ってます。
try{ Integer a = 10; Integer b = 0; System.debug(a/b); }catch(MathException ex){ System.debug('--- This is Test---'); } // -> //15:35:11.036 (36980000)|EXCEPTION_THROWN|[4]|System.MathException: Divide by 0 //15:35:11.037 (37168000)|HEAP_ALLOCATE|[4]|Bytes:15 //15:35:11.040 (40311000)|FATAL_ERROR|System.MathException: Divide by 0
確かにCatchされないッ...!
(MathException -> Exceptionにすれば、さすがにCatchしてくれるけど...いい感じの破壊っぷりでした。)