概要
UiPath Developer Community 第12回ワークショップ で聞いてきた内容の覚え書き。。
いってきました。第12回。今回は LTへ登壇させてもらったり といろいろあったんですが、いちばん驚いたのが、、下記の例外処理について。
残念なお知らせ(として説明されていた内容)
コレです。
「try/catchアクティビティは、try節、catch節、いずれかを最後まで実行しないと、finally節が呼び出されない」というナゾ仕様のはなし。
いやいや、、、ありえないっしょ、、、。ということでやってみました。
Tryで例外をスローするコード。Finally節がよばれれば「Finally.」が出力されるはずです。
うん、ホントだ実行されてない。
ありえない仕様だと思います。。しりませんでした。
try/finallyでなくてtry/catch/finally とした場合も、catchで再度例外をスローすると、try/catchいずれも最後まで実行できていないので、同じ結果となります。これは「例外を再度throw」でも「再スローのアクティビティ」でも「new Exception("hoge",exception)」など別の例外にWrapしてスローしても、結果は同じです。
「try節、catch節、いずれかを最後まで実行しないと、finally節が呼び出されない」ってことは例外が発生しないで正常終了するか、発生しても上(呼び元)に投げない(ってつまり正常終了じゃん) 場合のみfinallyがよばれるってことですよね。。ちょっと意味が。。。ホントに残念なお知らせだと思います。
ちなみにJavaやC#だと
ちなみに、たとえばJavaだと、try/catch のfinally節は基本的に try/catch節がどうなろうと、必ず呼び出されます。
- 例1: tryを最後まで実行しないとき
public class Main {
public static void main(String[] args) {
System.out.println("UiPathだとFinallyがよばれない例1");
execute1();
}
private static void execute1() {
try {
System.out.println("Start.");
throw new RuntimeException("Error!");
} finally {
System.out.println("Finally.");
}
}
}
実行すると、
Exception in thread "main"
UiPathだとFinallyがよばれない例1
Start.
Finally.
java.lang.RuntimeException: Error!
at Main.execute1(Main.java:10)
at Main.main(Main.java:4)
うん、当然こうなります。
- 例2: tryを最後まで実行しない、かつcatchも最後まで実行しない とき
public class Main {
public static void main(String[] args) {
System.out.println("UiPathだとFinallyがよばれない例2");
execute2();
}
private static void execute2() {
try {
System.out.println("Start.");
throw new RuntimeException("Error!");
} catch (RuntimeException e) {
throw e;
} finally {
System.out.println("Finally.");
}
}
}
実行すると、
UiPathだとFinallyがよばれない例2
Exception in thread "main"
Start.
Finally.
java.lang.RuntimeException: Error!
at Main.execute2(Main.java:10)
at Main.main(Main.java:4)
当然C#でも、Javaとおなじ。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("UiPathだとFinallyがよばれない例1");
execute1();
}
private static void execute1()
{
try
{
Console.WriteLine("Start.");
throw new Exception("Error!");
}
finally
{
Console.WriteLine("Finally.");
//Console.ReadKey();
}
}
}
}
UiPathだとFinallyがよばれない例1
Start.
ハンドルされていない例外: System.Exception: Error!
場所 ConsoleApp1.Program.execute2()
場所 ConsoleApp1.Program.execute1()
場所 ConsoleApp1.Program.Main(String[] args)
Finally.
というわけで対応策
というわけでfinallyをちゃんと実行しつつ上(呼びだし元)にエラーを投げたいときは、catchで例外を投げるのではなく、例外のインスタンスを一旦変数に保管し、finallyもしくはさらにその後で、その例外をスローします。
まずJavaで書くとこんな感じ。
public class Main {
public static void main(String[] args) {
System.out.println("そのための対策をしたコード");
execute3();
}
private static void execute3() {
RuntimeException exception = null;
try {
System.out.println("Start.");
throw new RuntimeException("Error!");
} catch (RuntimeException e) {
exception = e;
} finally {
System.out.println("Finally.");
if (exception != null) {
throw exception;
}
}
}
}
実行してみると、
そのための対策をしたコード
Start.
Finally.
Exception in thread "main" java.lang.RuntimeException: Error!
at Main.execute3(Main.java:11)
at Main.main(Main.java:4)
こういうことですね。
UiPathでやるとこうです。try節は元のワークフローと同じ。トライキャッチのスコープであからじめexception
変数を定義しておき、catchでスローされた例外 e
を、その変数に格納します。
そしてfinally節で、その変数がnullでなければ「例外が発生していたはず」ということであらためて例外をスローします。
よさそうですね。
そういえば Attended Frameworkもそうなってた :-)
そういえば、Attended FrameworkもProcess.xaml
をtry/catchで囲んでる箇所も、まったく同じ構造になっていました。
この処理の流れ、なんでこんなメンドイ流れなのかなー??「正常終了と異常終了(業務とシステム例外)」の3パタンを一箇所に集めるためかなー??って理解してたんですが、まさかfinallyをちゃんと呼べないバグの対応だったとは、、。。
なるほど、色々勉強になりました。
新たなユーザコミュニティについて
新しいユーザコミュニティをつくって、もっともっとユーザの声が届きやすくする動きがあるようですね!
まずは名前を決めましょうということで、名前を投票できるようです。下記のQRからいけるので興味がある方はアクセスしてみてください。
以上です。。今回の記事は、、例外処理の件というUiPath本体外のところが中心になっちゃいました。。
おつかれさまでした。
関連リンク
- Attended Framework テンプレートを使ってみた(Slide版) LTで登壇した資料です
- UiPathの Attended Framework テンプレートを使ってみた その資料の元ネタ
- UiPath Developer Community 第12回ワークショップ 覚え書き。例外処理のfinally節問題。 本記事
- UiPath Developer Community 第11回ワークショップ 覚え書き AI Computer Vision とUiPath 2019 Fast Trackの新機能 紹介。
- UiPath Developer Community 第10回ワークショップ 覚え書き OrchestratorのWebhook連携、ほか。
- UiPath Developer Community 第9回ワークショップ 覚え書き「Error Handling」や「Floating Robot」。
- UiPath Developer Community 第8回ワークショップ 覚え書き「カスタムアクティビティの、デバッガによるデバッグ方法について」
- UiPath Developer Community 第7回ワークショップ 覚え書き「カスタム入力アクティビティ」
- UiPath Developer Community 第6回ワークショップ 覚え書き「出現するタイミングが不定のポップアップを処理する」
- System.Activities.Statements.TryCatch のソースコード