引数変換 - Mule 4

Java Module バージョン 1.1 以降、Java 呼び出しに指定された引数が Java メソッドが想定する型と完全に一致しない場合でも、このモジュールはその引数を変換します。Java Module は、パラメーターをメソッドが想定するものに変換する方法を推定します。

引数が変換されるタイミング

Java Module は、指定されたパラメーターごとに、その型がそのパラメーターのメソッドが想定する型と一致するかどうかをチェックします。メソッドが想定する型でない場合は、Java Module が想定される型に変換します。

シンプルな引数変換の例

以下に、引数の 1 つが変換されるシンプルな例を示します。

Math​ クラスから ​min​ 静的メソッドがコールされますが、クラスは 2 つの ​int​ パラメーターを受け取ることを想定します。このコールの実行時には Number と String が使用されます。

<flow name="calculateMinimum">
  <java:invoke-static class="java.lang.Math" method="min(int,int)" >
    <java:args>#[{
        'arg0': 5,
        'arg1' : "3"
      }]
    </java:args>
  </java:invoke-static>
</flow>

この場合、​arg1​ は String として渡されるところですが、Java メソッドをコールする前に Integer に変換されます。

カスタム POJO を Map としてモジュールに渡す

Mule 3 では、カスタム POJO を処理する場合に、ユーザーがデータをどの型に変換するかを DataWeave 式で明示的に宣言していました。Mule 4 では、引数の想定される型を Java Module が自動的に認識し、データを想定される型に変換しようとします。(POJO は Plain Old Java Object の略称です)。

以下の例では、Java Module で Map パラメーターがカスタム POJO に変換されています。

  1. POJO の ​Car​ クラスを定義します。

    public class Car {
      private String doors;
      private String wheels;
      private String engine;
    
      public String getDoors() {
        return doors;
      }
    
      public String getWheels() {
        return wheels;
      }
    
      public String getEngine() {
        return engine;
      }
    }
  2. POJO のインスタンスを受信するクラスの ​describeCar​ 静的メソッドを宣言します。

    public class CarUtils {
      public static String describeCar(Car car) {
        return "This car has: " + car.getEngine() + ", " + car.getWheels() + ", " + car.getDoors();
      }
    }
  3. Mule フローで静的メソッドを呼び出します。

    <flow name="describeCarFlow">
        <java:invoke-static class="CarUtils" method="describeCar(Car)" >
            <java:args>
                #[{
                'car': {
                    'doors' : "Four doors",
                    'engine' : "120 Horsepower engine",
                    'wheels' : "17 Inch chromed rims"
                }
                }]
            </java:args>
        </java:invoke-static>
    </flow>

    Mule 操作は ​car​ Map を受け取り、そのキーと値は ​Car​ クラスインスタンスにマップされます。Java メソッドを呼び出す前に、この Map がインスタンスに変換されます。こうした改善がなければ呼び出しに失敗し、Java メソッドに渡された引数がその署名と一致していなかった旨が表示されるでしょう。

Collection と Map

Java Module は、Collection の各要素と Map の各エントリが、メソッドの署名で宣言された Java ジェネリクスを使用しているかどうかをチェックします。使用していない要素がある場合、Java Module は Collection または Map 全体を作成して、変換済みの要素を再入力します。

変換が必要な場合は、Collection または Map の別のインスタンスで Java メソッドがコールされます (Mule フローで渡されるものと同じではありません)。この点が特に重要となるのは、コールされたメソッドで Collection または Map の要素を追加または削除し、呼び出しが必要になった後でこの Collection または Map を参照できることが想定される場合です。

List の変換例

操作に指定された ​List​ が変換され、変換された項目を含む新しい ​List​ が Java メソッドに渡されます。

IntegerUtils​ Java クラスは、​sumNumbers​ 静的メソッドを宣言します。

public class IntegerUtils {
  public static Integer sumNumbers(List<Integer> numbers) {
    return numbers.stream().mapToInt(i -> i.intValue()).sum();
  }
}

この Mule フローは、Java クラスを呼び出します。

<flow name="sumListOfNumbers">
  <java:invoke-static class="IntegerUtils" method="sumNumbers(List)">
    <java:args>
      #[{
        'numbers' : [1, "5", 4, "8", 3]
      }]
    </java:args>
  </java:invoke-static>
</flow>

フローの ​numbers​ リストに 2 つの String オブジェクト (​"5"​ と ​"8"​) があり、モジュールはそれらを Integer に変換します。

Map の変換例

操作の Map が変換され、変換されたキーと値を含む新しい Map が Java メソッドに渡されます。

この Java クラスは、​sumMapValues​ 静的メソッドを宣言します。

public class MapUtils {
  public static Integer sumMapValues(Map<String, Integer> map) {
    return map.keySet().stream().mapToInt(i -> i.intValue()).sum();
  }
}

この Mule フローは、​MapUtils​ Java クラスを呼び出します。

<flow name="sumValuesOnMap">
  <java:invoke-static class="MapUtils" method="sumMapValues(Map)">
    <java:args>
      #[{
        'map' :{
          'books': "22",
          'pencils': 33,
          'pens': 12
        }
      }]
    </java:args>
  </java:invoke-static>
</flow>

この Map には、Java メソッドで強制されるジェネリクスに従っていない値があります。このため、変換されたキーと値を指定した新しいインスタンスを使用してメソッドがコールされます。