出力メタデータ

出力メタデータは、コンポーネントの結果の型を解決します。各コンポーネントは、ペイロードと属性の静的メタデータまたは動的メタデータを互いに分離して提供できます。

OutputTypeResolver と AttributesTypeResolver の宣言

OutputTypeResolver​ 実装と ​AttributesTypeResolver​ 実装は、​MetadataContext​ が提供する情報に基づいて、また、最も重要な点として ​MetadataKey​ を使用してエンドユーザー (Mule アプリケーションの作成者) が必要とする ​MetadataType​ を特定することによって、​MetadataType​ の解決要求を処理します。​MetadataType​ の詳細は、​「コンポーネントのメタデータとは?」​を参照してください。

OutputTypeResolver<T>​ インターフェースと ​AttributesTypeResolver<T>​ インターフェースは、汎用 ​T​ でパラメーター化され、​MetadataKeyId​ パラメーターの型と一致する必要があります。この例では、最も一般的な ​MetadataKeyId​ 型である ​String​ を汎用型として使用しています。(他のドキュメントもこの汎用型を参照し、​String​ 以外に変更する必要がある場合に型を詳細に定義しています。)

上記の例では、​typeLoader​ を取得するために ​MetadataContext​ のみを使用して Java クラスに基づいて MetadataType を記述していますが、提供されている設定要素や接続要素を使用することもできます。

OutputTypeResolver の使用

TypeKeysResolver​ と ​OutputTypeResolver​ を使用することで、操作とソースに出力 DataSense サポートを追加できます。​OutputTypeResolver​ と特定の ​TypeKeysResolver​ を一緒に使用する場合の主な制限は、​TypeKeysResolver​ で提供される ​MetadataKey​ が ​OutputTypeResolver​ によって ​MetadataType​ に解決できるようにするため、どちらも同じ ​category​ に属している必要があるという点です。

結果ペイロードへの DataSense の追加

public class FetchOperations {

  @OutputResolver(output = OutputEntityResolver.class)
  public Map<String,Object> get(@Connection MyConnection connection,
                                @MetadataKeyId(EntityKeysResolver.class) String entityKind){

    return connection.getClient().fetch(entityKind);
  }

}
java

上記の例では、フェッチされる ​entityKind​ に基づいて出力の MetadataType を動的に解決しているため、​EntityKeysResolver​ が提供する ​Author_id​ で ​entityKind​ を設定してある場合は、その ​MetadataKey​ で ​OutputEntityResolver​ が呼び出され、​get​ 操作の出力は ​AuthorResult​ ObjectType に解決されます。

ソースは、同じ出力型解決を使用して、フローにディスパッチされるオブジェクトの MetadataType を記述することができます。宣言は同様です。

@MetadataScope(keysResolver = EntityKeysResolver.class,
               outputResolver = OutputEntityResolver.class)
public class ListenerSource extends Source<Map<String, Object>, Void>  {

  @MetadataKeyId
  @Parameter
  public String type;

  @Connection
  private ConnectionProvider<MetadataConnection> connection;

  @Override
  public void onStart(SourceCallback<Map<String, Object>, Void> sourceCallback) throws MuleException {
    //...
  }

  @Override
  public void onStop() {
    //...
  }

}
java

ソースと操作では、出力型の解決のライフサイクルは同じです。まず ​MetadataKeyId​ を設定してから、そのキーで ​OutputTypeResolver​ を呼び出して、結果のエンティティの MetadataType を解決します。

結果属性用の DataSense の追加

動的メタデータの解決では、コンポーネントの完全な出力がペイロードだけではなく ​Result<Payload, Attributes>​ であることを考慮します。

操作またはソースの出力に動的な属性構造がある場合は、​AttributesTypeResolver​ (​OutputTypeResolver.java​ の例で実装済み) を宣言してから、操作またはソースの宣言にリゾルバーへの参照を追加することで、MetadataType を解決することができます。

次の例では、​Book​ エンティティを、それぞれが独自の構造を持つ本のコンテンツと属性に分割します。この分割により、エンドユーザーは操作の結果をより効果的に理解して使用できます。つまり、データ (ペイロードに格納される本のコンテンツ) とペイロードを特徴付けるメタデータ (本の属性) に分けて考えることができます。

public class FetchOperationsWithAttributes {

  @OutputResolver(output = OutputEntityResolver.class,
                  attributes = OutputEntityResolver.class)
  public Result<Object, Object> get(@Connection MyConnection connection,
                                                @MetadataKeyId(EntityKeysResolver.class) String entityKind){

    if ("Book_id".equals(entityKind)){
      Book book = (Book)connection.getClient().fetch(entityKind);
      return Result.<Object, Object>builder()
                   .output(book.content())
                   .attributes(book.attributes())
                   .build();
    }

    return return Result.<Object, Object>builder()
                 .output(connection.getClient().fetch(entityKind))
                 .build();
  }

}
java

ソースには、ペイロードで使用したのと同じような宣言がありますが、​attributesResolver​ 参照が追加されています。

@MetadataScope(keysResolver = EntityKeysResolver.class,
               outputResolver = OutputEntityResolver.class,
               attributesResolver = OutputEntityResolver.class)
public class ListenerSource extends Source<Map<String, Object>, Object>  {

  @MetadataKeyId
  @Parameter
  public String type;

  //...

}
java

ユーザー定義の MetadataKey を持つ出力メタデータ

ユーザー定義の MetadataKey のケースは、コンポーネントの出力にも適用されます。 クエリの場合は、解決される可能性のある MetadataKey のセットを事前に定義することができません。その代わりに、出力の型または構造を特徴付けるパラメーターとその値があります。

たとえば、Database Connector には ​select​ 操作があります。その出力は、クエリ対象のエンティティによって異なります。

  @OutputResolver(output = SelectMetadataResolver.class)
  public List<Map<String, Object>> select(@MetadataKeyId String sql, @Config DbConnector connector){
    // ...
  }
java

SelectMetadataResolver​ は次のように宣言されています。

メタデータの自動ラップのリスト

select​ の例では、操作から ​List<Map<String, Object>​ が返されています。SELECT クエリの結果は複数のレコードエントリであるため当然ですが、​SelectMetadataResolver​ は ​getOutputType​ メソッドで ArrayType を記述していません。その代わりに、返された MetadataType は単一の ​record​ 構造を表しています。

これは何故でしょうか。

すでにお分かりかも知れませんが、操作は ArrayType (リスト、PagingProvider など) を返すため、配列の ​generic​ 型のみを記述するだけで済みます。OutputTypeResolver と AttributesTypeResolver は常に、​コレクション​型自身ではなく​コレクションの要素​の MetadataType を解決します。これにより、MetadataType リゾルバーの再利用性が高まり、必要なコードを減らすことができます。

解決された属性は、操作の ​List​ 出力の属性​ではなく​、コレクションの​要素​の属性​でもある​ことを考慮してください。

MetadataKey を使用しない動的出力メタデータの解決

入力と同様、コンポーネントの設定または接続に依存する動的型として、操作の出力は特定の ​MetadataKey​ がなくても解決できます。この場合も、キーレスリゾルバーを宣言するには、​MetadataKeyId​ パラメーターを省略して、TypeResolvers の MetadataKey を無視してください。

public class UserOperations {

  @OutputResolver(output = UserTypeResolver.class, attributes=UserTypeResolver.class)
  public Result<Map<String,Object>, Object> getUser(@Connection DemoConnection connection){
    User user = connection.getUser();

    return Result.<Map<String,Object>, Object>.builder()
                 .output(user.personalInfo())
                 .attributes(user.accountInfo())
                 .build().

  }

}
java