プログラマ38の日記

主にプログラムメモです。

Java: Map.remove ではまりました(java.util.ConcurrentModificationException)

Javaコードを書いていて、for each 内で、Mapのremoveを行いjava.util.ConcurrentModificationExceptionエラーになるのをすっかり忘れてました。

 

エラーになるコード

        HashMap<String, String> map = new HashMap<String, String>();
        
        map.put("k1", "v1");
        map.put("k2", "v2");
        map.put("k3", "v3");
        
        for(String k : map.keySet()){
            if( k.endsWith("2")){
                map.remove(k);
            }
        }

 

エラーにならないコード

        HashMap<String, String> map = new HashMap<String, String>();
        
        map.put("k1", "v1");
        map.put("k2", "v2");
        map.put("k3", "v3");
        
        for(Iterator<String> i = map.keySet().iterator();i.hasNext();){
            String k = i.next();
            if( k.endsWith("2")){
                i.remove();
            }
        }

 

Iteratorで要素を順に取得する場合は、要素の削除は Iterator.remove で行う必要がありました。(拡張for文はコンパイル時にIteraterのコードに展開されるようです)

すっかり拡張for文に慣れてしまいIteratorなんてほぼ目にしなくなっているのに、removeするときだけIteratorで回すのは面倒くさいなーと思いました。

 

removeではなく、新しいMapを作成する

処理に問題がなければ、removeした結果と同じMapを新規に作成しとけば問題ないですよね。

        HashMap<String, String> map = new HashMap<String, String>();
        
        map.put("k1", "v1");
        map.put("k2", "v2");
        map.put("k3", "v3");
        
        HashMap<String, String> newmap = new HashMap<String, String>();
        for(String k : map.keySet()){
            
            if( k.endsWith("2") == false){
                newmap.put(k, map.get(k));
            }
        }
        
        map = newmap;

さらにStreamAPIで綺麗に書けるようになってます。

    HashMap<String, String> map = new HashMap<String, String>();
    
    map.put("k1", "v1");
    map.put("k2", "v2");
    map.put("k3", "v3");
    
    map = map.entrySet().stream()
        .filter(m-> m.getKey().endsWith("2")==false)
        .collect(
          Collectors.toMap(Entry::getKey, Entry::getValue, (e1, e2) -> e1,HashMap::new)
        );

 

でもラムダ式に慣れてなくて、いちいち調べないとまともに書けないですねー。ちゃんと把握しようかな。。と思いました。

Salesforce: メタデータAPIのretrieveでプロセスビルダーのメタデータ取得がうまくいかない件

メタデータAPIで、プロセスビルダーのメタデータを取得しようとしてうまくいかないことがわかりました。
メタデータダウンロードツールを作成していますが修正済みです。

 

 

プロセスビルダーのメタデータをlistMetadataで取得した際の物理名と、メタデータのリクエスト時の物理名が合ってないのが問題でした。

例えば、プロセスビルダーで物理名が「AutoCreateContact」というものを作成したとすると

listMetadataで取得した際の物理名 : AutoCreateContact
メタデータのリクエスト時の物理名 : AutoCreateContact-1

のようになる時があるようです。(listMetadataで取得した際の物理名で末尾の"-1"が最初から入っている場合もあり、条件は不明です)

対応策としては、プロセスビルダーのメタデータワイルドカードで取得するように変更しました。


最後に

Salesforceのヘルプ(https://developer.salesforce.com/docs/atlas.ja-jp.api_meta.meta/api_meta/meta_retrieve.htm)を参考に作成してもそのままでは取得できないメタデータがあるので注意が必要ですね。。

Salesforce: Lightning Lightning レコードページの設定

Lightning レコードページ を使うことでレイアウトの配置がさらに細かく指定できます。

 

f:id:crmprogrammer38:20180319092515p:plain

 

配置では次をよく使います。

指定できるもの 内容
強調表示パネル ヘッダとボタン
パス パスを設定した場合のパス表示
レコードの詳細 レコードの詳細ページ(ページレイアウトで設定したもの)
タブ Lightning レコードページを指定しない場合の、詳細ページと関連リストの表示に近いもの(タブは追加可能)
関連リスト ページレイアウトで指定した関連リストを表示(表示条件を追加可能)
関連リスト - 1つ ページレイアウトで指定した関連リストの中から1つを表示(表示条件を追加可能)

 

関連リストの指定で表示条件を追加できますが、この条件は関連リストそのものの表示・非表示で、関連リストに表示するデータの条件ではありませんでした。

 

Lightning レコードページはデフォルトで指定したり、アプリケーション毎やアプリケーションとレコードタイプ毎で指定できます。

また、Visualforceや、Lightningコンポーネントも指定できてレコード詳細表示でやりたいことは、ほぼ設定でできてしまいます。

 

ただ設定変更が画面に反映されるまで、多少ラグがあるのが気になりました。

Salesforce: Lightning ページレイアウトの設定

Lightningでのページレイアウトは、今まで通りのページレイアウトの指定と、Lightningレコードページで指定します。

 

今まで通りのページレイアウトの指定では次のような画面表示となります。

[詳細タブ]

f:id:crmprogrammer38:20180213092751p:plain
[関連タブ]

f:id:crmprogrammer38:20180213093858p:plain

 

① コンパクトレイアウトで指定した項目の表示
② 「モバイルおよび Lightning Experience のアクション」で指定した詳細ボタンとアクション
③ ページレイアウトでクイックアクションで投稿を指定した場合の表示
④ ページレイアウトの詳細項目
⑤ ページレイアウトのカスタムリンク
⑥ ページレイアウトの関連リストとリストボタン

 

①ですが、レイアウトの設定後にコンパクトを変更しても反映されませんでした。(反映が遅いだけですかね)再度、ページレイアウトを保存すると反映されました。

 

②は、LightningではJavaScriptボタンが使えません。カスタムボタンが使えないと勘違いしてました。

 

③は投稿のクイックアクションを指定しないと、フィード追跡が表示されるだけになります。

 

④は今まで通りです。

 

⑤はカスタムリンクもJavaScriptのリンクは使えません。

 

⑥の関連リストボタンもJavaScriptボタンが使えません。

 

最後に

JavaScriptボタンとJavaScriptリンクが使えないという点がインパクトがあると思いました。(Googleで検索すると、いくつか回避策がヒットしました)

基本的には、Visualforceボタンにすれば今まで通りに近いアプリケーションが作れると思いました。

ですが、1つのトランザクションではガバナ制限を超えてしまうため、JavaScriptボタンからカスタムWebServiceを何度かコールするという作りをする場合、JavaScriptボタンではなく、Lightningコンポーネントを使うのかなと勝手に考えています。

もうちょっと理解を進める必要がありそうです。Lightningコンポーネントは今までのVisualforceとは大分違うので道のりは長そうです。

Salesforce: Lightning オブジェクトの設定

Lightningではオブジェクトマネージャで、標準オブジェクトでも、カスタムオブジェクトもまとめて一覧表示する仕組みが追加されています。

f:id:crmprogrammer38:20180206100236p:plain

f:id:crmprogrammer38:20180206100459p:plain

LightningでもClassicでも、オブジェクトの作成と項目の追加に変更はありませんでした。
が、Lightningレコードページは、オブジェクトマネージャからでないと設定できませんでした。

後、検索レイアウトの、「タブ」「ルックアップダイアログ」「ルックアップ電話ダイアログ」の設定はLightningで使用する箇所はなく、「検索結果」のみ使用していました。

 

最後に


Lightningの設定ページや、オブジェクトマネージャは慣れるまで時間がかかりそうです。各設定で、ページ内の検索機能があるのは便利だなーと思いました。


ただ、オブジェクトマネージャの一覧表示で、添付ファイル(Attachment)や、ファイル(ContentVersion)などの内部のオブジェクトは表示されておらず、内部のオブジェクトにトリガを作成する場合は開発者コンソールやForce.com IDEから作成するのは今まで通りのようです。

Salesforce: Lightning experience を勉強したいと思いました

SalesforceのLightning Experienceに対して、見た目がかっこいいとか、カスタムボタンが使えないとかそれぐらいのイメージしか持っていませんでした。

(後、基本的にいやなのが、動作が遅かったり、Lightningの設定画面だけでは全ての設定ができないという点です。これでLightningに変える気になれていませんでした)

 

ですが、今後はClassicの機能追加が終了して、Classicの開発知識は陳腐化していくんだろうなーと思います。

そこで、Lightningを勉強しようと思います。

 

次のようないつものSalesforce開発をLightningで行えるようになりたいと思っています。

  • オブジェクトを作成
  • レイアウトを作成
  • ビューを作成 
  • 標準画面に詳細カスタムボタンを追加
  • 標準画面の関連リストにリストボタンを追加
  • ビューにボタン追加
  • アプリケーションを作成

 

できればボタンの上書きとかVisualforce、Lightningコンポーネントも触って行きたいと思いますが目標は低めが好きなので、まず上記でやってみます。

trailbrazerやhelp & training 、色々なブログ情報などから情報を集めるところからスタートしようと思います。

 

Salesforce: プロファイルのリリースで気をつけたいこと

Salesforceで、モジュールのリリースはとても大変な作業です。

リリースの中で特にプロファイルのリリースは気を使います。

プロファイルをリリースする際の注意点をメモしておこうと思います。

 

変更セットでリリースする際は、プロファイル別にアクセス権が付与できるコンポーネントと一緒に変更セットを作成する

アプリケーション、オブジェクト、タグ、レコードタイプ、Apexクラス、Visualforceページ、項目レベルセキュリティといったプロファイルで制御できるコンポーネントとプロファイルを1つの変更セットにまとめることで、プロファイルのアクセス権とともにリリースできます。

 

ただし、変更セットでは標準オブジェクトとそのタブ、標準項目が選べません。ですので変更セットではリリースできず標準オブジェクトとそのタブ、標準項目は手動での設定となります。

 

サイトプロファイルのリリース

各環境でサイトの設定をした後サイトの公開アクセス設定からサイトのプロファイル画面に行き、プロファイルの名前を揃えます。

f:id:crmprogrammer38:20180130105005p:plain

プロファイルの名前を揃えておけば、プロファイル設定をリリースできるようになります。

 

変更セットのプロファイルリリース時に、ログイン IP アドレスの制限もリリースされる

SandBoxと本番でIPアドレスの制限を変えて運用していることは多いと思いますが、変更セットでリリースするとIPアドレスの制限も一緒にリリースしてしまいます。

本番環境だけセキュリティを厳しくしている場合はこれは本当に困ります。

プロファイルはリリースせずに手動でプロファイル設定を行うことで対応できますが、リリースするコンポーネントでプロファイル制御する数(カスタム項目など)が多い場合、手動だと厳しい場合があります。

そういう時はプロファイルをデプロイ(IDEや、移行ツール)するのも1つの手かなと思います。手動で設定して間違えるくらいならプロファイルのメタデータxmlで不要な箇所を除いて(ログインIPアドレスの制限箇所をコメントアウトにする)デプロイの方が正確にリリースできます。

 

最後に

権限セットでアクセス権を付与することにすれば、項目権限(FieldPermissions)、オブジェクト権限(ObjectPermissions)はデータローダで設定できるようになります。

あまりに項目権限の設定が煩雑な場合は権限セットを使ってしまう手もあります。でも、プロファイルで正しく定義しておく方がオススメです。