DescribeSObjectResultの取り方で結果が異なる


### はじめに

Apexで開発していく中で、使用頻度が上位にくる（かもしれない）クラスとして[Schema.DescribeSObjectResult](https://developer.salesforce.com/docs/atlas.ja-jp.apexcode.meta/apexcode/apex_methods_system_sobject_describe.htm#apex_methods_system_sobject_describe)が挙げられます。

さて、このクラスを取得する方法によって、結果が異なることがありました、ということでいくつか試してみたいと思います。

### DescribeSObjectResultの取得パターン

さて、```DescribeSObjectResult```を取得するのに、3パターンほど思い浮かぶかと思います。（以下```Account```オブジェクトを対象にしてます）

①SObjectクラスからトークンを取得しながら...

```Apex
Schema.DescribeSObjectResult d = Account.sObjectType.getDescribe();
```

②Schemaクラスから対象オブジェクトのトークンを取得しながら...

```Apex
Schema.DescribeSObjectResult d = Schema.getGlobalDescribe().get('Account').getDescribe();
```

③Schemaクラスから取得...

```Apex
Schema.DescribeSObjectResult d = Schema.describeSObjects(new List<String>{'Account'})[0];
```

全て、```Account```オブジェクトのDescribe Informationを取得するだけのコードで、特に変わったこともない（つもり）です。

さて、ココで```Account```オブジェクトへの作成、編集、削除権限がないユーザで、上記コードを実行してみましょう。

### 作成、編集、削除権限のないユーザで実行してみる

※以下のコードを試す場合には、test method内で実行ください

```Apex
List<Profile> profiles = [Select Id From Profile Where Name IN ('Read Only','参照のみ')];

Profile p = profiles[0];
User testUser = new User(
  alias = 'hogehoge',
  email = 'smith@salesforce.com',
  emailencodingkey = 'UTF-8',
  lastname = 'smith',
  languagelocalekey = 'en_US',
  localesidkey = 'en_US',
  profileid = p.Id,
  timezonesidkey = 'America/Los_Angeles',
  username = 'smith@salesforce.com.forsample'
);

System.runAs(testUser){

  Schema.DescribeSObjectResult d1 = Account.sObjectType.getDescribe();
  System.assertEquals(d1.isAccessible(), true);
  System.assertEquals(d1.isCreateable(), false);
  System.assertEquals(d1.isDeletable(), false);
  System.assertEquals(d1.isUpdateable(), false);

  Schema.DescribeSObjectResult d2 = Schema.getGlobalDescribe().get('Account').getDescribe();
  System.assertEquals(d2.isAccessible(), true);
  System.assertEquals(d2.isCreateable(), false);
  System.assertEquals(d2.isDeletable(), false);
  System.assertEquals(d2.isUpdateable(), false);

  Schema.DescribeSObjectResult d3 = Schema.describeSObjects(new List<String>{'Account'})[0];
  System.assertEquals(d3.isAccessible(), true);
  System.assertEquals(d3.isCreateable(), false);
  System.assertEquals(d3.isDeletable(), false);
  System.assertEquals(d3.isUpdateable(), false);

}

```

上記のコードを実行してみると、

```System.assertEquals(d3.isCreateable(), false);```

の箇所にて、

```System.AssertException: Assertion Failed: Expected: true, Actual: false```

というエラーが発生します。上2つの方法で取得した結果と異なりました。

[Schema.describeSObjects(List<String>)](https://developer.salesforce.com/docs/atlas.ja-jp.apexcode.meta/apexcode/apex_methods_system_schema.htm#apex_System_Schema_describeSObjects)のリファレンスを見ると、【使用方法】には

> このメソッドは、Schema.sObjectType トークンの getDescribe メソッドと類似しています。getDescribe メソッドと異なり、このメソッドでは sObject 型を動的に指定して、複数の sObject を一度に記述できます。
>
> 最初に getGlobalDescribe をコールして組織のすべてのオブジェクトのリストを取得します。その後リスト内を反復処理し、describeSObjects を使用して個々のオブジェクトのメタデータを取得します。

とあります。
"リスト内を反復処理し...個々のオブジェクトのメタデータを取得します" といった中で、メタデータ取得に関しては、システム権限で実行されてしまうのだろうと推測します。
（そのため、期待する結果が得られなかった、と）

### さいごに

結局のところ、```Schema.DescribeSObjectResult```を取得したいときには、```Schema.describeSObjects(List<String>)```を使わない方が無難だよ、ということでしょうか。

（システム管理者権限でしか使わない、という前提があれば話は別ですが）

しかし、気付きにくい違いだったなぁ...と。（苦笑）