

翻訳は機械翻訳により提供されています。提供された翻訳内容と英語版の間で齟齬、不一致または矛盾がある場合、英語版が優先します。

# AWS SDK for Java 2.x からの AWS のサービス の呼び出し
<a name="work-with-services"></a>

このセクションでは、特定の AWS のサービス の使用方法に関する簡単なチュートリアルとガイダンスを提供します。完全な例のセットについては、[「コード例」セクション](java_code_examples.md)を参照してください。

**Topics**
+ [CloudWatch](examples-cloudwatch.md)
+ [AWS データベースサービス](examples-databases.md)
+ [DynamoDB](examples-dynamodb.md)
+ [Amazon EC2](examples-ec2.md)
+ [IAM](examples-iam.md)
+ [Kinesis](examples-kinesis.md)
+ [Lambda](examples-lambda.md)
+ [Amazon S3](examples-s3.md)
+ [Amazon SNS](examples-simple-notification-service.md)
+ [Amazon SQS](examples-sqs.md)
+ [Amazon Transcribe](examples-transcribe.md)

# の操作 CloudWatch
<a name="examples-cloudwatch"></a>

このセクションでは、 AWS SDK for Java 2.x を使用して [Amazon CloudWatch](https://docs.aws.amazon.com//AmazonCloudWatch/latest/monitoring/WhatIsCloudWatch.html) をプログラミングする例を示します。

 Amazon CloudWatch は Amazon Web Services 、 (AWS) リソースと で実行されるアプリケーションを AWS リアルタイムでモニタリングします。 CloudWatch を使用して、リソースとアプリケーションに対して測定できる変数であるメトリクスを収集および追跡できます。 CloudWatch アラームは、定義したルールに基づいて通知を送信するか、モニタリングしているリソースに自動的に変更を加えます。

次の例には各手法を示すのに必要なコードのみが含まれます。[完全なサンプルコードは GitHub で入手できます](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/javav2)。そこから、単一のソースファイルをダウンロードするかリポジトリをローカルにクローン作成して、ビルドし実行するためのすべての例を取得できます。

**Topics**
+ [からメトリクスを取得する CloudWatch](examples-cloudwatch-get-metrics.md)
+ [カスタムメトリクスデータを に発行する CloudWatch](examples-cloudwatch-publish-custom-metrics.md)
+ [CloudWatch アラームの操作](examples-cloudwatch-create-alarms.md)
+ [Amazon CloudWatch Events の使用](examples-cloudwatch-send-events.md)

# からメトリクスを取得する CloudWatch
<a name="examples-cloudwatch-get-metrics"></a>

## メトリクスの一覧表示
<a name="listing-metrics"></a>

 CloudWatch メトリクスを一覧表示するには、[ListMetricsRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/cloudwatch/model/ListMetricsRequest.html) を作成し、CloudWatchClient の `listMetrics`メソッドを呼び出します。`ListMetricsRequest` を使用して、名前空間、メトリクス名、またはディメンションで返されたメトリクスをフィルタリングできます。

**注記**  
 AWS サービスによって投稿されるメトリクスとディメンションのリストは、 Amazon CloudWatch 「 ユーザーガイド」の[Amazon CloudWatch 「メトリクスとディメンションのリファレンス](https://docs.aws.amazon.com//AmazonCloudWatch/latest/monitoring/aws-services-cloudwatch-metrics.html)」に記載されています。

 **インポート** 

```
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.cloudwatch.CloudWatchClient;
import software.amazon.awssdk.services.cloudwatch.model.CloudWatchException;
import software.amazon.awssdk.services.cloudwatch.model.ListMetricsRequest;
import software.amazon.awssdk.services.cloudwatch.model.ListMetricsResponse;
import software.amazon.awssdk.services.cloudwatch.model.Metric;
```

 **[コード]** 

```
    public static void listMets( CloudWatchClient cw, String namespace) {

        boolean done = false;
        String nextToken = null;

        try {
            while(!done) {

                ListMetricsResponse response;

                if (nextToken == null) {
                   ListMetricsRequest request = ListMetricsRequest.builder()
                        .namespace(namespace)
                        .build();

                 response = cw.listMetrics(request);
                } else {
                  ListMetricsRequest request = ListMetricsRequest.builder()
                        .namespace(namespace)
                        .nextToken(nextToken)
                        .build();

                response = cw.listMetrics(request);
            }

            for (Metric metric : response.metrics()) {
                System.out.printf(
                        "Retrieved metric %s", metric.metricName());
                System.out.println();
            }

            if(response.nextToken() == null) {
                done = true;
            } else {
                nextToken = response.nextToken();
            }
        }

        } catch (CloudWatchException e) {
            System.err.println(e.awsErrorDetails().errorMessage());
            System.exit(1);
        }
    }
```

このメトリクスは、[ メソッドを呼び出すことによって ](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/cloudwatch/model/ListMetricsResponse.html)ListMetricsResponse`getMetrics` で返ります。

結果は*ページ分割される*場合があります。結果の次のバッチを取得するには、レスポンスオブジェクトの `nextToken` を呼び出し、そのトークン値を使用して、新しいリクエストオブジェクトをビルドします。次に、`listMetrics` メソッドを新しいリクエストで再度呼び出します。

[GitHub](https://github.com/awsdocs/aws-doc-sdk-examples/blob/f4eaf2b2971805cfb2b87a8e5ab408f83169432e/javav2/example_code/cloudwatch/src/main/java/com/example/cloudwatch/ListMetrics.java) で完全な例をご覧ください。

## 詳細情報
<a name="more-information"></a>
+  Amazon CloudWatch API リファレンスの [ListMetrics](https://docs.aws.amazon.com//AmazonCloudWatch/latest/APIReference/API_ListMetrics.html) 

# カスタムメトリクスデータを に発行する CloudWatch
<a name="examples-cloudwatch-publish-custom-metrics"></a>

多くの AWS サービスは、`AWS`「」で始まる名前空間に[独自のメトリクス](https://docs.aws.amazon.com//AmazonCloudWatch/latest/monitoring/aws-services-cloudwatch-metrics.html)を発行します。独自の名前空間を使用してカスタムメトリクスデータを発行することもできます (「」で始まらない場合)`AWS`。

## カスタムメトリクスデータのパブリッシュ
<a name="cwid1"></a>

独自のメトリクスデータを発行するには、CloudWatchClient の `putMetricData` メソッドを [PutMetricDataRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/cloudwatch/model/PutMetricDataRequest.html) で呼び出します。`PutMetricDataRequest` には、データ用に使用するカスタム名前空間と、[MetricDatum](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/cloudwatch/model/MetricDatum.html) オブジェクト内のデータポイント自体に関する情報が含まれている必要があります。

**注記**  
「`AWS`」で始まる名前空間を指定することはできません。`AWS` 「」で始まる名前空間は、 Amazon Web Services 製品での使用のために予約されています。

 **インポート** 

```
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.cloudwatch.CloudWatchClient;
import software.amazon.awssdk.services.cloudwatch.model.Dimension;
import software.amazon.awssdk.services.cloudwatch.model.MetricDatum;
import software.amazon.awssdk.services.cloudwatch.model.StandardUnit;
import software.amazon.awssdk.services.cloudwatch.model.PutMetricDataRequest;
import software.amazon.awssdk.services.cloudwatch.model.CloudWatchException;
import java.time.Instant;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
```

 **コード** 

```
    public static void putMetData(CloudWatchClient cw, Double dataPoint ) {

        try {
            Dimension dimension = Dimension.builder()
                    .name("UNIQUE_PAGES")
                    .value("URLS")
                    .build();

            // Set an Instant object
            String time = ZonedDateTime.now( ZoneOffset.UTC ).format( DateTimeFormatter.ISO_INSTANT );
            Instant instant = Instant.parse(time);

            MetricDatum datum = MetricDatum.builder()
                .metricName("PAGES_VISITED")
                .unit(StandardUnit.NONE)
                .value(dataPoint)
                .timestamp(instant)
                .dimensions(dimension).build();

            PutMetricDataRequest request = PutMetricDataRequest.builder()
                .namespace("SITE/TRAFFIC")
                .metricData(datum).build();

            cw.putMetricData(request);

        } catch (CloudWatchException e) {
            System.err.println(e.awsErrorDetails().errorMessage());
            System.exit(1);
        }
        System.out.printf("Successfully put data point %f", dataPoint);
     }
```

[GitHub](https://github.com/awsdocs/aws-doc-sdk-examples/blob/f4eaf2b2971805cfb2b87a8e5ab408f83169432e/javav2/example_code/cloudwatch/src/main/java/com/example/cloudwatch/PutMetricData.java) で完全な例をご覧ください。

## 詳細情報
<a name="more-information"></a>
+  [「 ユーザーガイド」の「 Amazon CloudWatch メトリクス](https://docs.aws.amazon.com//AmazonCloudWatch/latest/monitoring/working_with_metrics.html)」を使用します。 Amazon CloudWatch 
+  Amazon CloudWatch ユーザーガイド[AWS の名前空間](https://docs.aws.amazon.com//AmazonCloudWatch/latest/monitoring/aws-services-cloudwatch-metrics.html)。
+  Amazon CloudWatch API リファレンスの [PutMetricData](https://docs.aws.amazon.com//AmazonCloudWatch/latest/APIReference/API_PutMetricData.html)。

# CloudWatch アラームの操作
<a name="examples-cloudwatch-create-alarms"></a>

## アラームの作成
<a name="create-an-alarm"></a>

 CloudWatch メトリクスに基づいてアラームを作成するには、アラーム条件が満たされた [PutMetricAlarmRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/cloudwatch/model/PutMetricAlarmRequest.html) を使用して CloudWatchClient の `putMetricAlarm`メソッドを呼び出します。

 **インポート** 

```
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.cloudwatch.CloudWatchClient;
import software.amazon.awssdk.services.cloudwatch.model.Dimension;
import software.amazon.awssdk.services.cloudwatch.model.PutMetricAlarmRequest;
import software.amazon.awssdk.services.cloudwatch.model.ComparisonOperator;
import software.amazon.awssdk.services.cloudwatch.model.Statistic;
import software.amazon.awssdk.services.cloudwatch.model.StandardUnit;
import software.amazon.awssdk.services.cloudwatch.model.CloudWatchException;
```

 **Code** 

```
    public static void putMetricAlarm(CloudWatchClient cw, String alarmName, String instanceId) {

        try {
            Dimension dimension = Dimension.builder()
                .name("InstanceId")
                .value(instanceId).build();

            PutMetricAlarmRequest request = PutMetricAlarmRequest.builder()
                .alarmName(alarmName)
                .comparisonOperator(
                        ComparisonOperator.GREATER_THAN_THRESHOLD)
                .evaluationPeriods(1)
                .metricName("CPUUtilization")
                .namespace("AWS/EC2")
                .period(60)
                .statistic(Statistic.AVERAGE)
                .threshold(70.0)
                .actionsEnabled(false)
                .alarmDescription(
                        "Alarm when server CPU utilization exceeds 70%")
                .unit(StandardUnit.SECONDS)
                .dimensions(dimension)
                .build();

            cw.putMetricAlarm(request);
            System.out.printf(
                    "Successfully created alarm with name %s", alarmName);

        } catch (CloudWatchException e) {
            System.err.println(e.awsErrorDetails().errorMessage());
            System.exit(1);
        }
    }
```

[GitHub](https://github.com/awsdocs/aws-doc-sdk-examples/blob/f4eaf2b2971805cfb2b87a8e5ab408f83169432e/javav2/example_code/cloudwatch/src/main/java/com/example/cloudwatch/PutMetricAlarm.java) で完全な例をご覧ください。

## アラームの一覧表示
<a name="list-alarms"></a>

作成した CloudWatch アラームを一覧表示するには、CloudWatchClient の `describeAlarms`メソッドを [DescribeAlarmsRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/cloudwatch/model/DescribeAlarmsRequest.html) で呼び出します。これを使用して、結果のオプションを設定できます。

 **インポート** 

```
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.cloudwatch.CloudWatchClient;
import software.amazon.awssdk.services.cloudwatch.model.CloudWatchException;
import software.amazon.awssdk.services.cloudwatch.model.DescribeAlarmsRequest;
import software.amazon.awssdk.services.cloudwatch.model.DescribeAlarmsResponse;
import software.amazon.awssdk.services.cloudwatch.model.MetricAlarm;
```

 **[コード]** 

```
    public static void desCWAlarms( CloudWatchClient cw) {

        try {

            boolean done = false;
            String newToken = null;

            while(!done) {
                DescribeAlarmsResponse response;

                if (newToken == null) {
                    DescribeAlarmsRequest request = DescribeAlarmsRequest.builder().build();
                    response = cw.describeAlarms(request);
                } else {
                    DescribeAlarmsRequest request = DescribeAlarmsRequest.builder()
                        .nextToken(newToken)
                        .build();
                    response = cw.describeAlarms(request);
                }

                for(MetricAlarm alarm : response.metricAlarms()) {
                    System.out.printf("\n Retrieved alarm %s", alarm.alarmName());
                }

                if(response.nextToken() == null) {
                    done = true;
                } else {
                    newToken = response.nextToken();
                }
            }

        } catch (CloudWatchException e) {
            System.err.println(e.awsErrorDetails().errorMessage());
            System.exit(1);
        }
        System.out.printf("Done");
    }
```

`describeAlarms` よって返された [DescribeAlarmsResponse](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/cloudwatch/model/DescribeAlarmsResponse.html) の `MetricAlarms` を呼び出することで、アラームのリストを取得できます。

結果は*ページ分割される*場合があります。結果の次のバッチを取得するには、レスポンスオブジェクトの `nextToken` を呼び出し、そのトークン値を使用して、新しいリクエストオブジェクトをビルドします。次に、`describeAlarms` メソッドを新しいリクエストで再度呼び出します。

**注記**  
また、特定のメトリクスのアラームを取得するには、CloudWatchClient の `describeAlarmsForMetric` メソッドを使用します。使用方法は `describeAlarms` と同様です。

[GitHub](https://github.com/awsdocs/aws-doc-sdk-examples/blob/f4eaf2b2971805cfb2b87a8e5ab408f83169432e/javav2/example_code/cloudwatch/src/main/java/com/example/cloudwatch/DescribeAlarms.java) で完全な例をご覧ください。

## アラームの削除
<a name="delete-alarms"></a>

 CloudWatch アラームを削除するには、削除するアラームの 1 つ以上の名前を含む [DeleteAlarmsRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/cloudwatch/model/DeleteAlarmsRequest.html) を使用して CloudWatchClient の `deleteAlarms`メソッドを呼び出します。

 **インポート** 

```
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.cloudwatch.CloudWatchClient;
import software.amazon.awssdk.services.cloudwatch.model.CloudWatchException;
import software.amazon.awssdk.services.cloudwatch.model.DeleteAlarmsRequest;
```

 **Code** 

```
    public static void deleteCWAlarm(CloudWatchClient cw, String alarmName) {

        try {
            DeleteAlarmsRequest request = DeleteAlarmsRequest.builder()
                    .alarmNames(alarmName)
                    .build();

            cw.deleteAlarms(request);
            System.out.printf("Successfully deleted alarm %s", alarmName);

        } catch (CloudWatchException e) {
            System.err.println(e.awsErrorDetails().errorMessage());
            System.exit(1);
        }
    }
```

[GitHub](https://github.com/awsdocs/aws-doc-sdk-examples/blob/f4eaf2b2971805cfb2b87a8e5ab408f83169432e/javav2/example_code/cloudwatch/src/main/java/com/example/cloudwatch/DeleteAlarm.java) で完全な例をご覧ください。

## 詳細情報
<a name="more-information"></a>
+  Amazon CloudWatch ユーザーガイドの[Amazon CloudWatch アラームの使用](https://docs.aws.amazon.com//AmazonCloudWatch/latest/monitoring/AlarmThatSendsEmail.html) 
+  Amazon CloudWatch API リファレンスの [PutMetricAlarm](https://docs.aws.amazon.com//AmazonCloudWatch/latest/APIReference/API_PutMetricAlarm.html) 
+  Amazon CloudWatch API リファレンスの [DescribeAlarms](https://docs.aws.amazon.com//AmazonCloudWatch/latest/APIReference/API_DescribeAlarms.html) 
+  Amazon CloudWatch API リファレンスの [DeleteAlarms](https://docs.aws.amazon.com//AmazonCloudWatch/latest/APIReference/API_DeleteAlarms.html) 

# Amazon CloudWatch Events の使用
<a name="examples-cloudwatch-send-events"></a>

 CloudWatch Events は、 AWS リソースの変更を記述するシステムイベントのほぼリアルタイムのストリームを、 Amazon EC2 インスタンス、 Lambda 関数、 Kinesis ストリーム、 Amazon ECS タスク、 Step Functions ステートマシン、 Amazon SNS トピック、 Amazon SQS キュー、または組み込みターゲットに配信します。簡単なルールを使用して、一致したイベントを 1 つ以上のターゲット関数またはストリームに振り分けることができます。

Amazon EventBridge は、Amazon CloudWatch Events の[進化形](https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-cwe-now-eb.html)です。どちらのサービスも同じ API を使用するため、SDK が提供する [CloudWatch Events クライアント](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/cloudwatch/CloudWatchClient.html)を引き続き使用することも、SDK for Java の [EventBridge クライアント](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/eventbridge/EventBridgeClient.html)に移行して CloudWatch Events 機能を使用することもできます。CloudWatch Events の[ユーザーガイドドキュメント](https://docs.aws.amazon.com/eventbridge/latest/userguide/index.html)と [API リファレンス](https://docs.aws.amazon.com/eventbridge/latest/APIReference/index.html)が、EventBridge ドキュメントサイトから利用可能になりました。

## イベントの追加
<a name="add-events"></a>

カスタム CloudWatch イベントを追加するには、各イベントの詳細を提供する 1 つ以上の[https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/cloudwatchevents/model/PutEventsRequest.html](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/cloudwatchevents/model/PutEventsRequest.html)オブジェクトを含む[https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/cloudwatchevents/model/PutEventsRequestEntry.html](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/cloudwatchevents/model/PutEventsRequestEntry.html)オブジェクトを使用して `CloudWatchEventsClient’s``putEvents`メソッドを呼び出します。イベントのソースとタイプ、イベントに関連付けられたリソースなど、エントリの複数のパラメータを指定できます。

**注記**  
`putEvents` への呼び出しごとに最大 10 個のイベントを指定できます。

 **インポート** 

```
import software.amazon.awssdk.services.cloudwatch.model.CloudWatchException;
import software.amazon.awssdk.services.cloudwatchevents.CloudWatchEventsClient;
import software.amazon.awssdk.services.cloudwatchevents.model.PutEventsRequest;
import software.amazon.awssdk.services.cloudwatchevents.model.PutEventsRequestEntry;
```

 **コード** 

```
    public static void putCWEvents(CloudWatchEventsClient cwe, String resourceArn ) {

        try {

            final String EVENT_DETAILS =
                "{ \"key1\": \"value1\", \"key2\": \"value2\" }";

            PutEventsRequestEntry requestEntry = PutEventsRequestEntry.builder()
                    .detail(EVENT_DETAILS)
                    .detailType("sampleSubmitted")
                    .resources(resourceArn)
                    .source("aws-sdk-java-cloudwatch-example")
                    .build();

            PutEventsRequest request = PutEventsRequest.builder()
                    .entries(requestEntry)
                    .build();

            cwe.putEvents(request);
            System.out.println("Successfully put CloudWatch event");

        } catch (CloudWatchException e) {
            System.err.println(e.awsErrorDetails().errorMessage());
            System.exit(1);
        }
    }
```

[GitHub](https://github.com/awsdocs/aws-doc-sdk-examples/blob/0b1785e42949ebf959eaa0f0da4dc2a48f92ea25/javav2/example_code/cloudwatch/src/main/java/com/example/cloudwatch/PutEvents.java) で完全な例をご覧ください。

## ルールの追加
<a name="add-rules"></a>

ルールを作成または更新するには、 `CloudWatchEventsClient’s``putRule`メソッドを呼び出して、ルールの名前と[イベントパターン](https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-event-patterns.html)、ルールに関連付ける IAM ロール、ルールの実行頻度を記述する[スケジューリング式](https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-create-rule-schedule.html)などのオプションパラメータ[https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/cloudwatchevents/model/PutRuleRequest.html](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/cloudwatchevents/model/PutRuleRequest.html)を指定します。

 **インポート** 

```
import software.amazon.awssdk.services.cloudwatch.model.CloudWatchException;
import software.amazon.awssdk.services.cloudwatchevents.CloudWatchEventsClient;
import software.amazon.awssdk.services.cloudwatchevents.model.PutRuleRequest;
import software.amazon.awssdk.services.cloudwatchevents.model.PutRuleResponse;
import software.amazon.awssdk.services.cloudwatchevents.model.RuleState;
```

 **コード** 

```
    public static void putCWRule(CloudWatchEventsClient cwe, String ruleName, String roleArn) {

        try {
            PutRuleRequest request = PutRuleRequest.builder()
                .name(ruleName)
                .roleArn(roleArn)
                .scheduleExpression("rate(5 minutes)")
                .state(RuleState.ENABLED)
                .build();

            PutRuleResponse response = cwe.putRule(request);
            System.out.printf(
                    "Successfully created CloudWatch events rule %s with arn %s",
                    roleArn, response.ruleArn());
        } catch (
            CloudWatchException e) {
            System.err.println(e.awsErrorDetails().errorMessage());
            System.exit(1);
        }
    }
```

[GitHub](https://github.com/awsdocs/aws-doc-sdk-examples/blob/0b1785e42949ebf959eaa0f0da4dc2a48f92ea25/javav2/example_code/cloudwatch/src/main/java/com/example/cloudwatch/PutRule.java) で完全な例をご覧ください。

## ターゲットの追加
<a name="add-targets"></a>

ターゲットは、ルールがトリガーされたときに呼び出されるリソースです。ターゲットの例には、 Amazon EC2 インスタンス、 Lambda 関数、 Kinesis ストリーム、 Amazon ECS タスク、 Step Functions ステートマシン、組み込みターゲットなどがあります。

ルールにターゲットを追加するには、更新するルールを含む [https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/cloudwatchevents/model/PutTargetsRequest.html](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/cloudwatchevents/model/PutTargetsRequest.html) とルールに追加するターゲットのリストを使用して `CloudWatchEventsClient’s` `putTargets` メソッドを呼び出します。

 **インポート** 

```
import software.amazon.awssdk.services.cloudwatch.model.CloudWatchException;
import software.amazon.awssdk.services.cloudwatchevents.CloudWatchEventsClient;
import software.amazon.awssdk.services.cloudwatchevents.model.PutTargetsRequest;
import software.amazon.awssdk.services.cloudwatchevents.model.PutTargetsResponse;
import software.amazon.awssdk.services.cloudwatchevents.model.Target;
```

 **コード** 

```
    public static void putCWTargets(CloudWatchEventsClient cwe, String ruleName, String functionArn, String targetId ) {

        try {
            Target target = Target.builder()
                .arn(functionArn)
                .id(targetId)
                .build();

            PutTargetsRequest request = PutTargetsRequest.builder()
                .targets(target)
                .rule(ruleName)
                .build();

            PutTargetsResponse response = cwe.putTargets(request);
            System.out.printf(
                "Successfully created CloudWatch events target for rule %s",
                ruleName);
        } catch (CloudWatchException e) {
            System.err.println(e.awsErrorDetails().errorMessage());
            System.exit(1);
        }
    }
```

[GitHub](https://github.com/awsdocs/aws-doc-sdk-examples/blob/0b1785e42949ebf959eaa0f0da4dc2a48f92ea25/javav2/example_code/cloudwatch/src/main/java/com/example/cloudwatch/PutTargets.java) で完全な例をご覧ください。

## 詳細情報
<a name="more-information"></a>
+  「Amazon EventBridge ユーザーガイド」の「[PutEvents を使用したイベントの追加](https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-putevents.html)」。
+  「Amazon EventBridge ユーザーガイド」の「[ルールのスケジュール式](https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-create-rule-schedule.html#eb-create-scheduled-rule-schedule)」
+  「Amazon EventBridge ユーザーガイド」の「[CloudWatch Eventsのイベントタイプ](https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-service-event.html)」
+  「Amazon EventBridge ユーザーガイド」の「[イベントパターン](https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-event-patterns.html)」
+  詳細については、 Amazon EventBridge API リファレンスの「[PutEvents](https://docs.aws.amazon.com/eventbridge/latest/APIReference/API_PutEvents.html)」を参照してください。
+  Amazon EventBridge API リファレンスの「[PutTargets](https://docs.aws.amazon.com/eventbridge/latest/APIReference/API_PutTargets.html)」
+  Amazon EventBridge API リファレンスの「[PutRule](https://docs.aws.amazon.com/eventbridge/latest/APIReference/API_PutRule.html)」

# AWS データベースサービスと AWS SDK for Java 2.x
<a name="examples-databases"></a>

AWS には、リレーショナル、キーバリュー、インメモリー、ドキュメント、[その他いくつか](https://aws.amazon.com/products/databases/)のさまざまなデータベースタイプが用意されています。SDK for Java 2.x のサポートは、AWS 内のデータベースサービスの性質によって異なります。

[Amazon DynamoDB](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/Welcome.html) サービスなどの一部のデータベースサービスには、AWS リソース (データベース) を管理するウェブサービス API と、データを操作するウェブサービス API があります。Java 2.x 用 SDK では、これらのタイプのサービスには [DynamoDBClient](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/DynamoDbClient.html) などの専用のサービスクライアントがあります。

他のデータベースサービスには、[Amazon DocumentDB](https://docs.aws.amazon.com/documentdb/latest/developerguide/api-reference.html) API (クラスター、インスタンス、リソース管理用) など、リソースとやり取りするウェブサービス API がありますが、データを操作するためのウェブサービス API はありません。Java 2.x 用 SDK には、リソースを操作するための対応する [DocDbClient](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/docdb/DocDbClient.html) インターフェイスがあります。ただし、データを処理するには、[MongoDB for Java](https://www.mongodb.com/developer/languages/java/) などの別の Java API が必要です。

以下の例を使用して、さまざまなタイプのデータベースで Java 2.x サービスクライアント用 SDK を使用する方法を説明します。

## Amazon DynamoDB の例
<a name="examples-db-dynamodb"></a>


| データの使用 | データベースの使用 | 
| --- |--- |
| SDK service client: [DynamoDbClient](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/DynamoDbClient.html) | SDK service client: [DynamoDbClient](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/DynamoDbClient.html) | 
| Example: [DynamoDB を使った React/Spring REST アプリケーション](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/javav2/usecases/creating_dynamodb_web_app) | Examples: [CreateTable、ListTables、DeleteTable](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/javav2/example_code/dynamodb/src/main/java/com/example/dynamodb) | 
| Examples: [いくつかの DynamoDB の例](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/javav2/example_code/dynamodb/src/main/java/com/example/dynamodb) |  | 
|  | 
| --- |
| SDK service client: [DynamoDbEnhancedClient](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/DynamoDbEnhancedClient.html) |  | 
| Example: [DynamoDB を使った React/Spring REST アプリケーション](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/javav2/usecases/creating_dynamodb_web_app) |  | 
| Examples: [いくつかの DynamoDB の例](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/javav2/example_code/dynamodb/src/main/java/com/example/dynamodb) (names starting with 'Enhanced") |  | 

このガイドのガイド付きコード例のセクションにある「[additional DynamoDB examples](examples-dynamodb.md)」を参照してください。

## Amazon RDS での例
<a name="examples-db-rds"></a>


|  データの使用  |  データベースの使用  | 
| --- | --- | 
| 非 SDK API: JDBC、データベース固有の SQL フレーバー。コードはデータベース接続または接続プールを管理します。 | SDK サービスクライアント: [RdsClient](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/rds/RdsClient.html) | 
| 例: [MySQL を使った React/Spring REST アプリケーション](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/javav2/usecases/Creating_rds_item_tracker) | 例: [いくつかの RdsClient の例](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/javav2/example_code/rds/src/main/java/com/example/rds) | 

## Amazon Redshiftの例
<a name="examples-db-redshift"></a>


|  データの使用  |  データベースの使用  | 
| --- | --- | 
| SDK サービスクライアント: [RedshiftDataClient](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/redshiftdata/RedshiftDataClient.html) | SDK サービスクライアント: [RedshiftClient](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/redshift/RedshiftClient.html) | 
| 例: [いくつかの RedshiftDataClient の例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/c682a07a1e6abce793e3c32ef3b9661fa723d0ff/javav2/example_code/redshift/src/main/java/com/example/scenario/RedshiftScenario.java) | 例: [いくつかの RedshiftClient の例](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/javav2/example_code/redshift/src/main/java/com/example/redshift) | 
| 例: [RedshiftDataClient を使った React/Spring REST アプリケーション](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/javav2/usecases/CreatingSpringRedshiftRest) |  | 

## Amazon Aurora Serverless v2 の例
<a name="examples-db-aurora-sv1"></a>


|  データの使用  |  データベースの使用  | 
| --- | --- | 
| [SDK サービスクライアント: RdsDataClient](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/rdsdata/RdsDataClient.html) | [SDK サービスクライアント: RdsClient](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/rds/RdsClient.html) | 
| 例: [RdsDataClient を使った React/Spring REST アプリケーション](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/javav2/usecases/Creating_Spring_RDS_Rest) | 例: [いくつかの RdsClient の例](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/javav2/example_code/rds/src/main/java/com/example/rds) | 

## Amazon DocumentDB の例
<a name="examples-db-docdb"></a>


|  データの使用  |  データベースの使用  | 
| --- | --- | 
| 非 SDK API: MongoDB 固有の Java ライブラリ ([MongoDB for Java](https://www.mongodb.com/developer/languages/java/) など)。コードはデータベース接続または接続プールを管理します。 | SDK サービスクライアント: [DocDBClient](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/docdb/DocDbClient.html) | 
| 例: [DocumentDB (Mongo) デベロッパーガイド](https://docs.aws.amazon.com/documentdb/latest/developerguide/connect_programmatically.html#connect_programmatically-tls_enabled) (「Java」タブを選択) |  | 

# の使用 DynamoDB
<a name="examples-dynamodb"></a>

[DynamoDB](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Introduction.html) は、高速で予測可能なパフォーマンスとシームレスなスケーラビリティを特長とするフルマネージド NoSQL データベースサービスです。このセクションでは、 AWS SDK for Java 2.x を使用して DynamoDB を使用する方法について説明します。

## DynamoDB クライアントの選択
<a name="ddb-clients-overview"></a>

SDK には、DynamoDB を使用するための 2 つの主なアプローチがあります。

低レベルクライアント (`DynamoDbClient`)  
DynamoDB オペレーションへの直接アクセスを提供し、リクエストとレスポンスを完全に制御します。詳細な制御が必要な場合や動的スキーマを使用する場合は、このクライアントを使用します。

拡張クライアント (`DynamoDbEnhancedClient`)  
Java オブジェクトと DynamoDB 項目間の自動マッピングによるオブジェクト指向プログラミングを提供します。また、固定スキーマに従わない JSON のようなデータを使用するための、ドキュメント指向の機能も提供します。明確に定義されたデータモデルまたはドキュメントタイプのデータを使用する場合は、このクライアントを使用します。

## DynamoDB クライアントの設定
<a name="ddb-configuration-setup"></a>

DynamoDB を使用する前に、最適なパフォーマンスと信頼性を実現するようにクライアントを設定します。

### DynamoDB の再試行動作について
<a name="ddb-retry-behavior"></a>

DynamoDB クライアントは、デフォルトの最大再試行回数である 8 を使用します。これは他の AWS のサービス クライアントよりも多い回数です。この再試行回数の多さは、DynamoDB の分散性および一時的な容量制限に対処するために役立ちます。再試行戦略についての詳細は、「[で再試行動作を設定する AWS SDK for Java 2.x](retry-strategy.md)」を参照してください。

### アカウントベースのエンドポイントでのパフォーマンス最適化
<a name="ddb-account-based-endpoints-v2"></a>

DynamoDB は[AWS 、アカウント ID を使用してリクエストのルーティングを合理化することで、パフォーマンスを向上させるアカウントベースのエンドポイント](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Programming.SDKOverview.html#Programming.SDKs.endpoints)を提供します。 AWS 

この機能を使用するには、 AWS SDK for Java 2.xのバージョン 2.28.4 以降が必要です。[Maven Central リポジトリ](https://central.sonatype.com/artifact/software.amazon.awssdk/bom/versions)で最新バージョンを検索できます。サポートされている SDK バージョンでは、新しいエンドポイントが自動的に使用されます。

アカウントベースのルーティングをオプトアウトするには、次のいずれかのオプションを選択します。
+ `AccountIdEndpointMode` を `DISABLED` に設定して DynamoDB サービスクライアントを設定する。
+ 環境変数を設定する。
+ JVM システムプロパティを設定する。
+ 共有 AWS 設定ファイル設定を更新します。

次の例は、DynamoDB サービスクライアントを設定してアカウントベースのルーティングを無効にする方法を示しています。

```
DynamoDbClient.builder()
                 .accountIdEndpointMode(AccountIdEndpointMode.DISABLED)
                 .build();
```

その他の設定オプションの詳細については、「SDK およびツールリファレンスガイド」の[「アカウントベースのエンドポイント](https://docs.aws.amazon.com/sdkref/latest/guide/feature-account-endpoints.html)」を参照してください。 AWS SDKs 

## このトピックで扱う内容
<a name="ddb-topics-overview"></a>

以下のセクションでは、DynamoDB を使用する方法を示します。
+ [DynamoDB のテーブルの操作](examples-dynamodb-tables.md) - テーブルの作成、記述、更新、削除
+ [で項目を操作する DynamoDB](examples-dynamodb-items.md) - 個々の項目の追加、取得、更新
+ [を使用して Java オブジェクトを DynamoDB 項目にマッピングする AWS SDK for Java 2.x](dynamodb-enhanced-client.md) - 拡張クライアントでのオブジェクトマッピングとドキュメント指向データの使用

その他の DynamoDB コード例については、[「 コード例ライブラリ」のDynamoDB ](java_dynamodb_code_examples.md) AWS コード例」を参照してください。

# DynamoDB のテーブルの操作
<a name="examples-dynamodb-tables"></a>

テーブルは、DynamoDB データベースのすべての項目のコンテナです。DynamoDB のデータの追加または削除を行う前に、テーブルを作成する必要があります。

テーブルごとに、以下を定義する必要があります。
+ アカウントおよびリージョンに一意であるテーブル*名*。
+ *プライマリキー*。すべての値は一意でなければならず、テーブル内のどの 2 つの項目も同じプライマリキー値を持つことはできません。

  プライマリキーは、単一のパーティション (ハッシュ) キーで構成される*シンプル*なプライマリキーにするか、パーティションとソート (範囲) キーで構成される*複合*プライマリキーにすることができます。

  各キーバリューには、[https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/model/ScalarAttributeType.html](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/model/ScalarAttributeType.html) クラスによって列挙される*データ型*が関連付けられています。キー値は、バイナリ (B)、数値 (N)、または文字列 (S) になります。詳細については、Amazon DynamoDB デベロッパーガイドの[命名規則とデータ型](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.NamingRulesDataTypes.html)を参照してください。
+  テーブル用に予約された読み込み/書き込みキャパシティーユニットの数を定義する*プロビジョンドスループット*の値。
**注記**  
 [Amazon DynamoDB の料金](https://aws.amazon.com/dynamodb/pricing/)は、テーブルに設定したプロビジョニングされたスループット値に基づくため、テーブルに必要と予想される分だけの容量を予約します。

  テーブルのプロビジョンドスループットはいつでも変更できるため、必要に応じてキャパシティーを調整できます。

## テーブルの作成
<a name="dynamodb-create-table"></a>

新しい DynamoDB テーブルを作成するには、`DynamoDbClient’s` `createTable` メソッドを使用します。テーブルのプライマリキーを識別するために使用する、テーブル属性とテーブルスキーマを構築する必要があります。また、最初のプロビジョニングされたスループット値およびテーブル名を指定する必要があります。

**注記**  
選択した名前のテーブルがすでに存在している場合は、`[DynamoDbException](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/model/DynamoDbException.html)` がスローされます。

### シンプルプライマリキーを使用してテーブルを作成する
<a name="dynamodb-create-table-simple"></a>

このコードは、テーブルのシンプルプライマリキーである 1 つの属性を持つテーブルを作成します。この例では、`[AttributeDefinition](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/model/AttributeDefinition.html)` と `[KeySchemaElement](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/model/KeySchemaElement.html)` オブジェクトを [https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/model/CreateTableRequest.html](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/model/CreateTableRequest.html) に使用しています。

 **インポート** 

```
import software.amazon.awssdk.core.waiters.WaiterResponse;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.dynamodb.model.CreateTableRequest;
import software.amazon.awssdk.services.dynamodb.model.AttributeDefinition;
import software.amazon.awssdk.services.dynamodb.model.ScalarAttributeType;
import software.amazon.awssdk.services.dynamodb.model.ScalarAttributeType;
import software.amazon.awssdk.services.dynamodb.model.KeySchemaElement;
import software.amazon.awssdk.services.dynamodb.model.ProvisionedThroughput;
import software.amazon.awssdk.services.dynamodb.model.KeyType;
import software.amazon.awssdk.services.dynamodb.model.CreateTableResponse;
import software.amazon.awssdk.services.dynamodb.model.DescribeTableRequest;
import software.amazon.awssdk.services.dynamodb.model.DescribeTableResponse;
import software.amazon.awssdk.services.dynamodb.model.DynamoDbException;
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
import software.amazon.awssdk.services.dynamodb.waiters.DynamoDbWaiter;
```

 **Code** 

```
    public static String createTable(DynamoDbClient ddb, String tableName, String key) {

        DynamoDbWaiter dbWaiter = ddb.waiter();
        CreateTableRequest request = CreateTableRequest.builder()
                .attributeDefinitions(AttributeDefinition.builder()
                        .attributeName(key)
                        .attributeType(ScalarAttributeType.S)
                        .build())
                .keySchema(KeySchemaElement.builder()
                        .attributeName(key)
                        .keyType(KeyType.HASH)
                        .build())
                .provisionedThroughput(ProvisionedThroughput.builder()
                        .readCapacityUnits(new Long(10))
                        .writeCapacityUnits(new Long(10))
                        .build())
                .tableName(tableName)
                .build();

        String newTable ="";
        try {
            CreateTableResponse response = ddb.createTable(request);
            DescribeTableRequest tableRequest = DescribeTableRequest.builder()
                    .tableName(tableName)
                    .build();

            // Wait until the Amazon DynamoDB table is created
            WaiterResponse<DescribeTableResponse> waiterResponse =  dbWaiter.waitUntilTableExists(tableRequest);
            waiterResponse.matched().response().ifPresent(System.out::println);

            newTable = response.tableDescription().tableName();
            return newTable;

        } catch (DynamoDbException e) {
            System.err.println(e.getMessage());
            System.exit(1);
        }
       return "";
    }
```

[GitHub](https://github.com/awsdocs/aws-doc-sdk-examples/blob/0b1785e42949ebf959eaa0f0da4dc2a48f92ea25/javav2/example_code/dynamodb/src/main/java/com/example/dynamodb/CreateTable.java) で完全な例をご覧ください。

### 複合プライマリキーを使用してテーブルを作成する
<a name="dynamodb-create-table-composite"></a>

次の例では、2 つの属性を持つテーブルを作成します。どちらの属性も複合プライマリキーに使用されます。

 **インポート** 

```
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.dynamodb.model.DynamoDbException;
import software.amazon.awssdk.services.dynamodb.model.AttributeDefinition;
import software.amazon.awssdk.services.dynamodb.model.CreateTableRequest;
import software.amazon.awssdk.services.dynamodb.model.CreateTableResponse;
import software.amazon.awssdk.services.dynamodb.model.KeySchemaElement;
import software.amazon.awssdk.services.dynamodb.model.KeyType;
import software.amazon.awssdk.services.dynamodb.model.ProvisionedThroughput;
import software.amazon.awssdk.services.dynamodb.model.ScalarAttributeType;
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
```

 **Code** 

```
    public static String createTableComKey(DynamoDbClient ddb, String tableName) {
        CreateTableRequest request = CreateTableRequest.builder()
                .attributeDefinitions(
                        AttributeDefinition.builder()
                                .attributeName("Language")
                                .attributeType(ScalarAttributeType.S)
                                .build(),
                        AttributeDefinition.builder()
                                .attributeName("Greeting")
                                .attributeType(ScalarAttributeType.S)
                                .build())
                .keySchema(
                        KeySchemaElement.builder()
                                .attributeName("Language")
                                .keyType(KeyType.HASH)
                                .build(),
                        KeySchemaElement.builder()
                                .attributeName("Greeting")
                                .keyType(KeyType.RANGE)
                                .build())
                .provisionedThroughput(
                        ProvisionedThroughput.builder()
                                .readCapacityUnits(new Long(10))
                                .writeCapacityUnits(new Long(10)).build())
                .tableName(tableName)
                .build();

       String tableId = "";

       try {
            CreateTableResponse result = ddb.createTable(request);
            tableId = result.tableDescription().tableId();
            return tableId;
        } catch (DynamoDbException e) {
            System.err.println(e.getMessage());
            System.exit(1);
        }
       return "";
    }
```

[GitHub](https://github.com/awsdocs/aws-doc-sdk-examples/blob/0b1785e42949ebf959eaa0f0da4dc2a48f92ea25/javav2/example_code/dynamodb/src/main/java/com/example/dynamodb/CreateTableCompositeKey.java) で完全な例をご覧ください。

## テーブルの一覧表示
<a name="dynamodb-list-tables"></a>

特定のリージョンのテーブルを一覧表示するには、`DynamoDbClient’s` `listTables` メソッドを呼び出します。

**注記**  
指定したテーブルがアカウントやリージョンにない場合は、[https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/model/ResourceNotFoundException.html](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/model/ResourceNotFoundException.html) がスローされます。

 **インポート** 

```
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.dynamodb.model.DynamoDbException;
import software.amazon.awssdk.services.dynamodb.model.ListTablesResponse;
import software.amazon.awssdk.services.dynamodb.model.ListTablesRequest;
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
import java.util.List;
```

 **Code** 

```
    public static void listAllTables(DynamoDbClient ddb){

        boolean moreTables = true;
        String lastName = null;

        while(moreTables) {
            try {
                ListTablesResponse response = null;
                if (lastName == null) {
                    ListTablesRequest request = ListTablesRequest.builder().build();
                    response = ddb.listTables(request);
                } else {
                    ListTablesRequest request = ListTablesRequest.builder()
                            .exclusiveStartTableName(lastName).build();
                    response = ddb.listTables(request);
                }

                List<String> tableNames = response.tableNames();

                if (tableNames.size() > 0) {
                    for (String curName : tableNames) {
                        System.out.format("* %s\n", curName);
                    }
                } else {
                    System.out.println("No tables found!");
                    System.exit(0);
                }

                lastName = response.lastEvaluatedTableName();
                if (lastName == null) {
                    moreTables = false;
                }
            } catch (DynamoDbException e) {
                System.err.println(e.getMessage());
                System.exit(1);
            }
        }
        System.out.println("\nDone!");
    }
```

デフォルトでは、1 回の呼び出しで最大 100 個のテーブルが返ります。評価された最後のテーブルを取得するには、返された [https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/model/ListTablesResponse.html](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/model/ListTablesResponse.html) オブジェクトに対して `lastEvaluatedTableName` を使用します。この値を使用して、前回の一覧表示で返された最後の値以降から、一覧表示を開始できます。

[GitHub](https://github.com/awsdocs/aws-doc-sdk-examples/blob/0b1785e42949ebf959eaa0f0da4dc2a48f92ea25/javav2/example_code/dynamodb/src/main/java/com/example/dynamodb/ListTables.java) で完全な例をご覧ください。

## テーブルの説明 (テーブルに関する情報の取得)
<a name="dynamodb-describe-table"></a>

`DynamoDbClient’s` `describeTable` メソッドを使用して、テーブルに関する情報を取得します。

**注記**  
指定したテーブルがアカウントやリージョンにない場合は、[https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/model/ResourceNotFoundException.html](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/model/ResourceNotFoundException.html) がスローされます。

 **インポート** 

```
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.dynamodb.model.DynamoDbException;
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
import software.amazon.awssdk.services.dynamodb.model.AttributeDefinition;
import software.amazon.awssdk.services.dynamodb.model.DescribeTableRequest;
import software.amazon.awssdk.services.dynamodb.model.ProvisionedThroughputDescription;
import software.amazon.awssdk.services.dynamodb.model.TableDescription;
import java.util.List;
```

 **Code** 

```
    public static void describeDymamoDBTable(DynamoDbClient ddb,String tableName ) {

        DescribeTableRequest request = DescribeTableRequest.builder()
                .tableName(tableName)
                .build();

        try {
            TableDescription tableInfo =
                    ddb.describeTable(request).table();

            if (tableInfo != null) {
                System.out.format("Table name  : %s\n",
                        tableInfo.tableName());
                System.out.format("Table ARN   : %s\n",
                        tableInfo.tableArn());
                System.out.format("Status      : %s\n",
                        tableInfo.tableStatus());
                System.out.format("Item count  : %d\n",
                        tableInfo.itemCount().longValue());
                System.out.format("Size (bytes): %d\n",
                        tableInfo.tableSizeBytes().longValue());

                ProvisionedThroughputDescription throughputInfo =
                        tableInfo.provisionedThroughput();
                System.out.println("Throughput");
                System.out.format("  Read Capacity : %d\n",
                        throughputInfo.readCapacityUnits().longValue());
                System.out.format("  Write Capacity: %d\n",
                        throughputInfo.writeCapacityUnits().longValue());

                List<AttributeDefinition> attributes =
                        tableInfo.attributeDefinitions();
                System.out.println("Attributes");

                for (AttributeDefinition a : attributes) {
                    System.out.format("  %s (%s)\n",
                            a.attributeName(), a.attributeType());
                }
            }
        } catch (DynamoDbException e) {
            System.err.println(e.getMessage());
            System.exit(1);
        }
        System.out.println("\nDone!");
    }
```

[GitHub](https://github.com/awsdocs/aws-doc-sdk-examples/blob/0b1785e42949ebf959eaa0f0da4dc2a48f92ea25/javav2/example_code/dynamodb/src/main/java/com/example/dynamodb/DescribeTable.java) で完全な例をご覧ください。

## テーブルの変更 (更新)
<a name="dynamodb-update-table"></a>

テーブルのプロビジョンドスループット値は、`DynamoDbClient’s` `updateTable` メソッドを呼び出すことで随時変更できます。

**注記**  
指定したテーブルがアカウントやリージョンにない場合は、[ResourceNotFoundException](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/model/ResourceNotFoundException.html) がスローされます。

 **インポート** 

```
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.dynamodb.model.ProvisionedThroughput;
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
import software.amazon.awssdk.services.dynamodb.model.UpdateTableRequest;
import software.amazon.awssdk.services.dynamodb.model.DynamoDbException;
```

 **Code** 

```
    public static void updateDynamoDBTable(DynamoDbClient ddb,
                                           String tableName,
                                           Long readCapacity,
                                           Long writeCapacity) {

        System.out.format(
                "Updating %s with new provisioned throughput values\n",
                tableName);
        System.out.format("Read capacity : %d\n", readCapacity);
        System.out.format("Write capacity : %d\n", writeCapacity);

        ProvisionedThroughput tableThroughput = ProvisionedThroughput.builder()
                .readCapacityUnits(readCapacity)
                .writeCapacityUnits(writeCapacity)
                .build();

        UpdateTableRequest request = UpdateTableRequest.builder()
                .provisionedThroughput(tableThroughput)
                .tableName(tableName)
                .build();

        try {
            ddb.updateTable(request);
        } catch (DynamoDbException e) {
            System.err.println(e.getMessage());
            System.exit(1);
        }

        System.out.println("Done!");
    }
```

[GitHub](https://github.com/awsdocs/aws-doc-sdk-examples/blob/0b1785e42949ebf959eaa0f0da4dc2a48f92ea25/javav2/example_code/dynamodb/src/main/java/com/example/dynamodb/UpdateTable.java) で完全な例をご覧ください。

## テーブルの削除
<a name="dynamodb-delete-table"></a>

テーブルを削除するには、`DynamoDbClient’s` `deleteTable` メソッドを呼び出してテーブルの名前を指定します。

**注記**  
指定したテーブルがアカウントやリージョンにない場合は、[ResourceNotFoundException](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/model/ResourceNotFoundException.html) がスローされます。

 **インポート** 

```
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.dynamodb.model.DynamoDbException;
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
import software.amazon.awssdk.services.dynamodb.model.DeleteTableRequest;
```

 **Code** 

```
    public static void deleteDynamoDBTable(DynamoDbClient ddb, String tableName) {

        DeleteTableRequest request = DeleteTableRequest.builder()
                .tableName(tableName)
                .build();

        try {
            ddb.deleteTable(request);

        } catch (DynamoDbException e) {
            System.err.println(e.getMessage());
            System.exit(1);
        }
        System.out.println(tableName +" was successfully deleted!");
    }
```

[GitHub](https://github.com/awsdocs/aws-doc-sdk-examples/blob/0b1785e42949ebf959eaa0f0da4dc2a48f92ea25/javav2/example_code/dynamodb/src/main/java/com/example/dynamodb/DeleteTable.java) で完全な例をご覧ください。

## 詳細情報
<a name="more-information"></a>
+  Amazon DynamoDB デベロッパーガイドの[テーブルの操作のガイドライン](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GuidelinesForTables.html)
+  Amazon DynamoDB デベロッパーガイドの [DynamoDB のテーブルの操作](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/WorkingWithTables.html)

# で項目を操作する DynamoDB
<a name="examples-dynamodb-items"></a>

では DynamoDB、項目は*属性*のコレクションであり、それぞれに*名前*と*値*があります。属性値はスカラー型、セット型、ドキュメント型のいずれかです。詳細については、 Amazon DynamoDB デベロッパーガイドの[命名規則とデータ型](https://docs.aws.amazon.com//amazondynamodb/latest/developerguide/HowItWorks.NamingRulesDataTypes.html)を参照してください。

## テーブルからの項目の取り出し (取得)
<a name="dynamodb-get-item"></a>

DynamoDbClient の `getItem` メソッドを呼び出して、指定する項目のテーブル名とプライマリキーバリューを持つ [GetItemRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/model/GetItemRequest.html) オブジェクトを渡します。これにより、その項目のすべての属性を含む [GetItemResponse](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/model/GetItemResponse.html) オブジェクトが返されます。特定の属性を取得するには、[ で、1 つ以上の](https://docs.aws.amazon.com//amazondynamodb/latest/developerguide/Expressions.ProjectionExpressions.html)プロジェクション式`GetItemRequest`を指定します。

返された `GetItemResponse` オブジェクトの `item()` メソッドを使用して、項目に関連付けられているキー (String) と値 ([AttributeValue](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/model/AttributeValue.html)) のペアの [Map](https://docs.oracle.com/javase/8/docs/api/index.html?java/util/Map.html) を取得できます。

 **インポート** 

```
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.dynamodb.model.DynamoDbException;
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
import software.amazon.awssdk.services.dynamodb.model.AttributeValue;
import software.amazon.awssdk.services.dynamodb.model.GetItemRequest;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
```

 **Code** 

```
    public static void getDynamoDBItem(DynamoDbClient ddb,String tableName,String key,String keyVal ) {

        HashMap<String,AttributeValue> keyToGet = new HashMap<String,AttributeValue>();

        keyToGet.put(key, AttributeValue.builder()
                .s(keyVal).build());

        GetItemRequest request = GetItemRequest.builder()
                .key(keyToGet)
                .tableName(tableName)
                .build();

        try {
            Map<String,AttributeValue> returnedItem = ddb.getItem(request).item();

            if (returnedItem != null) {
                Set<String> keys = returnedItem.keySet();
                System.out.println("Amazon DynamoDB table attributes: \n");

                for (String key1 : keys) {
                    System.out.format("%s: %s\n", key1, returnedItem.get(key1).toString());
                }
            } else {
                System.out.format("No item found with the key %s!\n", key);
            }
        } catch (DynamoDbException e) {
            System.err.println(e.getMessage());
            System.exit(1);
        }
    }
```

[GitHub](https://github.com/awsdocs/aws-doc-sdk-examples/blob/bc964a243276990f05c180618ea8b34777c68f0e/javav2/example_code/dynamodb/src/main/java/com/example/dynamodb/GetItem.java) で完全な例をご覧ください。

## 非同期クライアントを使用したテーブルからの項目の取り出し (取得)
<a name="id1ddb"></a>

DynamoDbAsyncClient の `getItem` メソッドを呼び出して、指定する項目のテーブル名とプライマリキーバリューを持つ [GetItemRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/model/GetItemRequest.html) オブジェクトを渡します。

その項目のすべての属性を持つ [Collection](https://docs.oracle.com/javase/8/docs/api/index.html?java/util/Collection.html) インスタンスを返すことができます (次の例を参照)。

 **インポート** 

```
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.dynamodb.model.GetItemRequest;
import software.amazon.awssdk.services.dynamodb.model.AttributeValue;
import software.amazon.awssdk.services.dynamodb.DynamoDbAsyncClient;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import software.amazon.awssdk.services.dynamodb.model.DynamoDbException;
```

 **Code** 

```
    public static void getItem(DynamoDbAsyncClient client, String tableName, String key,  String keyVal) {

        HashMap<String, AttributeValue> keyToGet =
                new HashMap<String, AttributeValue>();

        keyToGet.put(key, AttributeValue.builder()
                .s(keyVal).build());

        try {

            // Create a GetItemRequest instance
            GetItemRequest request = GetItemRequest.builder()
                    .key(keyToGet)
                    .tableName(tableName)
                    .build();

            // Invoke the DynamoDbAsyncClient object's getItem
            java.util.Collection<AttributeValue> returnedItem = client.getItem(request).join().item().values();

            // Convert Set to Map
            Map<String, AttributeValue> map = returnedItem.stream().collect(Collectors.toMap(AttributeValue::s, s->s));
            Set<String> keys = map.keySet();
            for (String sinKey : keys) {
                System.out.format("%s: %s\n", sinKey, map.get(sinKey).toString());
            }

        } catch (DynamoDbException e) {
            System.err.println(e.getMessage());
            System.exit(1);
        }
```

[GitHub](https://github.com/awsdocs/aws-doc-sdk-examples/blob/bc964a243276990f05c180618ea8b34777c68f0e/javav2/example_code/dynamodbasync/src/main/java/com/example/dynamodbasync/DynamoDBAsyncGetItem.java) で完全な例をご覧ください。

## テーブルへの新しい項目の追加
<a name="dynamodb-add-item"></a>

項目の属性を表すキーと値のペアの[マップ](https://docs.oracle.com/javase/8/docs/api/index.html?java/util/Map.html)を作成します。これらには、テーブルのプライマリキーフィールドの値を含める必要があります。プライマリキーで特定される項目がすでにある場合、フィールドはリクエストによって*更新*されます。

**注記**  
指定したテーブルがアカウントやリージョンにない場合は、[ResourceNotFoundException](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/model/ResourceNotFoundException.html) がスローされます。

 **インポート** 

```
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.dynamodb.model.DynamoDbException;
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
import software.amazon.awssdk.services.dynamodb.model.AttributeValue;
import software.amazon.awssdk.services.dynamodb.model.PutItemRequest;
import software.amazon.awssdk.services.dynamodb.model.ResourceNotFoundException;
import java.util.HashMap;
```

 **Code** 

```
    public static void putItemInTable(DynamoDbClient ddb,
                                      String tableName,
                                      String key,
                                      String keyVal,
                                      String albumTitle,
                                      String albumTitleValue,
                                      String awards,
                                      String awardVal,
                                      String songTitle,
                                      String songTitleVal){

        HashMap<String,AttributeValue> itemValues = new HashMap<String,AttributeValue>();

        // Add all content to the table
        itemValues.put(key, AttributeValue.builder().s(keyVal).build());
        itemValues.put(songTitle, AttributeValue.builder().s(songTitleVal).build());
        itemValues.put(albumTitle, AttributeValue.builder().s(albumTitleValue).build());
        itemValues.put(awards, AttributeValue.builder().s(awardVal).build());

        PutItemRequest request = PutItemRequest.builder()
                .tableName(tableName)
                .item(itemValues)
                .build();

        try {
            ddb.putItem(request);
            System.out.println(tableName +" was successfully updated");

        } catch (ResourceNotFoundException e) {
            System.err.format("Error: The Amazon DynamoDB table \"%s\" can't be found.\n", tableName);
            System.err.println("Be sure that it exists and that you've typed its name correctly!");
            System.exit(1);
        } catch (DynamoDbException e) {
            System.err.println(e.getMessage());
            System.exit(1);
        }
    }
```

[GitHub](https://github.com/awsdocs/aws-doc-sdk-examples/blob/f4eaf2b2971805cfb2b87a8e5ab408f83169432e/javav2/example_code/dynamodb/src/main/java/com/example/dynamodb/PutItem.java) で完全な例をご覧ください。

## テーブルの既存の項目の更新
<a name="dynamodb-update-item"></a>

テーブルに既に存在する項目の属性を更新するには、DynamoDbClient の `updateItem` メソッドを呼び出して、テーブル名、プライマリキーバリュー、更新するフィールドのマップを渡します。

**注記**  
指定したテーブルがアカウントやリージョンにない場合、または渡したプライマリキーで特定される項目がない場合、[ResourceNotFoundException](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/model/ResourceNotFoundException.html) がスローされます。

 **インポート** 

```
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.dynamodb.model.DynamoDbException;
import software.amazon.awssdk.services.dynamodb.model.AttributeAction;
import software.amazon.awssdk.services.dynamodb.model.AttributeValue;
import software.amazon.awssdk.services.dynamodb.model.AttributeValueUpdate;
import software.amazon.awssdk.services.dynamodb.model.ResourceNotFoundException;
import software.amazon.awssdk.services.dynamodb.model.UpdateItemRequest;
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
import java.util.HashMap;
```

 **Code** 

```
    public static void updateTableItem(DynamoDbClient ddb,
                                       String tableName,
                                       String key,
                                       String keyVal,
                                       String name,
                                       String updateVal){

        HashMap<String,AttributeValue> itemKey = new HashMap<String,AttributeValue>();

        itemKey.put(key, AttributeValue.builder().s(keyVal).build());

        HashMap<String,AttributeValueUpdate> updatedValues =
                new HashMap<String,AttributeValueUpdate>();

        // Update the column specified by name with updatedVal
        updatedValues.put(name, AttributeValueUpdate.builder()
                .value(AttributeValue.builder().s(updateVal).build())
                .action(AttributeAction.PUT)
                .build());

        UpdateItemRequest request = UpdateItemRequest.builder()
                .tableName(tableName)
                .key(itemKey)
                .attributeUpdates(updatedValues)
                .build();

        try {
            ddb.updateItem(request);
        } catch (ResourceNotFoundException e) {
            System.err.println(e.getMessage());
            System.exit(1);
        } catch (DynamoDbException e) {
            System.err.println(e.getMessage());
            System.exit(1);
        }

        System.out.println("Done!");
    }
```

[GitHub](https://github.com/awsdocs/aws-doc-sdk-examples/blob/f4eaf2b2971805cfb2b87a8e5ab408f83169432e/javav2/example_code/dynamodb/src/main/java/com/example/dynamodb/UpdateItem.java) で完全な例をご覧ください。

## テーブルの既存の項目の削除
<a name="dynamodb-delete-item"></a>

テーブルに存在する項目を削除するには、DynamoDbClient の `deleteItem` メソッドを使用して、テーブル名とプライマリキーバリューを渡します。

**注記**  
指定したテーブルがアカウントやリージョンにない場合、または渡したプライマリキーで特定される項目がない場合、[ResourceNotFoundException](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/model/ResourceNotFoundException.html) がスローされます。

 **インポート** 

```
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
import software.amazon.awssdk.services.dynamodb.model.AttributeValue;
import software.amazon.awssdk.services.dynamodb.model.DeleteItemRequest;
import software.amazon.awssdk.services.dynamodb.model.DynamoDbException;
import java.util.HashMap;
```

 **Code** 

```
  public static void deleteDynamoDBItem(DynamoDbClient ddb, String tableName, String key, String keyVal) {

        HashMap<String,AttributeValue> keyToGet =
                new HashMap<String,AttributeValue>();

        keyToGet.put(key, AttributeValue.builder()
                .s(keyVal)
                .build());

        DeleteItemRequest deleteReq = DeleteItemRequest.builder()
                .tableName(tableName)
                .key(keyToGet)
                .build();

        try {
            ddb.deleteItem(deleteReq);
        } catch (DynamoDbException e) {
            System.err.println(e.getMessage());
            System.exit(1);
        }
    }
```

[GitHub](https://github.com/awsdocs/aws-doc-sdk-examples/blob/f4eaf2b2971805cfb2b87a8e5ab408f83169432e/javav2/example_code/dynamodb/src/main/java/com/example/dynamodb/DeleteItem.java) で完全な例をご覧ください。

## 詳細情報
<a name="more-information"></a>
+  Amazon DynamoDB デベロッパーガイドの[項目の操作のガイドライン](https://docs.aws.amazon.com//amazondynamodb/latest/developerguide/best-practices.html)
+  Amazon DynamoDB デベロッパーガイドの[「 でのアイテムの操作 DynamoDB](https://docs.aws.amazon.com//amazondynamodb/latest/developerguide/WorkingWithItems.html)」

# を使用して Java オブジェクトを DynamoDB 項目にマッピングする AWS SDK for Java 2.x
<a name="dynamodb-enhanced-client"></a>

[DynamoDB Enhanced Client API](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/package-summary.html) は、SDK for Java v1.x の `DynamoDBMapper` クラスの後継となる高レベルのライブラリです。クライアント側のクラスを DynamoDB テーブルにマッピングする簡単な方法を提供します。テーブルおよび対応するデータクラスの間の関係をコードで定義します。関係を定義したら、DynamoDB のテーブルまたは項目に対して、さまざまな作成、読み取り、更新、または削除 (CRUD) オペレーションを直感的に実行できます。

DynamoDB Enhanced Client API には、定義されたスキーマに従わないドキュメントタイプの項目を操作できる[拡張ドキュメント API](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/document/package-summary.html) も含まれています。

**Topics**
+ [DynamoDB Enhanced Client API の使用を開始する](ddb-en-client-getting-started.md)
+ [DynamoDB Enhanced Client API の基礎について学ぶ](ddb-en-client-use.md)
+ [高度なマッピング機能を使用する](ddb-en-client-adv-features.md)
+ [DynamoDB 用の拡張ドキュメント API を使用して JSON ドキュメントを操作する](ddb-en-client-doc-api.md)
+ [拡張機能を使用して DynamoDB 拡張クライアントオペレーションをカスタマイズする](ddb-en-client-extensions.md)
+ [DynamoDB 拡張クライアント API を非同期的に使用する](ddb-en-client-async.md)
+ [データクラス注釈](ddb-en-client-anno-index.md)

# DynamoDB Enhanced Client API の使用を開始する
<a name="ddb-en-client-getting-started"></a>

次のチュートリアルでは、DynamoDB Enhanced Client API を操作するために必要な基本事項を紹介します。

## 依存関係を追加する
<a name="ddb-en-client-gs-dep"></a>

プロジェクトで DynamoDB Enhanced Client API を使い始めるには、`dynamodb-enhanced` Maven アーティファクトへの依存関係を追加します。これは次の例で示されます。

------
#### [ Maven ]

```
<project>
  <dependencyManagement>
   <dependencies>
      <dependency>
        <groupId>software.amazon.awssdk</groupId>
        <artifactId>bom</artifactId>
        <version><VERSION></version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
   </dependencies>
  </dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>software.amazon.awssdk</groupId>
      <artifactId>dynamodb-enhanced</artifactId>
    </dependency>
  </dependencies>
  ...
</project>
```

Maven central リポジトリで[最新バージョン](https://central.sonatype.com/artifact/software.amazon.awssdk/bom)を検索し、*<VERSION>* をこの値に置き換えます。

------
#### [ Gradle ]

```
repositories {
    mavenCentral()
}
dependencies {
    implementation(platform("software.amazon.awssdk:bom:<VERSION>"))
    implementation("software.amazon.awssdk:dynamodb-enhanced")
    ...
}
```

Maven central リポジトリで[最新バージョン](https://central.sonatype.com/artifact/software.amazon.awssdk/bom)を検索し、*<VERSION>* をこの値に置き換えます。

------

# データクラスから `TableSchema` を生成する
<a name="ddb-en-client-gs-tableschema"></a>

`[TableSchema](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/TableSchema.html)` を使用すると、拡張クライアントは DynamoDB 属性値をクライアント側クラスとの間でマッピングできるようになります。このチュートリアルでは、静的データクラスから派生し、ビルダーを使用してコードから生成された `TableSchema` について説明します。

## 注釈付きデータクラスを使用する
<a name="ddb-en-client-gs-tableschema-anno-bean"></a>

SDK for Java 2.x には、データクラスと一緒に使用することで、Java Bean で使用して、クラスをテーブルにマッピングするための `TableSchema` をすばやく生成できる[一連の注釈](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/mapper/annotations/package-summary.html)が含まれています。

まず、[JavaBean 仕様](https://download.oracle.com/otn-pub/jcp/7224-javabeans-1.01-fr-spec-oth-JSpec/beans.101.pdf)に準拠するデータクラスを作成します。この仕様では、クラスには引数のないパブリックコンストラクタが必要であり、クラスの各属性にはゲッターとセッターが必要です。データクラスが `DynamoDbBean` であることを示すクラスレベルの注釈を含めます。また、少なくとも、 getters と setters にはプライマリキー属性の `DynamoDbPartitionKey` 注釈を含めます。

[属性レベルの注釈](ddb-en-client-anno-index.md)はゲッターまたはセッターに適用できますが、両方に適用することはできません。

**注記**  
通常、`property` という用語は JavaBean にカプセル化された値に使用されます。ただし、このガイドでは、DynamoDB で使用されている用語との一貫性を保つため、代わりに `attribute` という用語を使用しています。

次の `Customer` クラスは、クラス定義を DynamoDB テーブルにリンクする注釈を示しています。

### `Customer` クラス
<a name="ddb-en-client-gs-tableschema-anno-bean-cust"></a>

```
package org.example.tests.model;

import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbBean;
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbPartitionKey;
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbSortKey;

import java.time.Instant;

@DynamoDbBean
public class Customer {

    private String id;
    private String name;
    private String email;
    private Instant regDate;

    @DynamoDbPartitionKey
    public String getId() { return this.id; }

    public void setId(String id) { this.id = id; }

    public String getCustName() { return this.name; }

    public void setCustName(String name) { this.name = name; }

    @DynamoDbSortKey
    public String getEmail() { return this.email; }

    public void setEmail(String email) { this.email = email; }

    public Instant getRegistrationDate() { return this.regDate; }

    public void setRegistrationDate(Instant registrationDate) { this.regDate = registrationDate; }

    @Override
    public String toString() {
        return "Customer [id=" + id + ", name=" + name + ", email=" + email
                + ", regDate=" + regDate + "]";
    }
}
```

注釈付きデータクラスを作成したら、次のスニペットに示すように、それを使って `TableSchema` を作成します。

```
static final TableSchema<Customer> customerTableSchema = TableSchema.fromBean(Customer.class);
```

`TableSchema` は静的で変更不可能であるように設計されています。通常、クラスロード時にインスタンス化できます。

静的 `TableSchema.fromBean()` ファクトリメソッドは Bean をイントロスペクトして、データクラス属性 (プロパティ) と DynamoDB 属性間のマッピングを生成します。

複数のデータクラスで構成されるデータモデルの操作例については、[Bean、Map、List、Set の属性を使用する](ddb-en-client-adv-features-nested.md) セクションの「`Person` クラス」を参照してください。

## ビルダーを使用する
<a name="ddb-en-client-gs-tableschema-builder"></a>

テーブルスキーマをコードで定義すれば、Bean イントロスペクションのコストを省くことができます。スキーマをコーディングする場合、クラスは JavaBean の命名基準に従う必要も、注釈を付ける必要もありません。次の例ではビルダーを使用しており、注釈を使用する `Customer` クラスの例と同じです。

```
static final TableSchema<Customer> customerTableSchema =
                TableSchema.builder(Customer.class)
                        .newItemSupplier(Customer::new)
                        .addAttribute(String.class, a -> a.name("id")
                                .getter(Customer::getId)
                                .setter(Customer::setId)
                                .tags(StaticAttributeTags.primaryPartitionKey()))
                        .addAttribute(String.class, a -> a.name("email")
                                .getter(Customer::getEmail)
                                .setter(Customer::setEmail)
                                .tags(StaticAttributeTags.primarySortKey()))
                        .addAttribute(String.class, a -> a.name("name")
                                .getter(Customer::getCustName)
                                .setter(Customer::setCustName))
                        .addAttribute(Instant.class, a -> a.name("registrationDate")
                                .getter(Customer::getRegistrationDate)
                                .setter(Customer::setRegistrationDate))
                        .build();
```

# 拡張クライアントと `DynamoDbTable` を作成する
<a name="ddb-en-client-getting-started-dynamodbTable"></a>

## 拡張クライアントを作成する
<a name="ddb-en-client-getting-started-dynamodbTable-eclient"></a>

[DDynamoDbEnhancedClient](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/DynamoDbEnhancedClient.html) クラスまたはその非同期クラスである [DynamoDBEnhancedAsyncClient](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/DynamoDbEnhancedAsyncClient.html) は、DynamoDB Enhanced Client API を操作するためのエントリポイントです。

拡張クライアントでは、作業を実行するための標準の `[DynamoDbClient](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/DynamoDbClient.html)` が必要です。API には、`DynamoDbEnhancedClient` インスタンスを作成する 2 つの方法があります。以下のスニペットに示す 1 つ目のオプションは、構成設定から選択したデフォルト設定を使用して標準の `DynamoDbClient` を作成します。

```
DynamoDbEnhancedClient enhancedClient = DynamoDbEnhancedClient.create();
```

基礎となる標準クライアントを設定する場合は、次のスニペットに示すように、拡張クライアントのビルダーメソッドにそれを提供することができます。

```
// Configure an instance of the standard DynamoDbClient.
DynamoDbClient standardClient = DynamoDbClient.builder()
    .region(Region.US_EAST_1)
    .credentialsProvider(ProfileCredentialsProvider.create())
    .build();

// Use the configured standard client with the enhanced client.
DynamoDbEnhancedClient enhancedClient = DynamoDbEnhancedClient.builder()
    .dynamoDbClient(standardClient)
    .build();
```

## `DynamoDbTable` インスタンスを作成する
<a name="ddb-en-client-getting-started-dynamodbTable-table"></a>

[https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/DynamoDbTable.html](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/DynamoDbTable.html) は、`TableSchema` によって提供されるマッピング機能を使用する DynamoDB テーブルのクライアント側表現と考えます。`DynamoDbTable` クラスには、単一の DynamoDB テーブルを操作できる CRUD オペレーションのメソッドが用意されています。

`DynamoDbTable<T>` は、カスタムクラスでもドキュメントタイプのアイテムを操作するときの `EnhancedDocument` でも、単一の型引数を取る汎用クラスです。この引数タイプは、使用するクラスと単一の DynamoDB テーブルとの関係を確立します。

次のスニペットに示すように、`DynamoDbEnhancedClient` の `table()` ファクトリメソッドを使用して、`DynamoDbTable` インスタンスを作成します。

```
static final DynamoDbTable<Customer> customerTable = 
        enhancedClient.table("Customer", TableSchema.fromBean(Customer.class));
```

`DynamoDbTable` インスタンスは不変であり、アプリケーション全体で使用できるので、シングルトンの候補です。

これで、コードに `Customer` インスタンスを使用できる DynamoDB テーブルのインメモリ表現ができました。実際の DynamoDB テーブルは、存在する場合と存在しない場合があります。`Customer` という名前のテーブルがすでに存在する場合は、そのテーブルに対して CRUD オペレーションを実行し始めることができます。テーブルが見つからない場合、次のセクションで説明するように、`DynamoDbTable` インスタンスを使用してテーブルを作成します。

# 必要に応じて、DynamoDB テーブルを作成する
<a name="ddb-en-client-gs-ddbtable"></a>

`DynamoDbTable` インスタンスを作成したら、そのインスタンスを使用して DynamoDB でテーブルを *1 回*だけ作成します。

## テーブル作成例コード
<a name="ddb-en-client-gs-ddbtable-createex"></a>

次の例では、`Customer` データクラスに基づいて DynamoDB テーブルを作成します。

この例では、クラス名と同じ `Customer` という名前で DynamoDB テーブルを作成しますが、テーブル名は別の名前でもかまいません。テーブルにどのような名前を付けるにしても、テーブルを操作するには他のアプリケーションでもこの名前を使用する必要があります。基になる DynamoDB テーブルを操作するために、別の `DynamoDbTable` オブジェクトを作成するときはいつでも、この名前を `table()` メソッドに指定してください。

`createTable` メソッドに渡される Java lambda パラメータ、`builder`、によって、[テーブルをカスタマイズ](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/CreateTableEnhancedRequest.Builder.html)できます。この例では、[プロビジョニングされたスループット](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.ReadWriteCapacityMode.html#HowItWorks.ProvisionedThroughput.Manual)が設定されています。テーブルの作成時にデフォルト設定を使用する場合は、次のスニペットに示すようにビルダーをスキップします。

```
customerTable.createTable();
```

デフォルト設定を使用すると、プロビジョニングされたスループットの値は設定されません。代わりに、テーブルの請求モードは[オンデマンド](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.ReadWriteCapacityMode.html#HowItWorks.OnDemand)に設定されます。

この例では、レスポンスで受け取ったテーブル名を出力しようとする前に、`[DynamoDbWaiter](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/waiters/DynamoDbWaiter.html)` を使用しています。テーブルの作成には少し時間がかかります。したがって、ウェーターを使用すると、テーブルを使用する前に DynamoDB サービスをポーリングしてテーブルが存在するかどうかを確認するロジックを記述する必要がなくなります。

### インポート
<a name="ddb-en-client-gs-ddbtable-imports"></a>

```
import com.example.dynamodb.Customer;
import software.amazon.awssdk.core.internal.waiters.ResponseOrException;
import software.amazon.awssdk.enhanced.dynamodb.DynamoDbEnhancedClient;
import software.amazon.awssdk.enhanced.dynamodb.DynamoDbTable;
import software.amazon.awssdk.enhanced.dynamodb.TableSchema;
import software.amazon.awssdk.enhanced.dynamodb.model.CreateTableEnhancedRequest;
import software.amazon.awssdk.services.dynamodb.model.DescribeTableResponse;
import software.amazon.awssdk.services.dynamodb.waiters.DynamoDbWaiter;
```

### コード
<a name="ddb-en-client-gs-ddbtable-code"></a>

```
 public static void createCustomerTable(DynamoDbTable<Customer> customerTable, DynamoDbClient standardClient) {
     // Create the DynamoDB table using the 'customerTable' DynamoDbTable instance.
     customerTable.createTable(builder -> builder
             .provisionedThroughput(b -> b
                     .readCapacityUnits(10L)
                     .writeCapacityUnits(10L)
                     .build())
     );
     // The DynamoDbClient instance (named 'standardClient') passed to the builder for the DynamoDbWaiter is the same instance
     // that was passed to the builder of the DynamoDbEnhancedClient instance that we created previously.
     // By using the same instance, it ensures that the same Region that was configured on the standard DynamoDbClient 
     // instance is used for other service clients that accept a DynamoDbClient during construction.
     try (DynamoDbWaiter waiter = DynamoDbWaiter.builder().client(standardClient).build()) { // DynamoDbWaiter is Autocloseable
         ResponseOrException<DescribeTableResponse> response = waiter
                 .waitUntilTableExists(builder -> builder.tableName("Customer").build())
                 .matched();
         DescribeTableResponse tableDescription = response.response().orElseThrow(
                 () -> new RuntimeException("Customer table was not created."));
         // The actual error can be inspected in response.exception()
         logger.info("Customer table was created.");
     }
 }
```

**注記**  
DynamoDB テーブルの属性名は、テーブルがデータクラスから生成される場合、小文字で始まります。テーブルの属性名を大文字で始めたい場合は、[`@DynamoDbAttribute(NAME)` 注釈](ddb-en-client-adv-features-inex-attr.md)を使用して、必要な名前をパラメータとして指定します。

# オペレーションを実行する
<a name="ddb-en-client-gs-use"></a>

テーブルが作成されたら、`DynamoDbTable` インスタンスを使用して DynamoDB テーブルに対して操作を実行します。

次の例では、[`Customer` データクラス](ddb-en-client-gs-tableschema.md#ddb-en-client-gs-tableschema-anno-bean-cust)のインスタンスとともにシングルトン `DynamoDbTable<Customer>` をパラメータとして渡し、テーブルに新しいアイテムを追加します。

```
    public static void putItemExample(DynamoDbTable<Customer> customerTable, Customer customer){
        logger.info(customer.toString());
        customerTable.putItem(customer);
    }
```

## `Customer` オブジェクト
<a name="perform_ops_create_customer_instatnce"></a>

```
        Customer customer = new Customer();
        customer.setId("1");
        customer.setCustName("Customer Name");
        customer.setEmail("customer@example.com");
        customer.setRegistrationDate(Instant.parse("2023-07-03T10:15:30.00Z"));
```

`customer` オブジェクトを DynamoDB サービスに送信する前に、オブジェクトの `toString()` メソッドの出力をログに記録して、拡張クライアントが送信するものと比較します。

```
Customer [id=1, name=Customer Name, email=customer@example.com, regDate=2023-07-03T10:15:30Z]
```

ワイヤレベルのログ記録には、生成されたリクエストのペイロードが表示されます。拡張クライアントはデータクラスから低レベルの表現を生成しました。Java の `Instant` タイプである `regDate` 属性は、DynamoDB の文字列として表されます。

```
{
  "TableName": "Customer",
  "Item": {
    "registrationDate": {
      "S": "2023-07-03T10:15:30Z"
    },
    "id": {
      "S": "1"
    },
    "custName": {
      "S": "Customer Name"
    },
    "email": {
      "S": "customer@example.com"
    }
  }
}
```

# 既存のテーブルを使用する
<a name="ddb-en-client-gs-existingtable"></a>

前のセクションでは、Java データクラスから DynamoDB テーブルを作成する方法を示しました。既存のテーブルがあって、拡張クライアントの機能を使いたい場合は、そのテーブルを操作する Java データクラスを作成できます。DynamoDB テーブルを調べ、必要な注釈をデータクラスに追加する必要があります。

既存のテーブルを操作する前に、`DynamoDbEnhanced.table()` メソッドを呼び出します。これは、前の例で次のステートメントを使用して行われました。

```
DynamoDbTable<Customer> customerTable = enhancedClient.table("Customer", TableSchema.fromBean(Customer.class));
```

`DynamoDbTable` インスタンスが返されたら、基になるテーブルですぐに作業を開始できます。`DynamoDbTable.createTable()` メソッドを呼び出してテーブルを再作成する必要はありません。

次の例では、DynamoDB テーブルから `Customer` インスタンスをすぐに取得することで示されます。

```
DynamoDbTable<Customer> customerTable = enhancedClient.table("Customer", TableSchema.fromBean(Customer.class));
// The Customer table exists already and has an item with a primary key value of "1" and a sort key value of "customer@example.com".
customerTable.getItem(
        Key.builder().
                partitionValue("1").
                sortValue("customer@example.com").build());
```

**重要**  
`table()` メソッドで使用されるテーブル名は、既存の DynamoDB テーブル名と一致する必要があります。

# DynamoDB Enhanced Client API の基礎について学ぶ
<a name="ddb-en-client-use"></a>

このトピックでは、DynamoDB Enhanced Client API の基本機能について説明し、[標準の DynamoDB client API](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/package-summary.html) と比較します。

DynamoDB Enhanced Client API を初めて使用する場合は、[入門チュートリアル](ddb-en-client-getting-started.md)を読んで基本的なクラスに慣れることをおすすめします。

## Java の DynamoDB アイテム
<a name="ddb-en-client-use-usecase"></a>

DynamoDB テーブルにはアイテムが保存されます。ユースケースに応じて、Java 側のアイテムは静的に構造化されたデータまたは動的に作成された構造の形をとることができます。

ユースケースで一貫性のある属性セットを持つアイテムが必要な場合は、[注釈付きクラス](ddb-en-client-gs-tableschema.md#ddb-en-client-gs-tableschema-anno-bean)を使用するか、[ビルダー](ddb-en-client-gs-tableschema.md#ddb-en-client-gs-tableschema-builder)を使用して適切な静的型 `TableSchema` を生成します。

あるいは、さまざまな構造から構成されるアイテムを保存する必要がある場合は、`DocumentTableSchema` を作成します。`DocumentTableSchema` は[拡張ドキュメント API](ddb-en-client-doc-api.md) の一部であり、必要なのは静的型プライマリキーのみで、`EnhancedDocument` インスタンスと連携してデータ要素を保持します。拡張ドキュメント API については別の[トピック](ddb-en-client-doc-api.md)で説明しています。

## データモデルクラスの属性型
<a name="ddb-en-client-use-types"></a>

DynamoDB は、Java の豊富なタイプシステムに比べて[少数の属性型](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.NamingRulesDataTypes.html#HowItWorks.DataTypes)をサポートしています。DynamoDB Enhanced Client API には Java クラスのメンバーと DynamoDB 属性タイプを相互に変換するメカニズムを提供します。

Java データクラスの属性型 (プロパティ) は、プリミティブではなくオブジェクト型である必要があります。たとえば、 `Long` および `int` プリミティブではなく、常に `long` および `Integer` オブジェクトデータ型を使用します。

デフォルトでは、DynamoDB Enhanced Client API は、[整数](https://docs.oracle.com/javase/8/docs/api/java/lang/Integer.html)、[文字列](https://docs.oracle.com/javase/8/docs/api/java/lang/String.html)、[BigDecimal](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/internal/converter/attribute/BigDecimalAttributeConverter.html)、[インスタント](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/internal/converter/attribute/InstantAsStringAttributeConverter.html)など、多数のタイプの属性コンバーターをサポートしています。このリストは、[AttributeConverter インターフェイスの既知の実装クラス](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/AttributeConverter.html)に表示されます。リストには、マップ、リスト、セットなど、さまざまなタイプとコレクションが含まれています。

デフォルトではサポートされていない属性型や JavaBean 規約に準拠していない属性型のデータを保存するには、変換を行うカスタム `AttributeConverter` 実装を記述できます。[例](ddb-en-client-adv-features-conversion.md#ddb-en-client-adv-features-conversion-example)については、「属性変換」セクションを参照してください。

クラスが Java Bean 仕様に準拠する属性型 (または[不変データクラス](ddb-en-client-use-immut.md)) のデータを保存するには、2 つの方法があります。
+ ソースファイルにアクセスできる場合は、クラスに `@DynamoDbBean` (または `@DynamoDbImmutable`) という注釈を付けることができます。ネストされた属性について説明しているセクションでは、注釈付きクラスの使用[例](ddb-en-client-adv-features-nested.md#ddb-en-client-adv-features-nested-map-anno)を示しています。
+ 属性の JavaBean データクラスのソースファイルにアクセスできない (またはアクセス権限のあるクラスのソースファイルに注釈を付けたくない) 場合は、ビルダーアプローチを使用できます。これにより、キーを定義せずにテーブルスキーマが作成されます。次に、このテーブルスキーマを別のテーブルスキーマ内にネストしてマッピングを実行できます。ネストされた属性セクションには、ネストされたスキーマの[使用例](ddb-en-client-adv-features-nested.md#ddb-en-client-adv-features-nested-map-builder)があります。

### Null 値
<a name="ddb-en-client-use-types-nulls"></a>

`putItem` メソッドを使用する場合、拡張クライアントは、マッピングされたデータオブジェクトの NULL 値属性を DynamoDB へのリクエストに含めません。

`updateItem` リクエストに対する SDK のデフォルト動作は、`updateItem` メソッドで送信するオブジェクトで null に設定されている属性を DynamoDB の項目から削除します。一部の属性値を更新し、他の属性値を変更しないようにするには、2 つのオプションがあります。
+ 値を変更する前に (`getItem` を使用して) 項目を取得します。このアプローチを使用すると、SDK はすべての更新された値と古い値を DynamoDB に送信します。
+ 項目を更新するリクエストを構築するときは、`[IgnoreNullsMode](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/IgnoreNullsMode.html).SCALAR_ONLY` または `IgnoreNullsMode.MAPS_ONLY` のいずれかを使用します。どちらのモードも、DynamoDB のスカラー属性を表すオブジェクト内の null 値のプロパティを無視します。このガイドの [複合型を含む項目の更新](ddb-en-client-adv-features-nested.md#ddb-en-client-adv-features-nested-updates) トピックには、`IgnoreNullsMode` 値の詳細と複合型の使用方法が記載されています。

次の例は、`updateItem()` メソッドの `ignoreNullsMode()` を示しています。

```
    public static void updateItemNullsExample() {
        Customer customer = new Customer();
        customer.setCustName("CustomerName");
        customer.setEmail("email");
        customer.setId("1");
        customer.setRegistrationDate(Instant.now());

        logger.info("Original customer: {}", customer);

        // Put item with values for all attributes.
        try {
            customerAsyncDynamoDbTable.putItem(customer).join();
        } catch (RuntimeException rte) {
            logger.error("A exception occurred during putItem: {}", rte.getCause().getMessage(), rte);
            return;
        }

        // Create a Customer instance with the same 'id' and 'email' values, but a different 'name' value.
        // Do not set the 'registrationDate' attribute.
        Customer customerForUpdate = new Customer();
        customerForUpdate.setCustName("NewName");
        customerForUpdate.setEmail("email");
        customerForUpdate.setId("1");

        // Update item without setting the 'registrationDate' property and set IgnoreNullsMode to SCALAR_ONLY.
        try {
            Customer updatedWithNullsIgnored = customerAsyncDynamoDbTable.updateItem(b -> b
                            .item(customerForUpdate)
                            .ignoreNullsMode(IgnoreNullsMode.SCALAR_ONLY))
                    .join();
            logger.info("Customer updated with nulls ignored: {}", updatedWithNullsIgnored.toString());
        } catch (RuntimeException rte) {
            logger.error("An exception occurred during updateItem: {}", rte.getCause().getMessage(), rte);
            return;
        }

        // Update item without setting the registrationDate attribute and not setting ignoreNulls to true.
        try {
            Customer updatedWithNullsUsed = customerAsyncDynamoDbTable.updateItem(customerForUpdate)
                    .join();
            logger.info("Customer updated with nulls used: {}", updatedWithNullsUsed.toString());
        } catch (RuntimeException rte) {
            logger.error("An exception occurred during updateItem: {}", rte.getCause().getMessage(), rte);
        }
    }


// Logged lines. 
Original customer: Customer [id=1, name=CustomerName, email=email, regDate=2024-10-11T14:12:30.222858Z]
Customer updated with nulls ignored: Customer [id=1, name=NewName, email=email, regDate=2024-10-11T14:12:30.222858Z]
Customer updated with nulls used: Customer [id=1, name=NewName, email=email, regDate=null]
```

## DynamoDB Enhanced Client API の基本メソッド
<a name="ddb-en-client-use-basic-ops"></a>

拡張クライアントの基本的なメソッドは、その名前に由来する DynamoDB サービスオペレーションにマッピングされます。次の例は、各方法の最も単純なバリエーションを示しています。拡張リクエストオブジェクトを渡すことで、各メソッドをカスタマイズできます。拡張リクエストオブジェクトは、標準の DynamoDB クライアントで使用できるほとんどの機能を提供します。これらは、 AWS SDK for Java 2.x API リファレンスで完全に文書化されています。

この例では前に示した [`Customer` クラス](ddb-en-client-gs-tableschema.md#ddb-en-client-gs-tableschema-anno-bean-cust) を使用しています。

```
// CreateTable
customerTable.createTable();

// GetItem
Customer customer = customerTable.getItem(Key.builder().partitionValue("a123").build());

// UpdateItem
Customer updatedCustomer = customerTable.updateItem(customer);

// PutItem
customerTable.putItem(customer);

// DeleteItem
Customer deletedCustomer = customerTable.deleteItem(Key.builder().partitionValue("a123").sortValue(456).build());

// Query
PageIterable<Customer> customers = customerTable.query(keyEqualTo(k -> k.partitionValue("a123")));

// Scan
PageIterable<Customer> customers = customerTable.scan();

// BatchGetItem
BatchGetResultPageIterable batchResults = 
    enhancedClient.batchGetItem(r -> r.addReadBatch(ReadBatch.builder(Customer.class)
                                      .mappedTableResource(customerTable)
                                      .addGetItem(key1)
                                      .addGetItem(key2)
                                      .addGetItem(key3)
                                      .build()));

// BatchWriteItem
batchResults = enhancedClient.batchWriteItem(r -> r.addWriteBatch(WriteBatch.builder(Customer.class)
                                                   .mappedTableResource(customerTable)
                                                   .addPutItem(customer)
                                                   .addDeleteItem(key1)
                                                   .addDeleteItem(key1)
                                                   .build()));

// TransactGetItems
transactResults = enhancedClient.transactGetItems(r -> r.addGetItem(customerTable, key1)
                                                        .addGetItem(customerTable, key2));

// TransactWriteItems
enhancedClient.transactWriteItems(r -> r.addConditionCheck(customerTable, 
                                                           i -> i.key(orderKey)
                                                                 .conditionExpression(conditionExpression))
                                        .addUpdateItem(customerTable, customer)
                                        .addDeleteItem(customerTable, key));
```

## DynamoDB Enhanced Client を標準の DynamoDB クライアントと比較する
<a name="ddb-en-client-use-compare"></a>

DynamoDB client API ([標準](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/package-summary.html)と[拡張](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/package-summary.html)) はどちらも、DynamoDB テーブルを操作して CRUD (作成、読み取り、更新、削除) データレベルの操作を実行できます。クライアント API の違いは、その方法にあります。標準クライアントを使用すると、低レベルのデータ属性を直接操作できます。拡張クライアント API では、使い慣れた Java クラスが使用され、バックグラウンドで低レベル API にマッピングされます。

どちらのクライアント API もデータレベルの操作をサポートしていますが、標準の DynamoDB クライアントはリソースレベルの操作もサポートします。リソースレベルのオペレーションは、バックアップの作成、テーブルの一覧表示、テーブルの更新など、データベースを管理します。拡張クライアント API は、テーブルの作成、説明、削除など、特定の数のリソースレベルの操作をサポートします。

2 つのクライアント API が使用するさまざまなアプローチの違いを説明するために、以下のコード例は、標準クライアントと拡張クライアントを使用して同じ `ProductCatalog` テーブルを作成する方法を示しています。

### 比較: 標準の DynamoDB クライアントを使用してテーブルを作成
<a name="ddb-en-client-use-compare-cs1"></a>

```
DependencyFactory.dynamoDbClient().createTable(builder -> builder
        .tableName(TABLE_NAME)
        .attributeDefinitions(
                b -> b.attributeName("id").attributeType(ScalarAttributeType.N),
                b -> b.attributeName("title").attributeType(ScalarAttributeType.S),
                b -> b.attributeName("isbn").attributeType(ScalarAttributeType.S)
        )
        .keySchema(
                builder1 -> builder1.attributeName("id").keyType(KeyType.HASH),
                builder2 -> builder2.attributeName("title").keyType(KeyType.RANGE)
        )
        .globalSecondaryIndexes(builder3 -> builder3
                        .indexName("products_by_isbn")
                        .keySchema(builder2 -> builder2
                                .attributeName("isbn").keyType(KeyType.HASH))
                        .projection(builder2 -> builder2
                                .projectionType(ProjectionType.INCLUDE)
                                .nonKeyAttributes("price", "authors"))
                        .provisionedThroughput(builder4 -> builder4
                                .writeCapacityUnits(5L).readCapacityUnits(5L))
        )
        .provisionedThroughput(builder1 -> builder1
                .readCapacityUnits(5L).writeCapacityUnits(5L))
);
```

### 比較: DynamoDB Enhanced Client を使用したテーブルの作成
<a name="ddb-en-client-use-compare-cs2"></a>

```
DynamoDbEnhancedClient enhancedClient = DependencyFactory.enhancedClient();
productCatalog = enhancedClient.table(TABLE_NAME, TableSchema.fromImmutableClass(ProductCatalog.class));
productCatalog.createTable(b -> b
        .provisionedThroughput(b1 -> b1.readCapacityUnits(5L).writeCapacityUnits(5L))
        .globalSecondaryIndices(b2 -> b2.indexName("products_by_isbn")
                .projection(b4 -> b4
                        .projectionType(ProjectionType.INCLUDE)
                        .nonKeyAttributes("price", "authors"))
                .provisionedThroughput(b3 -> b3.writeCapacityUnits(5L).readCapacityUnits(5L))
        )
);
```

拡張クライアントは、以下の注釈付きデータクラスを使用します。DynamoDB Enhanced Client は、Java データ型を DynamoDB データ型にマッピングして、より簡潔でわかりやすいコードにします。`ProductCatalog` は、DynamoDB Enhanced Client で不変クラスを使用する例です。マッピングされたデータクラスでの不変クラスの使用については、このトピックの[後半で説明します](ddb-en-client-use-immut.md)。

### `ProductCatalog` クラス
<a name="ddb-en-client-use-compare-cs3"></a>

```
package org.example.tests.model;

import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbIgnore;
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbImmutable;
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbPartitionKey;
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbSecondaryPartitionKey;
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbSortKey;

import java.math.BigDecimal;
import java.util.Objects;
import java.util.Set;

@DynamoDbImmutable(builder = ProductCatalog.Builder.class)
public class ProductCatalog implements Comparable<ProductCatalog> {
    private Integer id;
    private String title;
    private String isbn;
    private Set<String> authors;
    private BigDecimal price;


    private ProductCatalog(Builder builder){
        this.authors = builder.authors;
        this.id = builder.id;
        this.isbn = builder.isbn;
        this.price = builder.price;
        this.title = builder.title;
    }

    public static Builder builder(){ return new Builder(); }

    @DynamoDbPartitionKey
    public Integer id() { return id; }
    
    @DynamoDbSortKey
    public String title() { return title; }
    
    @DynamoDbSecondaryPartitionKey(indexNames = "products_by_isbn")
    public String isbn() { return isbn; }
    public Set<String> authors() { return authors; }
    public BigDecimal price() { return price; }


    public static final class Builder {
      private Integer id;
      private String title;
      private String isbn;
      private Set<String> authors;
      private BigDecimal price;
      private Builder(){}

      public Builder id(Integer id) { this.id = id; return this; }
      public Builder title(String title) { this.title = title; return this; }
      public Builder isbn(String ISBN) { this.isbn = ISBN; return this; }
      public Builder authors(Set<String> authors) { this.authors = authors; return this; }
      public Builder price(BigDecimal price) { this.price = price; return this; }
      public ProductCatalog build() { return new ProductCatalog(this); }
  }

    @Override
    public String toString() {
        final StringBuffer sb = new StringBuffer("ProductCatalog{");
        sb.append("id=").append(id);
        sb.append(", title='").append(title).append('\'');
        sb.append(", isbn='").append(isbn).append('\'');
        sb.append(", authors=").append(authors);
        sb.append(", price=").append(price);
        sb.append('}');
        return sb.toString();
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        ProductCatalog that = (ProductCatalog) o;
        return id.equals(that.id) && title.equals(that.title) && Objects.equals(isbn, that.isbn) && Objects.equals(authors, that.authors) && Objects.equals(price, that.price);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id, title, isbn, authors, price);
    }

    @Override
    @DynamoDbIgnore
    public int compareTo(ProductCatalog other) {
        if (this.id.compareTo(other.id) != 0){
            return this.id.compareTo(other.id);
        } else {
            return this.title.compareTo(other.title);
        }
    }
}
```

次の 2 つのバッチ文字起こしのコード例は、拡張クライアントではなく標準クライアントを使用する場合の冗長性とタイプの安全性の欠如を示しています。

### 比較: 標準の DynamoDB クライアントを使ったバッチ書き込み
<a name="ddb-en-client-use-compare-cs4"></a>

```
    public static void batchWriteStandard(DynamoDbClient dynamoDbClient, String tableName) {

        Map<String, AttributeValue> catalogItem = Map.of(
                "authors", AttributeValue.builder().ss("a", "b").build(),
                "id", AttributeValue.builder().n("1").build(),
                "isbn", AttributeValue.builder().s("1-565-85698").build(),
                "title", AttributeValue.builder().s("Title 1").build(),
                "price", AttributeValue.builder().n("52.13").build());

        Map<String, AttributeValue> catalogItem2 = Map.of(
                "authors", AttributeValue.builder().ss("a", "b", "c").build(),
                "id", AttributeValue.builder().n("2").build(),
                "isbn", AttributeValue.builder().s("1-208-98073").build(),
                "title", AttributeValue.builder().s("Title 2").build(),
                "price", AttributeValue.builder().n("21.99").build());

        Map<String, AttributeValue> catalogItem3 = Map.of(
                "authors", AttributeValue.builder().ss("g", "k", "c").build(),
                "id", AttributeValue.builder().n("3").build(),
                "isbn", AttributeValue.builder().s("7-236-98618").build(),
                "title", AttributeValue.builder().s("Title 3").build(),
                "price", AttributeValue.builder().n("42.00").build());

        Set<WriteRequest> writeRequests = Set.of(
                WriteRequest.builder().putRequest(b -> b.item(catalogItem)).build(),
                WriteRequest.builder().putRequest(b -> b.item(catalogItem2)).build(),
                WriteRequest.builder().putRequest(b -> b.item(catalogItem3)).build());

        Map<String, Set<WriteRequest>> productCatalogItems = Map.of(
                "ProductCatalog", writeRequests);

        BatchWriteItemResponse response = dynamoDbClient.batchWriteItem(b -> b.requestItems(productCatalogItems));

        logger.info("Unprocessed items: " + response.unprocessedItems().size());
    }
```

### 比較: DynamoDB Enhanced Client を使ったバッチ書き込み
<a name="ddb-en-client-use-compare-cs5"></a>

```
    public static void batchWriteEnhanced(DynamoDbTable<ProductCatalog> productCatalog) {
        ProductCatalog prod = ProductCatalog.builder()
                .id(1)
                .isbn("1-565-85698")
                .authors(new HashSet<>(Arrays.asList("a", "b")))
                .price(BigDecimal.valueOf(52.13))
                .title("Title 1")
                .build();
        ProductCatalog prod2 = ProductCatalog.builder()
                .id(2)
                .isbn("1-208-98073")
                .authors(new HashSet<>(Arrays.asList("a", "b", "c")))
                .price(BigDecimal.valueOf(21.99))
                .title("Title 2")
                .build();
        ProductCatalog prod3 = ProductCatalog.builder()
                .id(3)
                .isbn("7-236-98618")
                .authors(new HashSet<>(Arrays.asList("g", "k", "c")))
                .price(BigDecimal.valueOf(42.00))
                .title("Title 3")
                .build();

        BatchWriteResult batchWriteResult = DependencyFactory.enhancedClient()
                .batchWriteItem(b -> b.writeBatches(
                        WriteBatch.builder(ProductCatalog.class)
                                .mappedTableResource(productCatalog)
                                .addPutItem(prod).addPutItem(prod2).addPutItem(prod3)
                                .build()
                ));
        logger.info("Unprocessed items: " + batchWriteResult.unprocessedPutItemsForTable(productCatalog).size());
    }
```

# 不変データクラスでの操作
<a name="ddb-en-client-use-immut"></a>

DynamoDB Enhanced Client API のマッピング機能は、不変データクラスで動作します。不変クラスにはゲッターしかなく、SDK がクラスのインスタンスを作成するために使用するビルダークラスが必要です。不変クラスは、[カスタマークラス](ddb-en-client-gs-tableschema.md#ddb-en-client-gs-tableschema-anno-bean-cust)に示されている `@DynamoDbBean` 注釈を使用する代わりに、使用するビルダークラスを示すパラメータを受け取る `@DynamoDbImmutable` 注釈を使用します。

次のクラスは `Customer` の不変バージョンです。

```
package org.example.tests.model.immutable;

import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbImmutable;
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbPartitionKey;
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbSecondaryPartitionKey;
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbSecondarySortKey;
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbSortKey;

import java.time.Instant;

@DynamoDbImmutable(builder = CustomerImmutable.Builder.class)
public class CustomerImmutable {
    private final String id;
    private final String name;
    private final String email;
    private final Instant regDate;

    private CustomerImmutable(Builder b) {
        this.id = b.id;
        this.email = b.email;
        this.name = b.name;
        this.regDate = b.regDate;
    }

    // This method will be automatically discovered and used by the TableSchema.
    public static Builder builder() { return new Builder(); }

    @DynamoDbPartitionKey
    public String id() { return this.id; }

    @DynamoDbSortKey
    public String email() { return this.email; }

    @DynamoDbSecondaryPartitionKey(indexNames = "customers_by_name")
    public String name() { return this.name; }

    @DynamoDbSecondarySortKey(indexNames = {"customers_by_date", "customers_by_name"})
    public Instant regDate() { return this.regDate; }

    public static final class Builder {
        private String id;
        private String email;
        private String name;
        private Instant regDate;

        // The private Builder constructor is visible to the enclosing CustomerImmutable class.
        private Builder() {}

        public Builder id(String id) { this.id = id; return this; }
        public Builder email(String email) { this.email = email; return this; }
        public Builder name(String name) { this.name = name; return this; }
        public Builder regDate(Instant regDate) { this.regDate = regDate; return this; }

        // This method will be automatically discovered and used by the TableSchema.
        public CustomerImmutable build() { return new CustomerImmutable(this); }
    }
}
```

データクラスに `@DynamoDbImmutable` 注釈を付けるには、次の要件を満たす必要があります。

1. `Object.class` のオーバーライドされておらず、`@DynamoDbIgnore` 注釈も付いていないすべてのメソッドは、DynamoDB テーブルの属性のゲッターでなければなりません。

1. すべてのゲッターには、ビルダークラスに対応する大文字と小文字を区別するセッターが必要です。

1. 次のコンストラクト条件のうち 1 つだけ満たす必要があります。
   + ビルダークラスにはパブリックデフォルトコンストラクタが必要です。
   + データクラスには、パラメータを取らずにビルダークラスのインスタンスを返す、`builder()` という名前のパブリック静的メソッドが必要です。このオプションは不変 `Customer` クラスに表示されます。

1.  ビルダークラスには、パラメータを取らずに不変クラスのインスタンスを返す、`build()` という名前のパブリックメソッドが必要です。

不変クラスの `TableSchema` を作成するには、次のスニペットに示すように `TableSchema` の `fromImmutableClass()` メソッドを使用します。

```
static final TableSchema<CustomerImmutable> customerImmutableTableSchema = 
                         TableSchema.fromImmutableClass(CustomerImmutable.class);
```

不変クラスから DynamoDB テーブルを作成できるのと同様に、次のスニペットの例に示すように、`DynamoDbTable` の `createTable()` を *1 回*呼び出すだけで不変クラスからテーブルを作成できます。

```
static void createTableFromImmutable(DynamoDbEnhancedClient enhancedClient, String tableName, DynamoDbWaiter waiter){
    // First, create an in-memory representation of the table using the 'table()' method of the DynamoDb Enhanced Client.
    // 'table()' accepts a name for the table and a TableSchema instance that you created previously.
    DynamoDbTable<CustomerImmutable> customerDynamoDbTable = enhancedClient
            .table(tableName, TableSchema.fromImmutableClass(CustomerImmutable.class));
        
    // Second, call the 'createTable()' method on the DynamoDbTable instance.
    customerDynamoDbTable.createTable();
    waiter.waitUntilTableExists(b -> b.tableName(tableName));
}
```

## Lombok などのサードパーティライブラリを使用します。
<a name="ddb-en-client-use-immut-lombok"></a>

[Project Lombok](https://projectlombok.org/) などのサードパーティライブラリは、不変オブジェクトに関連するボイラープレートコードを生成するのに役立ちます。DynamoDB Enhanced Client API は、データクラスがこのセクションで説明する規則に従っている限り、これらのライブラリで動作します。

次の例は、Lombok 注釈付きの不変 `CustomerImmutable` クラスを示しています。Lombok の `onMethod` 機能が、`@DynamoDbPartitionKey` のような属性ベースの DynamoDB 注釈を生成されたコードにコピーすることに注意してください。

```
@Value
@Builder
@DynamoDbImmutable(builder = Customer.CustomerBuilder.class)
public class Customer {
    @Getter(onMethod_=@DynamoDbPartitionKey)
    private String id;

    @Getter(onMethod_=@DynamoDbSortKey)
    private String email;

    @Getter(onMethod_=@DynamoDbSecondaryPartitionKey(indexNames = "customers_by_name"))
    private String name;

    @Getter(onMethod_=@DynamoDbSecondarySortKey(indexNames = {"customers_by_date", "customers_by_name"}))
    private Instant createdDate;
}
```

# 式と条件を使用する
<a name="ddb-en-client-expressions"></a>

DynamoDB Enhanced Client API の式は、[DynamoDB 式](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.html)の Java の表現です。

DynamoDB Enhanced Client API では、次の 3 種類の式を使用します。

[Expression](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/Expression.html)  
`Expression` クラスは、条件とフィルタを定義するときに使用されます。

[https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/QueryConditional.html](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/QueryConditional.html)  
このタイプの式は、クエリオペレーションの[キー条件](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Query.html#Query.KeyConditionExpressions)を表します。

[https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/update/UpdateExpression.html](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/update/UpdateExpression.html)  
このクラスは DynamoDB [更新式](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.UpdateExpressions.html)の記述に役立ち、現在、拡張フレームワークでアイテムを更新する際に使用されています。

## 式の構造分析
<a name="ddb-en-client-expressions-compoonents"></a>

式は以下のような構成になっています。
+ 文字列式 (必須)。文字列には、属性名と属性値のプレースホルダー名を含む DynamoDB 論理式が含まれています。
+ 式値のマップ (通常は必須)。
+ 式名のマップ (オプション)。

ビルダーを使用して、次のような一般的な形式の `Expression` オブジェクトを生成します。

```
Expression expression = Expression.builder()
                            .expression(<String>)
                            .expressionNames(<Map>)
                            .expressionValues(<Map>)
                           .build()
```

`Expression` は通常、式値のマップを必要とします。マップは文字列式のプレースホルダーの値を提供します。マップキーはコロン (`:`) が付いたプレースホルダー名で構成され、マップ値は [AttributeValue](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/model/AttributeValue.html) のインスタンスです。[AttributeValues](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/internal/AttributeValues.html) クラスには、リテラルから `AttributeValue` インスタンスを生成する便利なメソッドがあります。または、`AttributeValue.Builder` を使用して `AttributeValue` インスタンスを生成することもできます。

次のスニペットは、コメント行 2 の後に 2 つのエントリがあるマップを示しています。コメント行 1 の後に表示される `expression()` メソッドに渡される文字列には、DynamoDB が操作を実行する前に DynamoDB が解決するプレースホルダーが含まれています。*price* は許容される属性名であるため、このスニペットには式名のマップは含まれていません。

```
    public static void scanAsync(DynamoDbAsyncTable productCatalog) {
        ScanEnhancedRequest request = ScanEnhancedRequest.builder()
                .consistentRead(true)
                .attributesToProject("id", "title", "authors", "price")
                .filterExpression(Expression.builder()
                        // 1. :min_value and :max_value are placeholders for the values provided by the map
                        .expression("price >= :min_value AND price <= :max_value")
                        // 2. Two values are needed for the expression and each is supplied as a map entry.
                        .expressionValues(
                                Map.of( ":min_value", numberValue(8.00),
                                        ":max_value", numberValue(400_000.00)))
                        .build())
                .build();
```

DynamoDB テーブル内の属性名が予約語か、数値で始まるか、またはスペースを含む場合、`Expression` には式名のマップが必要です。

たとえば、属性名が前のコード例で `price` ではなく `1price` だった場合は、次の例のように変更する必要があります。

```
        ScanEnhancedRequest request = ScanEnhancedRequest.builder()
                .filterExpression(Expression.builder()
                        .expression("#price >= :min_value AND #price <= :max_value")
                        .expressionNames( Map.of("#price", "1price") )
                        .expressionValues(
                                Map.of(":min_value", numberValue(8.00),
                                        ":max_value", numberValue(400_000.00)))
                        .build())
                .build();
```

式名のプレースホルダーはポンド記号 (`#`) で始まります。式名のマップのエントリでは、プレースホルダーをキー、属性名を値として使用します。マップは `expressionNames()` メソッドで式ビルダーに追加されます。DynamoDB は操作を実行する前に属性名を解決します。

文字列式で関数を使用する場合、式の値は不要です。式関数の例は `attribute_exists(<attribute_name>)` です。

次の例では、[DynamoDB 関数](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.OperatorsAndFunctions.html#Expressions.OperatorsAndFunctions.Functions)を使用する `Expression` を構築します。この例の式文字列はプレースホルダーを使用していません。この式を `putItem` オペレーションに使用すると、`movie` 属性値がデータオブジェクトの `movie` 属性と等しいアイテムがデータベースにすでに存在するかどうかを確認できます。

```
Expression exp = Expression.builder().expression("attribute_not_exists (movie)").build();
```

DynamoDB デベロッパーガイドには、DynamoDB で使用される[低レベルの式](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.html)に関する完全な情報が記載されています。

## 条件式と条件
<a name="ddb-en-client-expressions-cond"></a>

`putItem()`、`updateItem()`、`deleteItem()` メソッドを使用する場合、トランザクションオペレーションやバッチオペレーションを使用する場合は、`[Expression](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/Expression.html)` オブジェクトを使用して、DynamoDB が操作を続行するために満たすべき条件を指定します。これらの式は条件式と呼ばれています。例については、このガイドの[トランザクション例](ddb-en-client-use-multiop-trans.md#ddb-en-client-use-multiop-trans-writeitems-opcondition)の `addDeleteItem()` メソッド (コメント行 1 の後) で使われている条件式を参照してください。

`query()` メソッドを操作する場合、条件は [https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/QueryConditional.html](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/QueryConditional.html) として表されます。`QueryConditional` クラスには、DynamoDB から読み取るアイテムを決定する基準を記述するのに役立つ静的で便利なメソッドがいくつかあります。

`QueryConditionals` の例については、このガイドの [`Query` メソッドの例](ddb-en-client-use-multirecord.md#ddb-en-client-use-multirecord-query-example) セクションの最初のコード例を参照してください。

## フィルタ式
<a name="ddb-en-client-expressions-filter"></a>

フィルタ式は、スキャンやクエリオペレーションで、返されるアイテムをフィルターするために使用されます。

フィルタ式はデータベースからすべてのデータが読み取られた後に適用されるため、読み取りコストはフィルターがない場合と同じになります。*Amazon DynamoDB デベロッパーガイド*には、[クエリ](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Query.html#Query.FilterExpression)オペレーションと[スキャン](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Scan.html#Scan.FilterExpression)オペレーションの両方にフィルター式を使用する方法の詳細が記載されています。

次の例は、スキャンリクエストに追加されたフィルタ式を示しています。この条件では、返品されるアイテムは、価格が 8.00 から 80.00 までの価格に限定されます。

```
        Map<String, AttributeValue> expressionValues = Map.of(
                ":min_value", numberValue(8.00),
                ":max_value", numberValue(80.00));

        ScanEnhancedRequest request = ScanEnhancedRequest.builder()
                .consistentRead(true)
                // 1. the 'attributesToProject()' method allows you to specify which values you want returned.
                .attributesToProject("id", "title", "authors", "price")
                // 2. Filter expression limits the items returned that match the provided criteria.
                .filterExpression(Expression.builder()
                        .expression("price >= :min_value AND price <= :max_value")
                        .expressionValues(expressionValues)
                        .build())
                .build();
```

## 更新式
<a name="ddb-en-client-expressions-update"></a>

DynamoDB Enhanced Client の `updateItem()` メソッドは、DynamoDB 内のアイテムを更新する標準的な方法を提供します。ただし、より多くの機能が必要な場合は、[UpdateExpressions](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/update/UpdateExpression.html) によって DynamoDB [更新式の構文](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.UpdateExpressions.html)をタイプセーフに表現します。たとえば、`UpdateExpressions` を使用して、最初に DynamoDB からアイテムを読み取らずに値を増やしたり、リストに個々のメンバーを追加したりできます。現在、更新式は `updateItem()` メソッドのカスタム拡張で使用できます。

更新式の使用例については、このガイドの[カスタム拡張の例](ddb-en-client-extensions-custom.md)を参照してください。

更新式の詳細については、「[Amazon DynamoDB デベロッパーガイド](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.UpdateExpressions.html)」を参照してください。

# ページ分割された結果を処理する: スキャンとクエリ
<a name="ddb-en-client-use-multirecord"></a>

DynamoDB Enhanced Client API の`scan`、`query`、および `batch` メソッドは、1 つ以上の*ページ*を含むレスポンスを返します。ページには、1 つ以上のアイテムが含まれます。コードはページごとにレスポンスを処理することも、個々のアイテムを処理することもできます。

同期 `DynamoDbEnhancedClient` クライアントから返されるページ分割されたレスポンスは [PageIterable](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/PageIterable.html) オブジェクトを返し、非同期 `DynamoDbEnhancedAsyncClient` から返されるレスポンスは [PagePublisher](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/PagePublisher.html) オブジェクトを返します。

このセクションでは、ページ分割された結果の処理について説明し、スキャン API とクエリ API を使用する例を紹介します。

## テーブルのスキャン
<a name="ddb-en-client-use-multirecord-scan"></a>

SDK [https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/DynamoDbAsyncTable.html#scan(java.util.function.Consumer)](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/DynamoDbAsyncTable.html#scan(java.util.function.Consumer)) のメソッドは、同じ名前の [DynamoDB オペレーション](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_Scan.html)に対応しています。DynamoDB Enhanced Client API にも同じオプションがありますが、使い慣れたオブジェクトモデルを使用してページ分割を処理します。

まず、同期マッピングクラス [DynamoDbTable](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/DynamoDbTable.html) の `scan` メソッドを見て、`PageIterable` インターフェイスを調べます。

### 同期 API を使用する
<a name="ddb-en-client-use-multirecord-scan-sync"></a>

次の例は、[式](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/Expression.html)を使用して返されるアイテムをフィルタリングする `scan` メソッドを示しています。[ProductCatalog](ddb-en-client-use.md#ddb-en-client-use-compare-cs3) は、前に示したモデルオブジェクトです。

コメント行 2 の後に表示されるフィルタリング式は、返される`ProductCatalog`項目を 8.00～80.00 の料金値を持つ項目に制限します。

この例では、コメント行 1 の後に示されている `attributesToProject`メソッドを使用して`isbn`値を除外します。

コメント行 3 の後、`scan` メソッドによって `PageIterable` オブジェクトの `pagedResults` が返されます。`PageIterable` の `stream` メソッドは、ページの処理に使用できる [https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html](https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html) オブジェクトを返します。この例では、ページ数がカウントされ、ログに記録されます。

コメント行 4 から始まる例では、`ProductCatalog` アイテムへのアクセス方法が 2 種類示されています。コメント行 4a 以降のバージョンは、各ページをストリーミングし、各ページの項目をソートしてログに記録します。コメント行 4b 以降のバージョンは、ページの反復をスキップし、項目に直接アクセスします。

`PageIterable` インターフェースには、[https://docs.oracle.com/javase/8/docs/api/java/lang/Iterable.html](https://docs.oracle.com/javase/8/docs/api/java/lang/Iterable.html) と [https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/core/pagination/sync/SdkIterable.html](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/core/pagination/sync/SdkIterable.html) という 2 つの親インターフェースがあるため、結果を処理する方法が複数あります。`Iterable` は `forEach`、`iterator`、`spliterator` メソッドを、`SdkIterable` は `stream` メソッドを提供します。

```
    public static void scanSync(DynamoDbTable<ProductCatalog> productCatalog) {

        Map<String, AttributeValue> expressionValues = Map.of(
                ":min_value", numberValue(8.00),
                ":max_value", numberValue(80.00));

        ScanEnhancedRequest request = ScanEnhancedRequest.builder()
                .consistentRead(true)
                // 1. the 'attributesToProject()' method allows you to specify which values you want returned.
                .attributesToProject("id", "title", "authors", "price")
                // 2. Filter expression limits the items returned that match the provided criteria.
                .filterExpression(Expression.builder()
                        .expression("price >= :min_value AND price <= :max_value")
                        .expressionValues(expressionValues)
                        .build())
                .build();

        // 3. A PageIterable object is returned by the scan method.
        PageIterable<ProductCatalog> pagedResults = productCatalog.scan(request);
        logger.info("page count: {}", pagedResults.stream().count());

        // 4. Log the returned ProductCatalog items using two variations.
        // 4a. This version sorts and logs the items of each page.
        pagedResults.stream().forEach(p -> p.items().stream()
                .sorted(Comparator.comparing(ProductCatalog::price))
                .forEach(
                        item -> logger.info(item.toString())
                ));
        // 4b. This version sorts and logs all items for all pages.
        pagedResults.items().stream()
                .sorted(Comparator.comparing(ProductCatalog::price))
                .forEach(
                        item -> logger.info(item.toString())
                );
    }
```

### 非同期 API を使用する
<a name="ddb-en-client-use-multirecord-scan-async"></a>

非同期 `scan` メソッドは結果を `PagePublisher` オブジェクトとして返します。`PagePublisher` インターフェースには、レスポンスページの処理に使用できる `subscribe` メソッドが 2 つあります。`subscribe` メソッドの一つは、`org.reactivestreams.Publisher` 親インターフェースからのものです。この最初のオプションを使用してページを処理するには、`subscribe` メソッドに `[Subscriber](https://www.reactive-streams.org/reactive-streams-1.0.0-javadoc/org/reactivestreams/Subscriber.html)` インスタンスを渡します。次の最初の例は、`subscribe` メソッドの使用例を示しています。

2 つ目の `subscribe` メソッドは、[SdkPublisher](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/core/async/SdkPublisher.html) インターフェイスからのものです。このバージョンの `subscribe` は、`Subscriber` ではなく [https://docs.oracle.com/javase/8/docs/api/java/util/function/Consumer.html](https://docs.oracle.com/javase/8/docs/api/java/util/function/Consumer.html) を受け入れます。この `subscribe` メソッドのバリエーションは、次の 2 番目の例に示されています。

次の例は、前の例で示されたのと同じフィルタ式を使用する非同期バージョンの `scan` メソッドです。

コメント行 3 の後、`DynamoDbAsyncTable.scan` は `PagePublisher` オブジェクトを返します。次の行では、コードによって `org.reactivestreams.Subscriber` インターフェース、`ProductCatalogSubscriber` のインスタンスが作成され、コメント行 4 の後に `PagePublisher` がサブスクライブされます。

`Subscriber` オブジェクトは、`ProductCatalogSubscriber` クラスの例のコメント行 8 の後に、`onNext` メソッドの各ページから `ProductCatalog` アイテムを収集します。アイテムはプライベート変数 `List` に保存され、`ProductCatalogSubscriber.getSubscribedItems()` メソッドを使用して呼び出し元のコードからアクセスされます。これはコメント行 5 の後に呼び出されます。

リストが取得されると、コードはすべての `ProductCatalog` アイテムを価格順に並べ替え、各アイテムをログに記録します。

`ProductCatalogSubscriber` クラスの [CountDownLatch](https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/CountDownLatch.html) は、コメント行 5 以降を継続する前に、すべてのアイテムがリストに追加されるまで、呼び出し元のスレッドをブロックします。

```
    public static void scanAsync(DynamoDbAsyncTable productCatalog) {
        ScanEnhancedRequest request = ScanEnhancedRequest.builder()
                .consistentRead(true)
                .attributesToProject("id", "title", "authors", "price")
                .filterExpression(Expression.builder()
                        // 1. :min_value and :max_value are placeholders for the values provided by the map
                        .expression("price >= :min_value AND price <= :max_value")
                        // 2. Two values are needed for the expression and each is supplied as a map entry.
                        .expressionValues(
                                Map.of( ":min_value", numberValue(8.00),
                                        ":max_value", numberValue(400_000.00)))
                        .build())
                .build();

        // 3. A PagePublisher object is returned by the scan method.
        PagePublisher<ProductCatalog> pagePublisher = productCatalog.scan(request);
        ProductCatalogSubscriber subscriber = new ProductCatalogSubscriber();
        // 4. Subscribe the ProductCatalogSubscriber to the PagePublisher.
        pagePublisher.subscribe(subscriber);
        // 5. Retrieve all collected ProductCatalog items accumulated by the subscriber.
        subscriber.getSubscribedItems().stream()
                .sorted(Comparator.comparing(ProductCatalog::price))
                .forEach(item ->
                        logger.info(item.toString()));
        // 6. Use a Consumer to work through each page.
        pagePublisher.subscribe(page -> page
                        .items().stream()
                        .sorted(Comparator.comparing(ProductCatalog::price))
                        .forEach(item ->
                                logger.info(item.toString())))
                .join(); // If needed, blocks the subscribe() method thread until it is finished processing.
        // 7. Use a Consumer to work through each ProductCatalog item.
        pagePublisher.items()
                .subscribe(product -> logger.info(product.toString()))
                .exceptionally(failure -> {
                    logger.error("ERROR  - ", failure);
                    return null;
                })
                .join(); // If needed, blocks the subscribe() method thread until it is finished processing.
    }
```

```
    private static class ProductCatalogSubscriber implements Subscriber<Page<ProductCatalog>> {
        private CountDownLatch latch = new CountDownLatch(1);
        private Subscription subscription;
        private List<ProductCatalog> itemsFromAllPages = new ArrayList<>();

        @Override
        public void onSubscribe(Subscription sub) {
            subscription = sub;
            subscription.request(1L);
            try {
                latch.await(); // Called by main thread blocking it until latch is released.
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }

        @Override
        public void onNext(Page<ProductCatalog> productCatalogPage) {
            // 8. Collect all the ProductCatalog instances in the page, then ask the publisher for one more page.
            itemsFromAllPages.addAll(productCatalogPage.items());
            subscription.request(1L);
        }

        @Override
        public void onError(Throwable throwable) {
        }

        @Override
        public void onComplete() {
            latch.countDown(); // Call by subscription thread; latch releases.
        }

        List<ProductCatalog> getSubscribedItems() {
            return this.itemsFromAllPages;
        }
    }
```

次のスニペット例では、コメント行 6 以降に `Consumer` を受け入れる `PagePublisher.subscribe` メソッドのバージョンを使用しています。Java ラムダパラメータはページを消費し、各アイテムをさらに処理します。この例では、各ページが処理され、各ページのアイテムがソートされてからログに記録されます。

```
        // 6. Use a Consumer to work through each page.
        pagePublisher.subscribe(page -> page
                        .items().stream()
                        .sorted(Comparator.comparing(ProductCatalog::price))
                        .forEach(item ->
                                logger.info(item.toString())))
                .join(); // If needed, blocks the subscribe() method thread until it is finished processing.
```

`PagePublisher` の `items` メソッドはモデルインスタンスをアンラップして、コードでアイテムを直接処理できるようにします。このアプローチは次のスニペットに示されています。

```
        // 7. Use a Consumer to work through each ProductCatalog item.
        pagePublisher.items()
                .subscribe(product -> logger.info(product.toString()))
                .exceptionally(failure -> {
                    logger.error("ERROR  - ", failure);
                    return null;
                })
                .join(); // If needed, blocks the subscribe() method thread until it is finished processing.
```

## テーブルに対してクエリを実行する
<a name="ddb-en-client-use-multirecord-query"></a>

DynamoDB 拡張クライアントを使用してテーブルをクエリし、特定の条件に一致する複数の項目を取得できます。[https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/DynamoDbTable.html#query(software.amazon.awssdk.enhanced.dynamodb.model.QueryEnhancedRequest)](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/DynamoDbTable.html#query(software.amazon.awssdk.enhanced.dynamodb.model.QueryEnhancedRequest)) メソッドは、 データクラスで定義された `@DynamoDbPartitionKey` とオプションの `@DynamoDbSortKey` 注釈を使用して、プライマリキー値に基づいて項目を検索します。

`query()` メソッドにはパーティションキー値が必要で、オプションでソートキー条件を使用して結果をさらに絞り込むことができます。`scan` API と同様に、クエリは同期呼び出しの場合は `PageIterable` を返し、非同期呼び出しの場合は `PagePublisher` を返します。

### `Query` メソッドの例
<a name="ddb-en-client-use-multirecord-query-example"></a>

以下の `query()` メソッドコード例では `MovieActor` クラスを使用しています。データクラスは、パーティションキーとしての **`movie`** 属性と、ソートキーとしての **`actor`** 属性で構成される複合プライマリキーを定義します。

#### `MovieActor` クラス
<a name="ddb-en-client-use-movieactor-class"></a>

```
package org.example.tests.model;

import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbAttribute;
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbBean;
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbPartitionKey;
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbSecondaryPartitionKey;
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbSecondarySortKey;
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbSortKey;

import java.util.Objects;

@DynamoDbBean
public class MovieActor implements Comparable<MovieActor> {

    private String movieName;
    private String actorName;
    private String actingAward;
    private Integer actingYear;
    private String actingSchoolName;

    @DynamoDbPartitionKey
    @DynamoDbAttribute("movie")
    public String getMovieName() {
        return movieName;
    }

    public void setMovieName(String movieName) {
        this.movieName = movieName;
    }

    @DynamoDbSortKey
    @DynamoDbAttribute("actor")
    public String getActorName() {
        return actorName;
    }

    public void setActorName(String actorName) {
        this.actorName = actorName;
    }

    @DynamoDbSecondaryPartitionKey(indexNames = "acting_award_year")
    @DynamoDbAttribute("actingaward")
    public String getActingAward() {
        return actingAward;
    }

    public void setActingAward(String actingAward) {
        this.actingAward = actingAward;
    }

    @DynamoDbSecondarySortKey(indexNames = {"acting_award_year", "movie_year"})
    @DynamoDbAttribute("actingyear")
    public Integer getActingYear() {
        return actingYear;
    }

    public void setActingYear(Integer actingYear) {
        this.actingYear = actingYear;
    }

    @DynamoDbAttribute("actingschoolname")
    public String getActingSchoolName() {
        return actingSchoolName;
    }

    public void setActingSchoolName(String actingSchoolName) {
        this.actingSchoolName = actingSchoolName;
    }

    @Override
    public String toString() {
        final StringBuffer sb = new StringBuffer("MovieActor{");
        sb.append("movieName='").append(movieName).append('\'');
        sb.append(", actorName='").append(actorName).append('\'');
        sb.append(", actingAward='").append(actingAward).append('\'');
        sb.append(", actingYear=").append(actingYear);
        sb.append(", actingSchoolName='").append(actingSchoolName).append('\'');
        sb.append('}');
        return sb.toString();
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        MovieActor that = (MovieActor) o;
        return Objects.equals(movieName, that.movieName) && Objects.equals(actorName, that.actorName) && Objects.equals(actingAward, that.actingAward) && Objects.equals(actingYear, that.actingYear) && Objects.equals(actingSchoolName, that.actingSchoolName);
    }

    @Override
    public int hashCode() {
        return Objects.hash(movieName, actorName, actingAward, actingYear, actingSchoolName);
    }

    @Override
    public int compareTo(MovieActor o) {
        if (this.movieName.compareTo(o.movieName) != 0){
            return this.movieName.compareTo(o.movieName);
        } else {
            return this.actorName.compareTo(o.actorName);
        }
    }
}
```

以下のコード例では、以下の項目に対してクエリを実行します。

#### `MovieActor` テーブル内の項目
<a name="ddb-en-client-use-movieactor-items"></a>

```
MovieActor{movieName='movie01', actorName='actor0', actingAward='actingaward0', actingYear=2001, actingSchoolName='null'}
MovieActor{movieName='movie01', actorName='actor1', actingAward='actingaward1', actingYear=2001, actingSchoolName='actingschool1'}
MovieActor{movieName='movie01', actorName='actor2', actingAward='actingaward2', actingYear=2001, actingSchoolName='actingschool2'}
MovieActor{movieName='movie01', actorName='actor3', actingAward='actingaward3', actingYear=2001, actingSchoolName='null'}
MovieActor{movieName='movie01', actorName='actor4', actingAward='actingaward4', actingYear=2001, actingSchoolName='actingschool4'}
MovieActor{movieName='movie02', actorName='actor0', actingAward='actingaward0', actingYear=2002, actingSchoolName='null'}
MovieActor{movieName='movie02', actorName='actor1', actingAward='actingaward1', actingYear=2002, actingSchoolName='actingschool1'}
MovieActor{movieName='movie02', actorName='actor2', actingAward='actingaward2', actingYear=2002, actingSchoolName='actingschool2'}
MovieActor{movieName='movie02', actorName='actor3', actingAward='actingaward3', actingYear=2002, actingSchoolName='null'}
MovieActor{movieName='movie02', actorName='actor4', actingAward='actingaward4', actingYear=2002, actingSchoolName='actingschool4'}
MovieActor{movieName='movie03', actorName='actor0', actingAward='actingaward0', actingYear=2003, actingSchoolName='null'}
MovieActor{movieName='movie03', actorName='actor1', actingAward='actingaward1', actingYear=2003, actingSchoolName='actingschool1'}
MovieActor{movieName='movie03', actorName='actor2', actingAward='actingaward2', actingYear=2003, actingSchoolName='actingschool2'}
MovieActor{movieName='movie03', actorName='actor3', actingAward='actingaward3', actingYear=2003, actingSchoolName='null'}
MovieActor{movieName='movie03', actorName='actor4', actingAward='actingaward4', actingYear=2003, actingSchoolName='actingschool4'}
```

次のコードは、 `keyEqual` (コメント行 1 の後) と `sortGreaterThanOrEqualTo` (コメント行 1a の後) の 2 つの `QueryConditional` インスタンスを定義します。

#### パーティションキーで項目をクエリする
<a name="keyEqual-query-conditional-example"></a>

`keyEqual` インスタンスは、パーティションキー値が **`movie01`** の項目に一致します。

この例では、コメント行 2 の後に、**`actingschoolname`** 値がない項目を除外するフィルター式も定義しています。

`QueryEnhancedRequest` は、クエリのキー条件とフィルター式の組み合わせです。

```
    public static void query(DynamoDbTable movieActorTable) {

        // 1. Define a QueryConditional instance to return items matching a partition value.
        QueryConditional keyEqual = QueryConditional.keyEqualTo(b -> b.partitionValue("movie01"));
        // 1a. Define a QueryConditional that adds a sort key criteria to the partition value criteria.
        QueryConditional sortGreaterThanOrEqualTo = QueryConditional.sortGreaterThanOrEqualTo(b -> b.partitionValue("movie01").sortValue("actor2"));
        // 2. Define a filter expression that filters out items whose attribute value is null.
        final Expression filterOutNoActingschoolname = Expression.builder().expression("attribute_exists(actingschoolname)").build();

        // 3. Build the query request.
        QueryEnhancedRequest tableQuery = QueryEnhancedRequest.builder()
                .queryConditional(keyEqual)
                .filterExpression(filterOutNoActingschoolname)
                .build();
        // 4. Perform the query using the "keyEqual" conditional and filter expression.
        PageIterable<MovieActor> pagedResults = movieActorTable.query(tableQuery);
        logger.info("page count: {}", pagedResults.stream().count()); // Log  number of pages.

        pagedResults.items().stream()
                .sorted()
                .forEach(
                        item -> logger.info(item.toString()) // Log the sorted list of items.
                );
```

**Example – 条件付き `keyEqual` クエリを使用した出力**  
以下は、メソッドを実行したときの出力です。出力には **movie01 ** の `movieName` 値を持つ項目が表示され、**`null`**　と等しい `actingSchoolName` の項目は表示されません。  

```
2023-03-05 13:11:05 [main] INFO  org.example.tests.QueryDemo:46 - page count: 1
2023-03-05 13:11:05 [main] INFO  org.example.tests.QueryDemo:51 - MovieActor{movieName='movie01', actorName='actor1', actingAward='actingaward1', actingYear=2001, actingSchoolName='actingschool1'}
2023-03-05 13:11:05 [main] INFO  org.example.tests.QueryDemo:51 - MovieActor{movieName='movie01', actorName='actor2', actingAward='actingaward2', actingYear=2001, actingSchoolName='actingschool2'}
2023-03-05 13:11:05 [main] INFO  org.example.tests.QueryDemo:51 - MovieActor{movieName='movie01', actorName='actor4', actingAward='actingaward4', actingYear=2001, actingSchoolName='actingschool4'}
```

#### パーティションキーとソートキーで項目をクエリする
<a name="sort-type-query-conditional-example"></a>

`sortGreaterThanOrEqualTo` `QueryConditional` は、**actor2** 以上の値のソートキー条件を追加して、パーティションキーの一致 (**movie01**) を絞り込みます。

`sort` で始まる [`QueryConditional` メソッド](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/QueryConditional.html)では、ソートキー値に基づいた比較によってクエリを一致させ、さらに絞り込むためにパーティションキー値が必要です。メソッド名の `Sort` は、結果がソートされることを意味するのではなく、ソートキー値が比較に使用されることを意味します。

次のスニペットでは、コメント行 3 の後で、前に示したクエリリクエストを変更します。このスニペットは、「keyEqual」の条件付きクエリをコメント行 1a の後に定義された「sortGreaterThanOrEqualTo」の条件付きクエリに置き換えます。次のコードではフィルター式も削除されています。

```
        QueryEnhancedRequest tableQuery = QueryEnhancedRequest.builder()
                .queryConditional(sortGreaterThanOrEqualTo).build();
```

**Example – 条件付き `sortGreaterThanOrEqualTo` クエリを使用した出力**  
このクエリでは次の出力が生成されます。このクエリは、**movie01** と等しい `movieName` 値を持つアイテムを返し、**actor2** 以上の `actorName` 値のアイテムのみを返します。フィルターが削除されたため、このクエリでは `actingSchoolName` 属性に値がないアイテムが返されます。  

```
2023-03-05 13:15:00 [main] INFO  org.example.tests.QueryDemo:46 - page count: 1
2023-03-05 13:15:00 [main] INFO  org.example.tests.QueryDemo:51 - MovieActor{movieName='movie01', actorName='actor2', actingAward='actingaward2', actingYear=2001, actingSchoolName='actingschool2'}
2023-03-05 13:15:00 [main] INFO  org.example.tests.QueryDemo:51 - MovieActor{movieName='movie01', actorName='actor3', actingAward='actingaward3', actingYear=2001, actingSchoolName='null'}
2023-03-05 13:15:00 [main] INFO  org.example.tests.QueryDemo:51 - MovieActor{movieName='movie01', actorName='actor4', actingAward='actingaward4', actingYear=2001, actingSchoolName='actingschool4'}
```

# バッチオペレーションを実行する
<a name="ddb-en-client-use-multiop-batch"></a>

DynamoDB Enhanced Client API には、[`batchGetItem`()](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/DynamoDbEnhancedClient.html#batchGetItem(java.util.function.Consumer)) と [`batchWriteItem`()](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/DynamoDbEnhancedClient.html#batchWriteItem(java.util.function.Consumer)) の 2 つのバッチメソッドがあります。

## `batchGetItem()` の例
<a name="ddb-en-client-use-multiop-batch-get"></a>

[https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/DynamoDbEnhancedClient.html#batchGetItem(java.util.function.Consumer)](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/DynamoDbEnhancedClient.html#batchGetItem(java.util.function.Consumer)) メソッドを使用すると、1 回のリクエストで複数のテーブルから最大 100 個の項目を取得できます。次の例では、前に示した [`Customer`](ddb-en-client-gs-tableschema.md#ddb-en-client-gs-tableschema-anno-bean-cust) および [`MovieActor`](ddb-en-client-use-multirecord.md#ddb-en-client-use-movieactor-class) のデータクラスを使用しています。

1 行目と 2 行目の後の例では、3 行目のコメントの後に `batchGetItem()` メソッドにパラメータとして追加する `[ReadBatch](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/ReadBatch.html)` オブジェクトを作成します。

コメント行 1 の後のコードでは、`Customer` テーブルから読み取るバッチを構築します。コメント行 1a の後のコードは、プライマリキー値およびソートキー値を使用して読み取る項目を指定する `[GetItemEnhancedRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/GetItemEnhancedRequest.Builder.html)` ビルダーの使用を示しています。データクラスに複合キーがある場合は、パーティションキー値とソートキー値の両方を指定する必要があります。

キー値を指定して項目をリクエストするのとは対照的に、コメント行 1b の後に示されているように、データクラスを使用して項目をリクエストできます。SDK はリクエストを送信する前にバックグラウンドでキー値を抽出します。

2a の後の 2 つのステートメントに示されているように、キーベースのアプローチを使用して項目を指定する場合、DynamoDB が[強力な整合性のある読み込み](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.ReadConsistency.html)を実行するように指定することもできます。`consistentRead()` メソッドを使用する場合は、同じテーブルのリクエストされた項目すべてにそのメソッドを使用する必要があります。

DynamoDB が検出した項目を取得するには、コメント行 4 の後に表示される `[resultsForTable() ](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/BatchGetResultPage.html#resultsForTable(software.amazon.awssdk.enhanced.dynamodb.MappedTableResource))` メソッドを使用します。リクエストで読み取られた各テーブルのメソッドを呼び出します。`resultsForTable()` は見つかった項目の一覧を返し、どの `java.util.List` メソッドでも処理できます。この例では各項目を記録しています。

DynamoDB が処理しなかった項目を見つけるには、コメント行 5 の後の方法を使用します。`BatchGetResultPage` クラスには、未処理の各キーにアクセスできる `[unprocessedKeysForTable()](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/BatchGetResultPage.html#unprocessedKeysForTable(software.amazon.awssdk.enhanced.dynamodb.MappedTableResource))` メソッドがあります。[BatchGetItem API リファレンス](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_BatchGetItem.html)には、未処理のアイテムが発生する状況に関する詳細情報が記載されています。

```
    public static void batchGetItemExample(DynamoDbEnhancedClient enhancedClient,
                                           DynamoDbTable<Customer> customerTable,
                                           DynamoDbTable<MovieActor> movieActorTable) {

        Customer customer2 = new Customer();
        customer2.setId("2");
        customer2.setEmail("cust2@example.org");

        // 1. Build a batch to read from the Customer table.
        ReadBatch customerBatch = ReadBatch.builder(Customer.class)
                .mappedTableResource(customerTable)
                // 1a. Specify the primary key value and sort key value for the item.
                .addGetItem(b -> b.key(k -> k.partitionValue("1").sortValue("cust1@orgname.org")))
                // 1b. Alternatively, supply a data class instances to provide the primary key values.
                .addGetItem(customer2)
                .build();

        // 2. Build a batch to read from the MovieActor table.
        ReadBatch moveActorBatch = ReadBatch.builder(MovieActor.class)
                .mappedTableResource(movieActorTable)
                // 2a. Call consistentRead(Boolean.TRUE) for each item for the same table.
                .addGetItem(b -> b.key(k -> k.partitionValue("movie01").sortValue("actor1")).consistentRead(Boolean.TRUE))
                .addGetItem(b -> b.key(k -> k.partitionValue("movie01").sortValue("actor4")).consistentRead(Boolean.TRUE))
                .build();

        // 3. Add ReadBatch objects to the request.
        BatchGetResultPageIterable resultPages = enhancedClient.batchGetItem(b -> b.readBatches(customerBatch, moveActorBatch));

        // 4. Retrieve the successfully requested items from each table.
        resultPages.resultsForTable(customerTable).forEach(item -> logger.info(item.toString()));
        resultPages.resultsForTable(movieActorTable).forEach(item -> logger.info(item.toString()));

        // 5. Retrieve the keys of the items requested but not processed by the service.
        resultPages.forEach((BatchGetResultPage pageResult) -> {
            pageResult.unprocessedKeysForTable(customerTable).forEach(key -> logger.info("Unprocessed item key: " + key.toString()));
            pageResult.unprocessedKeysForTable(movieActorTable).forEach(key -> logger.info("Unprocessed item key: " + key.toString()));
        });
    }
```

サンプルコードを実行する前に、2 つのテーブルに次の項目が含まれていると仮定します。

### テーブル内の項目
<a name="ddb-en-client-use-multiop-batch-get-tableitems"></a>

```
Customer [id=1, name=CustName1, email=cust1@example.org, regDate=2023-03-31T15:46:27.688Z]
Customer [id=2, name=CustName2, email=cust2@example.org, regDate=2023-03-31T15:46:28.688Z]
Customer [id=3, name=CustName3, email=cust3@example.org, regDate=2023-03-31T15:46:29.688Z]
Customer [id=4, name=CustName4, email=cust4@example.org, regDate=2023-03-31T15:46:30.688Z]
Customer [id=5, name=CustName5, email=cust5@example.org, regDate=2023-03-31T15:46:31.689Z]
MovieActor{movieName='movie01', actorName='actor0', actingAward='actingaward0', actingYear=2001, actingSchoolName='null'}
MovieActor{movieName='movie01', actorName='actor1', actingAward='actingaward1', actingYear=2001, actingSchoolName='actingschool1'}
MovieActor{movieName='movie01', actorName='actor2', actingAward='actingaward2', actingYear=2001, actingSchoolName='actingschool2'}
MovieActor{movieName='movie01', actorName='actor3', actingAward='actingaward3', actingYear=2001, actingSchoolName='null'}
MovieActor{movieName='movie01', actorName='actor4', actingAward='actingaward4', actingYear=2001, actingSchoolName='actingschool4'}
```

次の出力は、コメント行 4 の後に返され、記録された項目を示しています。

```
Customer [id=1, name=CustName1, email=cust1@example.org, regDate=2023-03-31T15:46:27.688Z]
Customer [id=2, name=CustName2, email=cust2@example.org, regDate=2023-03-31T15:46:28.688Z]
MovieActor{movieName='movie01', actorName='actor4', actingAward='actingaward4', actingYear=2001, actingSchoolName='actingschool4'}
MovieActor{movieName='movie01', actorName='actor1', actingAward='actingaward1', actingYear=2001, actingSchoolName='actingschool1'}
```

## `batchWriteItem()` の例
<a name="ddb-en-client-use-multiop-batch-write"></a>

`batchWriteItem()` メソッドが 1 つ以上のテーブルに 1 つ以上の項目を入力または削除します。リクエストでは、最大 25 件の個別の入力または削除操作を指定できます。次の例では、前に示した [`ProductCatalog`](ddb-en-client-use.md#ddb-en-client-use-compare-cs3) または [`MovieActor`](ddb-en-client-use-multirecord.md#ddb-en-client-use-movieactor-class) のモデルクラスを使用しています。

`WriteBatch` オブジェクトはコメント行 1 と 2 の後に作成されます。`ProductCatalog` テーブルでは、コードによって 1 つの項目が入力され、1 つの項目が削除されます。コメント 2 行目以降の `MovieActor` テーブルでは、コードによって 2 つの項目が入力され、1 つの項目が削除されます。

`batchWriteItem` メソッドはコメント行 3 の後に呼び出されます。`[builder](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/BatchWriteItemEnhancedRequest.Builder.html)` パラメータは各テーブルのバッチリクエストを提供します。

返された `[BatchWriteResult](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/BatchWriteResult.html)` オブジェクトには、未処理のリクエストを表示するための個別のメソッドが操作ごとに用意されています。コメント行 4a の後のコードは未処理の削除リクエストのキーを提供し、コメント行 4b の後のコードは未処理の入力項目を示します。

```
    public static void batchWriteItemExample(DynamoDbEnhancedClient enhancedClient,
                                             DynamoDbTable<ProductCatalog> catalogTable,
                                             DynamoDbTable<MovieActor> movieActorTable) {

        // 1. Build a batch to write to the ProductCatalog table.
        WriteBatch products = WriteBatch.builder(ProductCatalog.class)
                .mappedTableResource(catalogTable)
                .addPutItem(b -> b.item(getProductCatItem1()))
                .addDeleteItem(b -> b.key(k -> k
                        .partitionValue(getProductCatItem2().id())
                        .sortValue(getProductCatItem2().title())))
                .build();

        // 2. Build a batch to write to the MovieActor table.
        WriteBatch movies = WriteBatch.builder(MovieActor.class)
                .mappedTableResource(movieActorTable)
                .addPutItem(getMovieActorYeoh())
                .addPutItem(getMovieActorBlanchettPartial())
                .addDeleteItem(b -> b.key(k -> k
                        .partitionValue(getMovieActorStreep().getMovieName())
                        .sortValue(getMovieActorStreep().getActorName())))
                .build();

        // 3. Add WriteBatch objects to the request.
        BatchWriteResult batchWriteResult = enhancedClient.batchWriteItem(b -> b.writeBatches(products, movies));
        // 4. Retrieve keys for items the service did not process.
        // 4a. 'unprocessedDeleteItemsForTable()' returns keys for delete requests that did not process.
        if (batchWriteResult.unprocessedDeleteItemsForTable(movieActorTable).size() > 0) {
            batchWriteResult.unprocessedDeleteItemsForTable(movieActorTable).forEach(key ->
                    logger.info(key.toString()));
        }
        // 4b. 'unprocessedPutItemsForTable()' returns keys for put requests that did not process.
        if (batchWriteResult.unprocessedPutItemsForTable(catalogTable).size() > 0) {
            batchWriteResult.unprocessedPutItemsForTable(catalogTable).forEach(key ->
                    logger.info(key.toString()));
        }
    }
```

以下のヘルパーメソッドは入力操作と削除操作のモデルオブジェクトを提供します。

### ヘルパーメソッド
<a name="ddb-en-client-use-multiop-batch-write-helpers"></a>

```
 1.     public static ProductCatalog getProductCatItem1() {
 2.         return ProductCatalog.builder()
 3.                 .id(2)
 4.                 .isbn("1-565-85698")
 5.                 .authors(new HashSet<>(Arrays.asList("a", "b")))
 6.                 .price(BigDecimal.valueOf(30.22))
 7.                 .title("Title 55")
 8.                 .build();
 9.     }
10. 
11.     public static ProductCatalog getProductCatItem2() {
12.         return ProductCatalog.builder()
13.                 .id(4)
14.                 .price(BigDecimal.valueOf(40.00))
15.                 .title("Title 1")
16.                 .build();
17.     }  
18. 
19.     public static MovieActor getMovieActorBlanchettPartial() {
20.         MovieActor movieActor = new MovieActor();
21.         movieActor.setActorName("Cate Blanchett");
22.         movieActor.setMovieName("Blue Jasmine");
23.         movieActor.setActingYear(2023);
24.         movieActor.setActingAward("Best Actress");
25.         return movieActor;
26.     }
27. 
28.     public static MovieActor getMovieActorStreep() {
29.         MovieActor movieActor = new MovieActor();
30.         movieActor.setActorName("Meryl Streep");
31.         movieActor.setMovieName("Sophie's Choice");
32.         movieActor.setActingYear(1982);
33.         movieActor.setActingAward("Best Actress");
34.         movieActor.setActingSchoolName("Yale School of Drama");
35.         return movieActor;
36.     }
37. 
38.     public static MovieActor getMovieActorYeoh(){
39.         MovieActor movieActor = new MovieActor();
40.         movieActor.setActorName("Michelle Yeoh");
41.         movieActor.setMovieName("Everything Everywhere All at Once");
42.         movieActor.setActingYear(2023);
43.         movieActor.setActingAward("Best Actress");
44.         movieActor.setActingSchoolName("Royal Academy of Dance");
45.         return movieActor;
46.     }
```

サンプルコードを実行する前に、テーブルに次の項目が含まれていると仮定します。

```
MovieActor{movieName='Blue Jasmine', actorName='Cate Blanchett', actingAward='Best Actress', actingYear=2013, actingSchoolName='National Institute of Dramatic Art'}
MovieActor{movieName='Sophie's Choice', actorName='Meryl Streep', actingAward='Best Actress', actingYear=1982, actingSchoolName='Yale School of Drama'}
ProductCatalog{id=4, title='Title 1', isbn='orig_isbn', authors=[b, g], price=10}
```

サンプルコードが完了すると、テーブルには以下の項目が含まれます。

```
MovieActor{movieName='Blue Jasmine', actorName='Cate Blanchett', actingAward='Best Actress', actingYear=2013, actingSchoolName='null'}
MovieActor{movieName='Everything Everywhere All at Once', actorName='Michelle Yeoh', actingAward='Best Actress', actingYear=2023, actingSchoolName='Royal Academy of Dance'}
ProductCatalog{id=2, title='Title 55', isbn='1-565-85698', authors=[a, b], price=30.22}
```

`MovieActor` テーブルでは、`Blue Jasmine` ムービーアイテムが、`getMovieActorBlanchettPartial()` ヘルパーメソッドを通じて取得された入力リクエストで使用されたアイテムに置き換えられていることに注意してください。データ Bean 属性値が指定されなかった場合、データベース内の値は削除されます。これが、`actingSchoolName` で `Blue Jasmine` ムービーアイテムの結果が NULL になる理由です。

**注記**  
API ドキュメントでは、条件式を使用でき、消費された容量とコレクションのメトリクスは個別の[入力](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/PutItemEnhancedRequest.html)リクエストと[削除](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/DeleteItemEnhancedRequest.html)リクエストで返すことができると記載されていますが、バッチ書き込みシナリオではそうではありません。バッチ操作のパフォーマンスを向上させるため、これらの個々のオプションは無視されます。

# トランザクションオペレーションを実行する
<a name="ddb-en-client-use-multiop-trans"></a>

DynamoDB 拡張クライアント API には、`transactGetItems()` および `transactWriteItems()` メソッドが用意されています。SDK for Java のトランザクションによって DynamoDB テーブルに不可分性、一貫性、分離性、耐久性 (ACID) が実現されるため、アプリケーション内でのデータの精度を維持することができます。

## `transactGetItems()` の例
<a name="ddb-en-client-use-multiop-trans-getitems"></a>

`[transactGetItems()](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/DynamoDbEnhancedClient.html#transactGetItems(java.util.function.Consumer))` メソッドは、項目に対する個別のリクエストを最大 100 件受け付けます。すべてのアイテムは 1 つの不可分トランザクションで読み取られます。*Amazon DynamoDB デベロッパーガイド*には、[`transactGetItems()` メソッドが失敗する原因となる条件](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/transaction-apis.html#transaction-apis-txgetitems)や、`[transactGetItem()](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/transaction-apis.html#transaction-isolation)` の呼び出し時に使用される分離レベルに関する情報が記載されています。

次の例の 1 行目のコメントのあと、コードは `[builder](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/TransactGetItemsEnhancedRequest.Builder.html)` パラメータを使用して `transactGetItems()` メソッドを呼び出します。ビルダー `[addGetItem()](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/TransactGetItemsEnhancedRequest.Builder.html#addGetItem(software.amazon.awssdk.enhanced.dynamodb.MappedTableResource,T))` は、SDK が最終リクエストの生成に使用するキー値を含むデータオブジェクトを使用して 3 回呼び出されます。

このリクエストは、コメント行 2 の後に `[Document](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/Document.html)` オブジェクトのリストを返します。返されるドキュメントのリストには、アイテムデータの null 以外の [ドキュメント](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/Document.html) インスタンスがリクエストと同じ順序で含まれています。`[Document.getItem(MappedTableResource<T> mappedTableResource)](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/Document.html#getItem(software.amazon.awssdk.enhanced.dynamodb.MappedTableResource))` メソッドは、アイテムデータが返された場合は型指定されていない `Document` オブジェクトを型付きの Java オブジェクトに変換し、それ以外の場合は null を返します。

```
    public static void transactGetItemsExample(DynamoDbEnhancedClient enhancedClient,
                                               DynamoDbTable<ProductCatalog> catalogTable,
                                               DynamoDbTable<MovieActor> movieActorTable) {

        // 1. Request three items from two tables using a builder.
        final List<Document> documents = enhancedClient.transactGetItems(b -> b
                .addGetItem(catalogTable, Key.builder().partitionValue(2).sortValue("Title 55").build())
                .addGetItem(movieActorTable, Key.builder().partitionValue("Sophie's Choice").sortValue("Meryl Streep").build())
                .addGetItem(movieActorTable, Key.builder().partitionValue("Blue Jasmine").sortValue("Cate Blanchett").build())
                .build());

        // 2. A list of Document objects is returned in the same order as requested.
        ProductCatalog title55 = documents.get(0).getItem(catalogTable);
        if (title55 != null) {
            logger.info(title55.toString());
        }

        MovieActor sophiesChoice = documents.get(1).getItem(movieActorTable);
        if (sophiesChoice != null) {
            logger.info(sophiesChoice.toString());
        }

        // 3. The getItem() method returns null if the Document object contains no item from DynamoDB.
        MovieActor blueJasmine = documents.get(2).getItem(movieActorTable);
        if (blueJasmine != null) {
            logger.info(blueJasmine.toString());
        }
    }
```

コード例が実行される前は、DynamoDB テーブルには次の項目が含まれています。

```
ProductCatalog{id=2, title='Title 55', isbn='orig_isbn', authors=[b, g], price=10}
MovieActor{movieName='Sophie's Choice', actorName='Meryl Streep', actingAward='Best Actress', actingYear=1982, actingSchoolName='Yale School of Drama'}
```

次の出力が記録されます。リクエストされたアイテムが見つからなかった場合、`Blue Jasmine` という名前の映画のリクエストの場合とは異なり、アイテムは返されません。

```
ProductCatalog{id=2, title='Title 55', isbn='orig_isbn', authors=[b, g], price=10}
MovieActor{movieName='Sophie's Choice', actorName='Meryl Streep', actingAward='Best Actress', actingYear=1982, actingSchoolName='Yale School of Drama'}
```

## `transactWriteItems()` の例
<a name="ddb-en-client-use-multiop-trans-writeitems"></a>

`[transactWriteItems()](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/DynamoDbEnhancedClient.html#transactWriteItems(java.util.function.Consumer))` は、複数のテーブルにわたる 1 回のアトミックトランザクションで最大 100 件の入力、更新、削除アクションを受け付けます。*Amazon DynamoDB デベロッパーガイド*には、[基盤となる DynamoDB サービスオペレーション](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/transaction-apis.html#transaction-apis-txwriteitems)の制限と障害条件に関する詳細が記載されています。

### 基本的な の例
<a name="ddb-en-client-use-multiop-trans-writeitems-basic"></a>

次の例では、2 つのテーブルに対して 4 つのオペレーションがリクエストされています。対応するモデルクラスは、前に示した [`ProductCatalog`](ddb-en-client-use.md#ddb-en-client-use-compare-cs3) および [`MovieActor`](ddb-en-client-use-multirecord.md#ddb-en-client-use-movieactor-class) です。

入力、更新、削除の 3 つの操作では、それぞれ専用のリクエストパラメータを使用して詳細を指定します。

コメント行 1 の後のコードは、`addPutItem()` メソッドの単純なバリエーションを示しています。このメソッドは、`[MappedTableResource](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/MappedTableResource.html)` オブジェクトと入力するデータオブジェクトインスタンスを受け入れます。2 行目のコメントの後のステートメントには、`[TransactPutItemEnhancedRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/TransactPutItemEnhancedRequest.html)` インスタンスを受け付けるバリエーションが表示されます。このバリエーションでは、条件式などのオプションをリクエストに追加できます。次の[例](#ddb-en-client-use-multiop-trans-writeitems-opcondition)では、個々のオペレーションの条件式を示しています。

更新操作はコメント行 3 の後に要求されます。`[TransactUpdateItemEnhancedRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/TransactUpdateItemEnhancedRequest.Builder.html)` には、SDK がモデルオブジェクトの `null` 値を使って何をするかを設定できる `ignoreNulls()` メソッドがあります。`ignoreNulls()` メソッドが true を返す場合、SDK は `null` であるデータオブジェクト属性のテーブルの属性値を削除しません。`ignoreNulls()` メソッドが false を返す場合、SDK は DynamoDB サービスにテーブル内の項目から属性を削除するようリクエストします。`ignoreNulls` のデフォルト値は false です。

コメント 4 行目の後のステートメントは、データオブジェクトを取得する削除リクエストのバリエーションを示しています。拡張クライアントは、最後のリクエストをディスパッチする前にキー値を抽出します。

```
    public static void transactWriteItems(DynamoDbEnhancedClient enhancedClient,
                                          DynamoDbTable<ProductCatalog> catalogTable,
                                          DynamoDbTable<MovieActor> movieActorTable) {

        enhancedClient.transactWriteItems(b -> b
                // 1. Simplest variation of put item request.
                .addPutItem(catalogTable, getProductCatId2())
                // 2. Put item request variation that accommodates condition expressions.
                .addPutItem(movieActorTable, TransactPutItemEnhancedRequest.builder(MovieActor.class)
                        .item(getMovieActorStreep())
                        .conditionExpression(Expression.builder().expression("attribute_not_exists (movie)").build())
                        .build())
                // 3. Update request that does not remove attribute values on the table if the data object's value is null.
                .addUpdateItem(catalogTable, TransactUpdateItemEnhancedRequest.builder(ProductCatalog.class)
                        .item(getProductCatId4ForUpdate())
                        .ignoreNulls(Boolean.TRUE)
                        .build())
                // 4. Variation of delete request that accepts a data object. The key values are extracted for the request.
                .addDeleteItem(movieActorTable, getMovieActorBlanchett())
        );
    }
```

以下のヘルパーメソッドは、`add*Item` パラメータのデータオブジェクトを提供します。

#### ヘルパーメソッド
<a name="ddb-en-client-use-multiop-trans-writeitems-basic-helpers"></a>

```
    public static ProductCatalog getProductCatId2() {
        return ProductCatalog.builder()
                .id(2)
                .isbn("1-565-85698")
                .authors(new HashSet<>(Arrays.asList("a", "b")))
                .price(BigDecimal.valueOf(30.22))
                .title("Title 55")
                .build();
    }

    public static ProductCatalog getProductCatId4ForUpdate() {
        return ProductCatalog.builder()
                .id(4)
                .price(BigDecimal.valueOf(40.00))
                .title("Title 1")
                .build();
    }

    public static MovieActor getMovieActorBlanchett() {
        MovieActor movieActor = new MovieActor();
        movieActor.setActorName("Cate Blanchett");
        movieActor.setMovieName("Tar");
        movieActor.setActingYear(2022);
        movieActor.setActingAward("Best Actress");
        movieActor.setActingSchoolName("National Institute of Dramatic Art");
        return movieActor;
    }

    public static MovieActor getMovieActorStreep() {
        MovieActor movieActor = new MovieActor();
        movieActor.setActorName("Meryl Streep");
        movieActor.setMovieName("Sophie's Choice");
        movieActor.setActingYear(1982);
        movieActor.setActingAward("Best Actress");
        movieActor.setActingSchoolName("Yale School of Drama");
        return movieActor;
    }
```

コード例が実行される前は、DynamoDB テーブルには次の項目が含まれています。

```
1 | ProductCatalog{id=4, title='Title 1', isbn='orig_isbn', authors=[b, g], price=10}
2 | MovieActor{movieName='Tar', actorName='Cate Blanchett', actingAward='Best Actress', actingYear=2022, actingSchoolName='National Institute of Dramatic Art'}
```

コードの実行が完了すると、次の項目がテーブルに表示されます。

```
3 | ProductCatalog{id=2, title='Title 55', isbn='1-565-85698', authors=[a, b], price=30.22}
4 | ProductCatalog{id=4, title='Title 1', isbn='orig_isbn', authors=[b, g], price=40.0}
5 | MovieActor{movieName='Sophie's Choice', actorName='Meryl Streep', actingAward='Best Actress', actingYear=1982, actingSchoolName='Yale School of Drama'}
```

2 行目の項目は削除され、3 行目と 5 行目には追加された項目が表示されます。4 行目は 1 行目の更新を示しています。アイテム上で変更されたのは `price` の値だけです。`ignoreNulls()` が false を返した場合、4 行目は次の行のようになります。

```
ProductCatalog{id=4, title='Title 1', isbn='null', authors=null, price=40.0}
```

### コンディションチェックの例
<a name="ddb-en-client-use-multiop-trans-writeitems-checkcond"></a>

次の例は、条件チェックの使用を示しています。コンディションチェックは、アイテムの存在を確認したり、データベース内のアイテムの特定の属性の状態をチェックしたりするために使用されます。コンディションチェックでチェックされたアイテムは、トランザクション内の別のオペレーションでは使用できません。

**注記**  
同じトランザクション内の複数のオペレーションが同じ項目をターゲットとすることはできません。たとえば、同じトランザクション内で同じ項目に対してコンディションチェックと更新を実行することはできません。

この例では、トランザクションによる項目書き込みリクエストにおける各タイプの操作を 1 つずつ示しています。2 行目のコメントの後、`addConditionCheck()` メソッドは、`conditionExpression` パラメータが `false` と評価された場合にトランザクションが失敗する条件を指定します。ヘルパーメソッドブロックに表示されているメソッドから返される条件式は、ムービーの受賞年度 `Sophie's Choice` が `1982` と等しくないかどうかをチェックします。一致した場合、式は `false` と評価され、トランザクションは失敗します。

このガイドでは、別のトピックで[式](ddb-en-client-expressions.md)について詳しく説明します。

```
    public static void conditionCheckFailExample(DynamoDbEnhancedClient enhancedClient,
                                                 DynamoDbTable<ProductCatalog> catalogTable,
                                                 DynamoDbTable<MovieActor> movieActorTable) {

        try {
            enhancedClient.transactWriteItems(b -> b
                    // 1. Perform one of each type of operation with the next three methods.
                    .addPutItem(catalogTable, TransactPutItemEnhancedRequest.builder(ProductCatalog.class)
                            .item(getProductCatId2()).build())
                    .addUpdateItem(catalogTable, TransactUpdateItemEnhancedRequest.builder(ProductCatalog.class)
                            .item(getProductCatId4ForUpdate())
                            .ignoreNulls(Boolean.TRUE).build())
                    .addDeleteItem(movieActorTable, TransactDeleteItemEnhancedRequest.builder()
                            .key(b1 -> b1
                                    .partitionValue(getMovieActorBlanchett().getMovieName())
                                    .sortValue(getMovieActorBlanchett().getActorName())).build())
                    // 2. Add a condition check on a table item that is not involved in another operation in this request.
                    .addConditionCheck(movieActorTable, ConditionCheck.builder()
                            .conditionExpression(buildConditionCheckExpression())
                            .key(k -> k
                                    .partitionValue("Sophie's Choice")
                                    .sortValue("Meryl Streep"))
                            // 3. Specify the request to return existing values from the item if the condition evaluates to true.
                            .returnValuesOnConditionCheckFailure(ReturnValuesOnConditionCheckFailure.ALL_OLD)
                            .build())
                    .build());
        // 4. Catch the exception if the transaction fails and log the information.
        } catch (TransactionCanceledException ex) {
            ex.cancellationReasons().stream().forEach(cancellationReason -> {
                logger.info(cancellationReason.toString());
            });
        }
    }
```

前のコード例では以下のヘルパーメソッドが使用されています。

#### ヘルパーメソッド
<a name="ddb-en-client-use-multiop-trans-writeitems-checkcond-helpers"></a>

```
    private static Expression buildConditionCheckExpression() {
        Map<String, AttributeValue> expressionValue = Map.of(
                ":year", numberValue(1982));

        return Expression.builder()
                .expression("actingyear <> :year")
                .expressionValues(expressionValue)
                .build();
    }

    public static ProductCatalog getProductCatId2() {
        return ProductCatalog.builder()
                .id(2)
                .isbn("1-565-85698")
                .authors(new HashSet<>(Arrays.asList("a", "b")))
                .price(BigDecimal.valueOf(30.22))
                .title("Title 55")
                .build();
    }

    public static ProductCatalog getProductCatId4ForUpdate() {
        return ProductCatalog.builder()
                .id(4)
                .price(BigDecimal.valueOf(40.00))
                .title("Title 1")
                .build();
    }

    public static MovieActor getMovieActorBlanchett() {
        MovieActor movieActor = new MovieActor();
        movieActor.setActorName("Cate Blanchett");
        movieActor.setMovieName("Blue Jasmine");
        movieActor.setActingYear(2013);
        movieActor.setActingAward("Best Actress");
        movieActor.setActingSchoolName("National Institute of Dramatic Art");
        return movieActor;
    }
```

コード例が実行される前は、DynamoDB テーブルには次の項目が含まれています。

```
1 | ProductCatalog{id=4, title='Title 1', isbn='orig_isbn', authors=[b, g], price=10}
2 | MovieActor{movieName='Sophie's Choice', actorName='Meryl Streep', actingAward='Best Actress', actingYear=1982, actingSchoolName='Yale School of Drama'}
3 | MovieActor{movieName='Tar', actorName='Cate Blanchett', actingAward='Best Actress', actingYear=2022, actingSchoolName='National Institute of Dramatic Art'}
```

コードの実行が完了すると、次の項目がテーブルに表示されます。

```
ProductCatalog{id=4, title='Title 1', isbn='orig_isbn', authors=[b, g], price=10}
MovieActor{movieName='Sophie's Choice', actorName='Meryl Streep', actingAward='Best Actress', actingYear=1982, actingSchoolName='Yale School of Drama'}
MovieActor{movieName='Tar', actorName='Cate Blanchett', actingAward='Best Actress', actingYear=2022, actingSchoolName='National Institute of Dramatic Art'}
```

トランザクションが失敗したため、テーブル内の項目は変更されません。ムービー `Sophie's Choice` の `actingYear` 値は `1982` であり、`transactWriteItem()` メソッドが呼び出される前のテーブル内の項目の 2 行目に示されているとおりです。

トランザクションのキャンセル情報を取得するには、`transactWriteItems()` メソッド呼び出しを `try` ブロックし、[https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/model/TransactionCanceledException.html](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/model/TransactionCanceledException.html) を `catch` します。この例の 4 行目のコメントの後、コードは各 `[CancellationReason](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/model/CancellationReason.html)` オブジェクトをログに記録します。この例の 3 行目のコメントに続くコードでは、トランザクションが失敗した原因となった項目の値を返すように指定していたため、ログには `Sophie's Choice` ムービー項目の未加工のデータベース値が表示されます。

```
CancellationReason(Code=None)
CancellationReason(Code=None)
CancellationReason(Code=None)
CancellationReason(Item={actor=AttributeValue(S=Meryl Streep), movie=AttributeValue(S=Sophie's Choice), actingaward=AttributeValue(S=Best Actress), actingyear=AttributeValue(N=1982), actingschoolname=AttributeValue(S=Yale School of Drama)}, ¬
    Code=ConditionalCheckFailed, Message=The conditional request failed.)
```

### 単一オペレーション条件の例
<a name="ddb-en-client-use-multiop-trans-writeitems-opcondition"></a>

次の例は、トランザクションリクエスト内の 1 つのオペレーションで条件を使用する方法を示しています。コメント行 1 の後の削除操作には、操作の対象項目の値をデータベースと照合する条件が含まれています。この例では、ヘルパーメソッドでコメント行 2 の後に作成した条件式は、映画の制作年が 2013 年と等しくない場合はその項目をデータベースから削除するように指定しています。

[式](ddb-en-client-expressions.md)についてはこのガイドの後半で説明します。

```
    public static void singleOperationConditionFailExample(DynamoDbEnhancedClient enhancedClient,
                                                           DynamoDbTable<ProductCatalog> catalogTable,
                                                           DynamoDbTable<MovieActor> movieActorTable) {
        try {
            enhancedClient.transactWriteItems(b -> b
                    .addPutItem(catalogTable, TransactPutItemEnhancedRequest.builder(ProductCatalog.class)
                            .item(getProductCatId2())
                            .build())
                    .addUpdateItem(catalogTable, TransactUpdateItemEnhancedRequest.builder(ProductCatalog.class)
                            .item(getProductCatId4ForUpdate())
                            .ignoreNulls(Boolean.TRUE).build())
                    // 1. Delete operation that contains a condition expression
                    .addDeleteItem(movieActorTable, TransactDeleteItemEnhancedRequest.builder()
                            .key((Key.Builder k) -> {
                                MovieActor blanchett = getMovieActorBlanchett();
                                k.partitionValue(blanchett.getMovieName())
                                        .sortValue(blanchett.getActorName());
                            })
                            .conditionExpression(buildDeleteItemExpression())
                            .returnValuesOnConditionCheckFailure(ReturnValuesOnConditionCheckFailure.ALL_OLD)
                            .build())
                    .build());
        } catch (TransactionCanceledException ex) {
            ex.cancellationReasons().forEach(cancellationReason -> logger.info(cancellationReason.toString()));
        }
    }

    // 2. Provide condition expression to check if 'actingyear' is not equal to 2013.
    private static Expression buildDeleteItemExpression() {
        Map<String, AttributeValue> expressionValue = Map.of(
                ":year", numberValue(2013));

        return Expression.builder()
                .expression("actingyear <> :year")
                .expressionValues(expressionValue)
                .build();
    }
```

前のコード例では以下のヘルパーメソッドが使用されています。

#### ヘルパーメソッド
<a name="ddb-en-client-use-multiop-trans-writeitems-opcondition-helpers"></a>

```
    public static ProductCatalog getProductCatId2() {
        return ProductCatalog.builder()
                .id(2)
                .isbn("1-565-85698")
                .authors(new HashSet<>(Arrays.asList("a", "b")))
                .price(BigDecimal.valueOf(30.22))
                .title("Title 55")
                .build();
    }

    public static ProductCatalog getProductCatId4ForUpdate() {
        return ProductCatalog.builder()
                .id(4)
                .price(BigDecimal.valueOf(40.00))
                .title("Title 1")
                .build();
    }
    public static MovieActor getMovieActorBlanchett() {
        MovieActor movieActor = new MovieActor();
        movieActor.setActorName("Cate Blanchett");
        movieActor.setMovieName("Blue Jasmine");
        movieActor.setActingYear(2013);
        movieActor.setActingAward("Best Actress");
        movieActor.setActingSchoolName("National Institute of Dramatic Art");
        return movieActor;
    }
```

コード例が実行される前は、DynamoDB テーブルには次の項目が含まれています。

```
1 | ProductCatalog{id=4, title='Title 1', isbn='orig_isbn', authors=[b, g], price=10}
2 | MovieActor{movieName='Blue Jasmine', actorName='Cate Blanchett', actingAward='Best Actress', actingYear=2013, actingSchoolName='National Institute of Dramatic Art'}
```

コードの実行が完了すると、次の項目がテーブルに表示されます。

```
ProductCatalog{id=4, title='Title 1', isbn='orig_isbn', authors=[b, g], price=10}
2023-03-15 11:29:07 [main] INFO  org.example.tests.TransactDemoTest:168 - MovieActor{movieName='Blue Jasmine', actorName='Cate Blanchett', actingAward='Best Actress', actingYear=2013, actingSchoolName='National Institute of Dramatic Art'}
```

トランザクションが失敗したため、テーブル内の項目は変更されません。ムービー `Blue Jasmine` の `actingYear` 値は、コード例が実行される前の項目リストの 2 行目に表示されている `2013` です。

次の行がコンソールに記録されます。

```
CancellationReason(Code=None)
CancellationReason(Code=None)
CancellationReason(Item={actor=AttributeValue(S=Cate Blanchett), movie=AttributeValue(S=Blue Jasmine), actingaward=AttributeValue(S=Best Actress), actingyear=AttributeValue(N=2013), actingschoolname=AttributeValue(S=National Institute of Dramatic Art)}, 
    Code=ConditionalCheckFailed, Message=The conditional request failed)
```

# セカンダリインデックスを使用する
<a name="ddb-en-client-use-secindex"></a>

セカンダリインデックスは、クエリやスキャンの操作に使用する代替キーを定義することで、データアクセスを向上させます。グローバルセカンダリインデックス (GSI) はベーステーブルのものとは異なる可能性があるパーティションキーおよびソートキーを持ちます。対照的に、ローカルセカンダリインデックス (LSI) はプライマリインデックスのパーティションキーを使用します。

## セカンダリインデックス注釈でデータクラスに注釈を付けます。
<a name="ddb-en-client-use-secindex-annomodel"></a>

セカンダリインデックスに含まれる属性には、`@DynamoDbSecondaryPartitionKey` または `@DynamoDbSecondarySortKey` 注釈が必要です。

次のクラスは 2 つのインデックスの注釈を表示します。*SubjectLastPostedDateIndex* という名前の GSI は、パーティションキーにこの `Subject` 属性を使用し、ソートキーには `LastPostedDateTime` という属性を使用します。*ForumLastPostedDateIndex* という名前の LSI は、`ForumName` をパーティションキーとして、`LastPostedDateTime` をソートキーとして使用します。

`Subject` 属性には 2 つの役割があることに注意してください。これはプライマリキーのソートキーであり、*subjectLastPostedDateIndex* という名前の GSI のパーティションキーでもあります。

### `MessageThread` クラス
<a name="ddb-en-client-use-secindex-class"></a>

`MessageThread` クラスは、*Amazon DynamoDB デベロッパーガイド*の[サンプルスレッドテーブル](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/AppendixSampleTables.html)のデータクラスとして使用するのに適しています。

#### インポート
<a name="ddb-en-client-use-secindex-classimports"></a>

```
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbBean;
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbPartitionKey;
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbSecondaryPartitionKey;
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbSecondarySortKey;
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbSortKey;

import java.util.List;
```

```
@DynamoDbBean
public class MessageThread {
    private String ForumName;
    private String Subject;
    private String Message;
    private String LastPostedBy;
    private String LastPostedDateTime;
    private Integer Views;
    private Integer Replies;
    private Integer Answered;
    private List<String> Tags;

    @DynamoDbPartitionKey
    public String getForumName() {
        return ForumName;
    }

    public void setForumName(String forumName) {
        ForumName = forumName;
    }

    // Sort key for primary index and partition key for GSI "SubjectLastPostedDateIndex".
    @DynamoDbSortKey
    @DynamoDbSecondaryPartitionKey(indexNames = "SubjectLastPostedDateIndex")
    public String getSubject() {
        return Subject;
    }

    public void setSubject(String subject) {
        Subject = subject;
    }

    // Sort key for GSI "SubjectLastPostedDateIndex" and sort key for LSI "ForumLastPostedDateIndex".
    @DynamoDbSecondarySortKey(indexNames = {"SubjectLastPostedDateIndex", "ForumLastPostedDateIndex"})
    public String getLastPostedDateTime() {
        return LastPostedDateTime;
    }

    public void setLastPostedDateTime(String lastPostedDateTime) {
        LastPostedDateTime = lastPostedDateTime;
    }
    public String getMessage() {
        return Message;
    }

    public void setMessage(String message) {
        Message = message;
    }

    public String getLastPostedBy() {
        return LastPostedBy;
    }

    public void setLastPostedBy(String lastPostedBy) {
        LastPostedBy = lastPostedBy;
    }

    public Integer getViews() {
        return Views;
    }

    public void setViews(Integer views) {
        Views = views;
    }

    @DynamoDbSecondaryPartitionKey(indexNames = "ForumRepliesIndex")
    public Integer getReplies() {
        return Replies;
    }

    public void setReplies(Integer replies) {
        Replies = replies;
    }

    public Integer getAnswered() {
        return Answered;
    }

    public void setAnswered(Integer answered) {
        Answered = answered;
    }

    public List<String> getTags() {
        return Tags;
    }

    public void setTags(List<String> tags) {
        Tags = tags;
    }

    public MessageThread() {
        this.Answered = 0;
        this.LastPostedBy = "";
        this.ForumName = "";
        this.Message = "";
        this.LastPostedDateTime = "";
        this.Replies = 0;
        this.Views = 0;
        this.Subject = "";
    }

    @Override
    public String toString() {
        return "MessageThread{" +
                "ForumName='" + ForumName + '\'' +
                ", Subject='" + Subject + '\'' +
                ", Message='" + Message + '\'' +
                ", LastPostedBy='" + LastPostedBy + '\'' +
                ", LastPostedDateTime='" + LastPostedDateTime + '\'' +
                ", Views=" + Views +
                ", Replies=" + Replies +
                ", Answered=" + Answered +
                ", Tags=" + Tags +
                '}';
    }
}
```

## インデックスを作成する
<a name="ddb-en-client-use-secindex-confindex"></a>

SDK for Java のバージョン 2.20.86 以降では、`createTable()` メソッドはデータクラス注釈からセカンダリインデックスを自動的に生成します。デフォルトでは、ベーステーブルのすべての属性がインデックスにコピーされ、プロビジョニングされるスループット値は 20 読み取りキャパシティーユニットと 20 書き込みキャパシティーユニットです。

ただし、2.20.86 より前のバージョンの SDK を使用する場合は、次の例のようにテーブルと一緒にインデックスを作成する必要があります。この例では、`Thread` テーブルの 2 つのインデックスを構築します。[builder](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/CreateTableEnhancedRequest.Builder.html) パラメータには、1 行目と 2 行目のコメント行の後に示されているように、両方のタイプのインデックスを設定するメソッドがあります。インデックスビルダーの `indexName()` メソッドを使用して、データクラス注釈で指定されているインデックス名を目的のインデックスタイプに関連付けます。

このコードでは、すべてのテーブル属性がコメント行 3 と 4 のコメント行の後に両方のインデックスに含まれるように構成しています。[属性プロジェクション](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/LSI.html#LSI.Projections)の詳細については、「*Amazon DynamoDB デベロッパーガイド*」を参照してください。

```
    public static void createMessageThreadTable(DynamoDbTable<MessageThread> messageThreadDynamoDbTable, DynamoDbClient dynamoDbClient) {
        messageThreadDynamoDbTable.createTable(b -> b
                // 1. Generate the GSI.
                .globalSecondaryIndices(gsi -> gsi.indexName("SubjectLastPostedDateIndex")
                        // 3. Populate the GSI with all attributes.
                        .projection(p -> p
                                .projectionType(ProjectionType.ALL))
                )
                // 2. Generate the LSI.
                .localSecondaryIndices(lsi -> lsi.indexName("ForumLastPostedDateIndex")
                        // 4. Populate the LSI with all attributes.
                        .projection(p -> p
                                .projectionType(ProjectionType.ALL))
                )
        );
```

## インデックスを使用してクエリを実行する
<a name="ddb-en-client-use-secindex-query"></a>

次の例では、ローカルセカンダリインデックス *ForumLastPostedDateIndex* にクエリを実行します。

2 行目のコメントに続いて、[DynamodBindEx.query ()](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/DynamoDbIndex.html#query(java.util.function.Consumer)) メソッドを呼び出すときに必要な [QueryConditional](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/QueryConditional.html) オブジェクトを作成します。

コメント 3 行目の後にインデックスの名前を渡すと、クエリするインデックスへの参照が得られます。4 行目のコメントに続いて、`QueryConditional` オブジェクトに渡されるインデックスの `query()` メソッドを呼び出します。

また、5 行目のコメントの後に示される 3 つの属性値を返すようにクエリを構成します。`attributesToProject()` が呼び出されない場合、クエリはすべての属性値を返します。指定した属性名は小文字で始まることに注意してください。これらの属性名は表で使用されているものと一致し、必ずしもデータクラスの属性名と一致するわけではありません。

6 行目のコメントに続いて、結果を反復処理し、クエリによって返される各項目をログ記録し、それをリストに保存して呼び出し元に返します。

```
public class IndexScanExamples {
    private static Logger logger = LoggerFactory.getLogger(IndexScanExamples.class);

    public static List<MessageThread> queryUsingSecondaryIndices(String lastPostedDate,
                                                                 DynamoDbTable<MessageThread> threadTable) {
        // 1. Log the parameter value.
        logger.info("lastPostedDate value: {}", lastPostedDate);

        // 2. Create a QueryConditional whose sort key value must be greater than or equal to the parameter value.
        QueryConditional queryConditional = QueryConditional.sortGreaterThanOrEqualTo(qc ->
                qc.partitionValue("Forum02").sortValue(lastPostedDate));

        // 3. Specify the index name to query.
        final DynamoDbIndex<MessageThread> forumLastPostedDateIndex = threadTable.index("ForumLastPostedDateIndex");

        // 4. Perform the query using the QueryConditional object.
        final SdkIterable<Page<MessageThread>> pagedResult = forumLastPostedDateIndex.query(q -> q
                .queryConditional(queryConditional)
                // 5. Request three attribute in the results.
                .attributesToProject("forumName", "subject", "lastPostedDateTime"));

        List<MessageThread> collectedItems = new ArrayList<>();
        // 6. Iterate through pages response and sort the items.
        pagedResult.stream().forEach(page -> page.items().stream()
                .sorted(Comparator.comparing(MessageThread::getLastPostedDateTime))
                .forEach(mt -> {
                    // 7. Log the returned items and add the collection to return to the caller.
                    logger.info(mt.toString());
                    collectedItems.add(mt);
                }));
        return collectedItems;
    }
```

クエリが実行される前は、次の項目がデータベースに存在しています。

```
MessageThread{ForumName='Forum01', Subject='Subject01', Message='Message01', LastPostedBy='', LastPostedDateTime='2023.03.28', Views=0, Replies=0, Answered=0, Tags=null}
MessageThread{ForumName='Forum02', Subject='Subject02', Message='Message02', LastPostedBy='', LastPostedDateTime='2023.03.29', Views=0, Replies=0, Answered=0, Tags=null}
MessageThread{ForumName='Forum02', Subject='Subject04', Message='Message04', LastPostedBy='', LastPostedDateTime='2023.03.31', Views=0, Replies=0, Answered=0, Tags=null}
MessageThread{ForumName='Forum02', Subject='Subject08', Message='Message08', LastPostedBy='', LastPostedDateTime='2023.04.04', Views=0, Replies=0, Answered=0, Tags=null}
MessageThread{ForumName='Forum02', Subject='Subject10', Message='Message10', LastPostedBy='', LastPostedDateTime='2023.04.06', Views=0, Replies=0, Answered=0, Tags=null}
MessageThread{ForumName='Forum03', Subject='Subject03', Message='Message03', LastPostedBy='', LastPostedDateTime='2023.03.30', Views=0, Replies=0, Answered=0, Tags=null}
MessageThread{ForumName='Forum03', Subject='Subject06', Message='Message06', LastPostedBy='', LastPostedDateTime='2023.04.02', Views=0, Replies=0, Answered=0, Tags=null}
MessageThread{ForumName='Forum03', Subject='Subject09', Message='Message09', LastPostedBy='', LastPostedDateTime='2023.04.05', Views=0, Replies=0, Answered=0, Tags=null}
MessageThread{ForumName='Forum05', Subject='Subject05', Message='Message05', LastPostedBy='', LastPostedDateTime='2023.04.01', Views=0, Replies=0, Answered=0, Tags=null}
MessageThread{ForumName='Forum07', Subject='Subject07', Message='Message07', LastPostedBy='', LastPostedDateTime='2023.04.03', Views=0, Replies=0, Answered=0, Tags=null}
```

1 行目と 6 行目のログ記録ステートメントは、次のようなコンソール出力になります。

```
lastPostedDate value: 2023.03.31
MessageThread{ForumName='Forum02', Subject='Subject04', Message='', LastPostedBy='', LastPostedDateTime='2023.03.31', Views=0, Replies=0, Answered=0, Tags=null}
MessageThread{ForumName='Forum02', Subject='Subject08', Message='', LastPostedBy='', LastPostedDateTime='2023.04.04', Views=0, Replies=0, Answered=0, Tags=null}
MessageThread{ForumName='Forum02', Subject='Subject10', Message='', LastPostedBy='', LastPostedDateTime='2023.04.06', Views=0, Replies=0, Answered=0, Tags=null}
```

このクエリでは、*Forum02* の `forumName` 値と *2023.03.31* 以上の `lastPostedDateTime` 値の項目が返されました。インデックスには `message` 属性に値が含まれていますが、結果には空の文字列を含む `message` 値が表示されます。これは、メッセージ属性がコメント 5 行目以降にコードによって投影されなかったためです。

# 高度なマッピング機能を使用する
<a name="ddb-en-client-adv-features"></a>

DynamoDB 拡張クライアント API の高度なテーブルスキーマ機能について説明します。

## テーブルのスキーマタイプを理解する
<a name="ddb-en-client-adv-features-schm-overview"></a>

`[TableSchema](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/TableSchema.html)` は DynamoDB 拡張クライアント API のマッピング機能へのインターフェイスです。データオブジェクトを AttributeValues のマップにマップしたり、[AttributeValues](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/model/AttributeValue.html) のマップからマップしたりできます。`TableSchema` オブジェクトはマッピングするテーブルの構造を知る必要があります。この構造情報は [https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/TableMetadata.html](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/TableMetadata.html) オブジェクトに格納されます。

拡張クライアント API には、以下のようないくつかの `TableSchema` の実装があります。

### 注釈付きのクラスから生成されたテーブルスキーマ
<a name="ddb-en-client-adv-features-schema-mapped"></a>

注釈付きクラスから `TableSchema` を構築するのは比較的コストのかかる操作であり、アプリケーションの起動時に一度実行することをお勧めします。

 [BeanTableSchema](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/mapper/BeanTableSchema.html)   
この実装は Bean クラスの属性と注釈に基づいて構築されています。この方法の例は、「[はじめに」セクション](ddb-en-client-gs-tableschema.md#ddb-en-client-gs-tableschema-anno-bean)で説明されています。  
`BeanTableSchema` が期待どおりに動作しない場合は、`software.amazon.awssdk.enhanced.dynamodb.beans` のデバッグログ記録を有効にします。

[ImmutableTableSchema](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/mapper/ImmutableTableSchema.html)  
この実装は不変データクラスから構築されています。このアプローチは [不変データクラスでの操作](ddb-en-client-use-immut.md) セクションで説明されています。

### ビルダーで生成されたテーブルスキーマ
<a name="ddb-en-client-adv-features-schema-static"></a>

以下の `TableSchema` は、ビルダーを使用してコードから構築されています。このアプローチは、注釈付きのデータクラスを使用するアプローチよりもコストが低くなります。ビルダーのアプローチでは注釈を使用せず、JavaBean の命名標準も必要ありません。

[StaticTableSchema](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/mapper/StaticTableSchema.html)  
この実装は可変データクラス用に構築されています。このガイドの「はじめに」セクションでは、[ビルダーを使用して `StaticTableSchema` を生成する](ddb-en-client-gs-tableschema.md#ddb-en-client-gs-tableschema-builder)方法を説明しました。

[StaticImmutableTableSchema](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/mapper/StaticImmutableTableSchema.html)  
`StaticTableSchema` を構築する場合と同様に、不変データクラスで使用する[ビルダー](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/mapper/StaticImmutableTableSchema.html)を使用してこのタイプ `TableSchema` の実装を生成します。

### 固定スキーマのないデータ用のテーブルスキーマ
<a name="ddb-en-client-adv-features-schema-document"></a>

[DocumentTableSchema](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/document/DocumentTableSchema.html)  
`TableSchema` の他の実装とは異なり、`DocumentTableSchema` インスタンスには属性を定義しません。通常は、プライマリキーと属性コンバータープロバイダーのみを指定します。`EnhancedDocument` インスタンスは、個々の要素または JSON 文字列から構築した属性を提供します。

# 属性を明示的に含めたり除外したりします。
<a name="ddb-en-client-adv-features-inex-attr"></a>

DynamoDB 拡張クライアント API には、データクラス属性がテーブルの属性にならないようにする注釈が用意されています。この API では、データクラスの属性名とは異なる属性名を使用することもできます。

## 属性を除外する
<a name="ddb-en-client-adv-features-inex-attr-ex"></a>

DynamoDB テーブルにマッピングしてはいけない属性を無視するには、その属性に `@DynamoDbIgnore` 注釈を付けます。

```
private String internalKey;

@DynamoDbIgnore
public String getInternalKey() { return this.internalKey; }
public void setInternalKey(String internalKey) { this.internalKey = internalKey;}
```

## 属性を含める
<a name="ddb-en-client-adv-features-inex-attr-in"></a>

DynamoDB テーブルで使用される属性の名前を変更するには、`@DynamoDbAttribute` 注釈を付けて別の名前を指定します。

```
private String internalKey;

@DynamoDbAttribute("renamedInternalKey")
public String getInternalKey() { return this.internalKey; }
public void setInternalKey(String internalKey) { this.internalKey = internalKey;}
```

# 属性変換を制御する
<a name="ddb-en-client-adv-features-conversion"></a>

デフォルトでは、テーブルスキーマは `[AttributeConverterProvider](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/AttributeConverterProvider.html)` インターフェースのデフォルト実装を通じて、多くの一般的な Java 型のコンバーターを提供します。全体的なデフォルト動作は、カスタム `AttributeConverterProvider` 実装で変更できます。また、1 つの属性のコンバーターを変更することもできます。

使用可能なコンバーターのリストについては、「[AttributeConverter](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/AttributeConverter.html) インターフェースの Java ドキュメント」を参照してください。

## カスタム属性コンバータープロバイダーを提供する
<a name="ddb-en-client-adv-features-conversion-prov"></a>

`@DynamoDbBean` `(converterProviders = {…})` 注釈を使用して、単一の `AttributeConverterProvider` または順序付けられた `AttributeConverterProvider` のチェーンを提供することができます。どのようなカスタム `AttributeConverterProvider` でも `AttributeConverterProvider` インターフェースを拡張する必要があります。

独自の属性コンバータープロバイダーチェーンを指定すると、デフォルトのコンバータープロバイダー、`DefaultAttributeConverterProvider` がオーバーライドされることに注意してください。`DefaultAttributeConverterProvider` の機能を使用するには、チェーンに組み込む必要があります。

Bean に空の配列 `{}` に注釈を付けすることもできます。これにより、デフォルトを含むすべての属性コンバータープロバイダーの使用が無効になります。この場合、マップされるすべての属性には独自の属性コンバーターが必要です。

次のスニペットは、単一のコンバータープロバイダーを示しています。

```
@DynamoDbBean(converterProviders = ConverterProvider1.class)
public class Customer {

}
```

次のスニペットは、コンバータープロバイダーのチェーンの使用方法を示しています。SDK デフォルトは最後に指定されるため、優先度は最も低くなります。

```
@DynamoDbBean(converterProviders = {
   ConverterProvider1.class, 
   ConverterProvider2.class,
   DefaultAttributeConverterProvider.class})
public class Customer {

}
```

静的テーブルスキーマビルダーにも同じように機能する `attributeConverterProviders()` メソッドがあります。これは次のスニペットに示されています。

```
private static final StaticTableSchema<Customer> CUSTOMER_TABLE_SCHEMA =
  StaticTableSchema.builder(Customer.class)
    .newItemSupplier(Customer::new)
    .addAttribute(String.class, a -> a.name("name")
                                     a.getter(Customer::getName)
                                     a.setter(Customer::setName))
    .attributeConverterProviders(converterProvider1, converterProvider2)
    .build();
```

## 単一の属性のマッピングをオーバーライドする
<a name="ddb-en-client-adv-features-conversion-single"></a>

単一の属性のマッピング方法をオーバーライドするには、その属性に `AttributeConverter` を指定します。この追加は、テーブルスキーマの `AttributeConverterProviders` で提供されるコンバーターよりも優先されます。これにより、その属性専用のカスタムコンバーターが追加されます。他の属性は、同じタイプの属性であっても、他の属性に明示的に指定されていない限り、そのコンバーターを使用しません。

`@DynamoDbConvertedBy` 注釈は、次のスニペットに示すようにカスタム `AttributeConverter` クラスを指定するために使用されます。

```
@DynamoDbBean
public class Customer {
    private String name;

    @DynamoDbConvertedBy(CustomAttributeConverter.class)
    public String getName() { return this.name; }
    public void setName(String name) { this.name = name;}
}
```

静的スキーマのビルダーには、同等の属性ビルダー `attributeConverter()` メソッドがあります。このメソッドは、次に示すように、`AttributeConverter` のインスタンスを取得します。

```
private static final StaticTableSchema<Customer> CUSTOMER_TABLE_SCHEMA =
  StaticTableSchema.builder(Customer.class)
    .newItemSupplier(Customer::new)
    .addAttribute(String.class, a -> a.name("name")
                                     a.getter(Customer::getName)
                                     a.setter(Customer::setName)
                                     a.attributeConverter(customAttributeConverter))
    .build();
```

## 例
<a name="ddb-en-client-adv-features-conversion-example"></a>

この例は、[https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/net/HttpCookie.html](https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/net/HttpCookie.html) オブジェクトの属性コンバーターを提供する `AttributeConverterProvider` 実装を示しています。

次の `SimpleUser` クラスには、`HttpCookie` のインスタンスである `lastUsedCookie` という名前の属性が含まれています。

`@DynamoDbBean` 注釈のパラメータには、コンバーターを提供する 2 つの `AttributeConverterProvider` クラスがリストされています。

------
#### [ Class with annotations ]

```
    @DynamoDbBean(converterProviders = {CookieConverterProvider.class, DefaultAttributeConverterProvider.class})
    public static final class SimpleUser {
        private String name;
        private HttpCookie lastUsedCookie;

        @DynamoDbPartitionKey
        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public HttpCookie getLastUsedCookie() {
            return lastUsedCookie;
        }

        public void setLastUsedCookie(HttpCookie lastUsedCookie) {
            this.lastUsedCookie = lastUsedCookie;
        }
```

------
#### [ Static table schema ]

```
    private static final TableSchema<SimpleUser> SIMPLE_USER_TABLE_SCHEMA =
            TableSchema.builder(SimpleUser.class)
                    .newItemSupplier(SimpleUser::new)
                    .attributeConverterProviders(CookieConverterProvider.create(), AttributeConverterProvider.defaultProvider())
                    .addAttribute(String.class, a -> a.name("name")
                            .setter(SimpleUser::setName)
                            .getter(SimpleUser::getName)
                            .tags(StaticAttributeTags.primaryPartitionKey()))
                    .addAttribute(HttpCookie.class, a -> a.name("lastUsedCookie")
                            .setter(SimpleUser::setLastUsedCookie)
                            .getter(SimpleUser::getLastUsedCookie))
                    .build();
```

------

次の例の `CookieConverterProvider` では、`HttpCookeConverter` のインスタンスを提供しています。

```
    public static final class CookieConverterProvider implements AttributeConverterProvider {
        private final Map<EnhancedType<?>, AttributeConverter<?>> converterCache = ImmutableMap.of(
                // 1. Add HttpCookieConverter to the internal cache.
                EnhancedType.of(HttpCookie.class), new HttpCookieConverter());

        public static CookieConverterProvider create() {
            return new CookieConverterProvider();
        }

        // The SDK calls this method to find out if the provider contains a AttributeConverter instance
        // for the EnhancedType<T> argument.
        @SuppressWarnings("unchecked")
        @Override
        public <T> AttributeConverter<T> converterFor(EnhancedType<T> enhancedType) {
            return (AttributeConverter<T>) converterCache.get(enhancedType);
        }
    }
```

### 変換コード
<a name="ddb-en-client-adv-features-conversion-example-code"></a>

次の `HttpCookieConverter` クラスの `transformFrom()` メソッドでは、コードは `HttpCookie` インスタンスを受け取り、属性として保存される DynamoDB マップに変換します。

`transformTo()` メソッドは DynamoDB マップパラメータを受け取り、名前と値を必要とする `HttpCookie` コンストラクターを呼び出します。

```
    public static final class HttpCookieConverter implements AttributeConverter<HttpCookie> {

        @Override
        public AttributeValue transformFrom(HttpCookie httpCookie) {

            return AttributeValue.fromM(
            Map.of ("cookieName", AttributeValue.fromS(httpCookie.getName()),
                    "cookieValue", AttributeValue.fromS(httpCookie.getValue()))
            );
        }

        @Override
        public HttpCookie transformTo(AttributeValue attributeValue) {
            Map<String, AttributeValue> map = attributeValue.m();
            return new HttpCookie(
                    map.get("cookieName").s(),
                    map.get("cookieValue").s());
        }

        @Override
        public EnhancedType<HttpCookie> type() {
            return EnhancedType.of(HttpCookie.class);
        }

        @Override
        public AttributeValueType attributeValueType() {
            return AttributeValueType.M;
        }
    }
```

# 属性の更新動作を変更する
<a name="ddb-en-client-adv-features-upd-behavior"></a>

*更新*オペレーションを実行するときに、個々の属性の更新動作をカスタマイズできます。DynamoDB 拡張クライアント API の更新オペレーションの例には、[updateItem ()](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/DynamoDbTable.html#updateItem(T)) と [transactWriteItems ()](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/DynamoDbEnhancedClient.html#transactWriteItems(java.util.function.Consumer)) があります。

たとえば、**作成した日付のタイムスタンプをレコードに保存したいとします。ただし、データベースにその属性の既存の値がない場合にのみ、その値を書き込むようにしたいとします。この場合、`[WRITE\$1IF\$1NOT\$1EXISTS](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/mapper/UpdateBehavior.html#WRITE_IF_NOT_EXISTS)` 更新動作を使用します。

次の例は、`createdOn` 属性に動作を追加する注釈を示しています。

```
@DynamoDbBean
public class Customer extends GenericRecord {
    private String id;
    private Instant createdOn;

    @DynamoDbPartitionKey
    public String getId() { return this.id; }
    public void setId(String id) { this.name = id; }

    @DynamoDbUpdateBehavior(UpdateBehavior.WRITE_IF_NOT_EXISTS)
    public Instant getCreatedOn() { return this.createdOn; }    
    public void setCreatedOn(Instant createdOn) { this.createdOn = createdOn; }
}
```

次の例のコメント行 1 の後のように、静的テーブルスキーマを構築する場合にも同じ更新動作を宣言できます。

```
static final TableSchema<Customer> CUSTOMER_TABLE_SCHEMA =
     TableSchema.builder(Customer.class)
       .newItemSupplier(Customer::new)
       .addAttribute(String.class, a -> a.name("id")
                                         .getter(Customer::getId)
                                         .setter(Customer::setId)
                                         .tags(StaticAttributeTags.primaryPartitionKey()))
       .addAttribute(Instant.class, a -> a.name("createdOn")
                                          .getter(Customer::getCreatedOn)
                                          .setter(Customer::setCreatedOn)
                                          // 1. Add an UpdateBehavior.
                                          .tags(StaticAttributeTags.updateBehavior(UpdateBehavior.WRITE_IF_NOT_EXISTS)))
       .build();
```

# 他のクラスの属性をフラット化する
<a name="ddb-en-client-adv-features-flatmap"></a>

テーブルの属性が継承または構成によって複数の異なる Java クラスに分散している場合、DynamoDB Enhanced Client API では属性を 1 つのクラスにフラット化するためのサポートを提供します。

## 継承を使用する
<a name="ddb-en-client-adv-features-flatmap-inheritance"></a>

クラスで継承を使用する場合は、以下の方法で階層をフラット化してください。

### 注釈の付いた Bean を使用する
<a name="ddb-en-client-adv-features-flatmap-inheritance-anno"></a>

注釈手法では、両方のクラスに `@DynamoDbBean` 注釈が必要で、1 つのクラスに 1 つ以上のプライマリキーの注釈を付ける必要があります。

継承関係を持つデータクラスの例を以下に示します。

------
#### [ Standard data class ]

```
@DynamoDbBean
public class Customer extends GenericRecord {
    private String name;

    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
}

@DynamoDbBean
public abstract class GenericRecord {
    private String id;
    private String createdDate;

    @DynamoDbPartitionKey
    public String getId() { return id; }
    public void setId(String id) { this.id = id; }

    public String getCreatedDate() { return createdDate; }
    public void setCreatedDate(String createdDate) { this.createdDate = createdDate; }
}
```

------
#### [ Lombok ]

Lombok [`onMethod` のオプション](https://projectlombok.org/features/experimental/onX)では、`@DynamoDbPartitionKey` などの属性ベースの DynamoDB 注釈が生成コードにコピーされます。

```
@DynamoDbBean
@Data
@ToString(callSuper = true)
public class Customer extends GenericRecord {
    private String name;
}

@Data
@DynamoDbBean
public abstract class GenericRecord {
    @Getter(onMethod_=@DynamoDbPartitionKey)
    private String id;
    private String createdDate;
}
```

------

### 静的スキーマを使用する
<a name="ddb-en-client-adv-features-flatmap-inheritance-static"></a>

静的スキーマアプローチでは、ビルダーの `extend()` メソッドを使用して親クラスの属性を子クラスに集約します。これは次の例のコメント行 1 の後で示されています。

```
        StaticTableSchema<org.example.tests.model.inheritance.stat.GenericRecord> GENERIC_RECORD_SCHEMA =
                StaticTableSchema.builder(org.example.tests.model.inheritance.stat.GenericRecord.class)
                        // The partition key will be inherited by the top level mapper.
                        .addAttribute(String.class, a -> a.name("id")
                                .getter(org.example.tests.model.inheritance.stat.GenericRecord::getId)
                                .setter(org.example.tests.model.inheritance.stat.GenericRecord::setId)
                                .tags(primaryPartitionKey()))
                        .addAttribute(String.class, a -> a.name("created_date")
                                .getter(org.example.tests.model.inheritance.stat.GenericRecord::getCreatedDate)
                                .setter(org.example.tests.model.inheritance.stat.GenericRecord::setCreatedDate))
                        .build();

        StaticTableSchema<org.example.tests.model.inheritance.stat.Customer> CUSTOMER_SCHEMA =
                StaticTableSchema.builder(org.example.tests.model.inheritance.stat.Customer.class)
                        .newItemSupplier(org.example.tests.model.inheritance.stat.Customer::new)
                        .addAttribute(String.class, a -> a.name("name")
                                .getter(org.example.tests.model.inheritance.stat.Customer::getName)
                                .setter(org.example.tests.model.inheritance.stat.Customer::setName))
                        // 1. Use the extend() method to collapse the parent attributes onto the child class.
                        .extend(GENERIC_RECORD_SCHEMA)     // All the attributes of the GenericRecord schema are added to Customer.
                        .build();
```

先ほどの静的スキーマの例では、次のデータクラスを使用しています。マッピングは静的テーブルスキーマの構築時に定義されるため、データクラスには注釈は必要ありません。

#### データクラス
<a name="gunk"></a>

------
#### [ Standard data class ]

```
public class Customer extends GenericRecord {
    private String name;

    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
}


public abstract class GenericRecord {
    private String id;
    private String createdDate;

    public String getId() { return id; }
    public void setId(String id) { this.id = id; }

    public String getCreatedDate() { return createdDate; }
    public void setCreatedDate(String createdDate) { this.createdDate = createdDate; }
```

------
#### [ Lombok ]

```
@Data
@ToString(callSuper = true)
public class Customer extends GenericRecord{
    private String name;
}

@Data
public abstract class GenericRecord {
    private String id;
    private String createdDate;
}
```

------

## 構成を使用する
<a name="ddb-en-client-adv-features-flatmap-comp"></a>

クラスで構成を使用する場合は、以下の方法で階層をフラット化してください。

### 注釈の付いた Bean を使用する
<a name="ddb-en-client-adv-features-flatmap-comp-anno"></a>

`@DynamoDbFlatten` 注釈は格納されているクラスをフラット化します。

以下のデータクラスの例では、`@DynamoDbFlatten` 注釈を使用して、含まれている `GenericRecord` クラスのすべての属性を `Customer` クラスに効果的に追加しています。

------
#### [ Standard data class ]

```
@DynamoDbBean
public class Customer {
    private String name;
    private GenericRecord record;

    public String getName() { return this.name; }
    public void setName(String name) { this.name = name; }

    @DynamoDbFlatten
    public GenericRecord getRecord() { return this.record; }
    public void setRecord(GenericRecord record) { this.record = record; }

@DynamoDbBean
public class GenericRecord {
    private String id;
    private String createdDate;

    @DynamoDbPartitionKey
    public String getId() { return this.id; }
    public void setId(String id) { this.id = id; }

    public String getCreatedDate() { return this.createdDate; }
    public void setCreatedDate(String createdDate) { this.createdDate = createdDate; }
}
```

------
#### [ Lombok ]

```
@Data
@DynamoDbBean
public class Customer {
    private String name;
    @Getter(onMethod_=@DynamoDbFlatten)
    private GenericRecord record;
}

@Data
@DynamoDbBean
public class GenericRecord {
    @Getter(onMethod_=@DynamoDbPartitionKey)
    private String id;
    private String createdDate;
}
```

------

フラット化された注釈を使用すると、対象となるさまざまなクラスを必要なだけフラット化できます。以下の制約が適用されます。
+ フラット化の後は、すべての属性名が一意でなければなりません。
+ パーティションキー、ソートキー、またはテーブル名は複数あってはなりません。

### 静的スキーマを使用する
<a name="ddb-en-client-adv-features-flatmap-comp-static"></a>

静的テーブルスキーマを構築するときは、ビルダーの `flatten()` メソッドを使用します。また、含まれているクラスを識別する getter メソッド と setter メソッドも指定します。

```
        StaticTableSchema<GenericRecord> GENERIC_RECORD_SCHEMA =
                StaticTableSchema.builder(GenericRecord.class)
                        .newItemSupplier(GenericRecord::new)
                        .addAttribute(String.class, a -> a.name("id")
                                .getter(GenericRecord::getId)
                                .setter(GenericRecord::setId)
                                .tags(primaryPartitionKey()))
                        .addAttribute(String.class, a -> a.name("created_date")
                                .getter(GenericRecord::getCreatedDate)
                                .setter(GenericRecord::setCreatedDate))
                        .build();

        StaticTableSchema<Customer> CUSTOMER_SCHEMA =
                StaticTableSchema.builder(Customer.class)
                        .newItemSupplier(Customer::new)
                        .addAttribute(String.class, a -> a.name("name")
                                .getter(Customer::getName)
                                .setter(Customer::setName))
                        // Because we are flattening a component object, we supply a getter and setter so the
                        // mapper knows how to access it.
                        .flatten(GENERIC_RECORD_SCHEMA, Customer::getRecord, Customer::setRecord)
                        .build();
```

先ほどの静的スキーマの例では、次のデータクラスを使用しています。

#### データクラス
<a name="ddb-en-client-adv-features-flatmap-comp-static-supporting"></a>

------
#### [ Standard data class ]

```
public class Customer {
    private String name;
    private GenericRecord record;

    public String getName() { return this.name; }
    public void setName(String name) { this.name = name; }

    public GenericRecord getRecord() { return this.record; }
    public void setRecord(GenericRecord record) { this.record = record; }

public class GenericRecord {
    private String id;
    private String createdDate;

    public String getId() { return this.id; }
    public void setId(String id) { this.id = id; }

    public String getCreatedDate() { return this.createdDate; }
    public void setCreatedDate(String createdDate) { this.createdDate = createdDate; }
}
```

------
#### [ Lombok ]

```
@Data
public class Customer {
    private String name;
    private GenericRecord record;
}

@Data
public class GenericRecord {
    private String id;
    private String createdDate;
}
```

------

ビルダーパターンを使用して、対象となるさまざまなクラスを必要なだけフラット化できます。

## 他のコードへの影響
<a name="ddb-en-client-adv-features-flatmap-compare"></a>

`@DynamoDbFlatten` 属性 (または `flatten()` ビルダーメソッド) を使用する場合、DynamoDB の項目には、構成オブジェクトの各属性の属性が含まれます。また、構成オブジェクトの属性も含まれます。

これとは対照的に、データクラスに構成クラスの注釈を付け、`@DynamoDbFlatten` を使用しない場合、その項目は構成オブジェクトとともに単一の属性として保存されます。

たとえば、[構成例によるフラット化](#ddb-en-client-adv-features-flatmap-comp-anno)で示された `Customer` クラスを、`record` 属性をフラット化する場合とフラット化しない場合で比較します。次の表に示すように、JSON との違いを視覚化できます。


****  

| フラット化あり | フラット化なし | 
| --- | --- | 
| 3 つの属性 | 2 つの属性 | 
|  <pre>{<br />  "id": "1",<br />  "createdDate": "today",<br />  "name": "my name"<br />}</pre>  |  <pre>{<br />  "id": "1",<br />  "record": {<br />      "createdDate": "today",<br />      "name": "my name"<br />  }<br />}</pre>  | 

他のコードが DynamoDB テーブルにアクセスしていて、特定の属性を見つけることを想定している場合には、この違いが重要になります。

# Bean、Map、List、Set の属性を使用する
<a name="ddb-en-client-adv-features-nested"></a>

以下に示す `Person` クラスなどの Bean 定義は、追加の属性を持つ型を参照するプロパティ (または属性) を定義する場合があります。例えば、 `Person` クラスでは、 `mainAddress` は追加の値属性を定義する `Address` Bean を参照するプロパティです。`addresses` は Java Map を参照し、その要素は `Address` Bean を参照します。これらの複合型は、DynamoDB のコンテキストでデータ値に使用するシンプルな属性のコンテナと考えることができます。

DynamoDB は、マップ、リスト、Bean などのネストされた要素の値プロパティを*ネストされた属性*として参照します。「[Amazon DynamoDB デベロッパーガイド](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.NamingRulesDataTypes.html#HowItWorks.DataTypes)」では、Java Map、List、または Bean の保存形式を*ドキュメントタイプ*として参照します。Java のデータ値に使用するシンプルな属性は、DynamoDB では*スカラー型*と呼ばれます。Set は同じタイプの複数のスカラー要素を含み、*セット型*と呼ばれます。

DynamoDB 拡張クライアント API は、保存時に Bean であるプロパティを DynamoDB マップドキュメントタイプに変換することに注意してください。

## `Person` クラス
<a name="ddb-en-client-adv-features-nested-person"></a>

```
@DynamoDbBean
public class Person {
    private Integer id;
    private String firstName;
    private String lastName;
    private Integer age;
    private Address mainAddress;
    private Map<String, Address> addresses;
    private List<PhoneNumber> phoneNumbers;
    private Set<String> hobbies;

    @DynamoDbPartitionKey
    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public Address getMainAddress() {
        return mainAddress;
    }

    public void setMainAddress(Address mainAddress) {
        this.mainAddress = mainAddress;
    }

    public Map<String, Address> getAddresses() {
        return addresses;
    }

    public void setAddresses(Map<String, Address> addresses) {
        this.addresses = addresses;
    }

    public List<PhoneNumber> getPhoneNumbers() {
        return phoneNumbers;
    }

    public void setPhoneNumbers(List<PhoneNumber> phoneNumbers) {
        this.phoneNumbers = phoneNumbers;
    }

    public Set<String> getHobbies() {
        return hobbies;
    }

    public void setHobbies(Set<String> hobbies) {
        this.hobbies = hobbies;
    }

    @Override
    public String toString() {
        return "Person{" +
               "addresses=" + addresses +
               ", id=" + id +
               ", firstName='" + firstName + '\'' +
               ", lastName='" + lastName + '\'' +
               ", age=" + age +
               ", mainAddress=" + mainAddress +
               ", phoneNumbers=" + phoneNumbers +
               ", hobbies=" + hobbies +
               '}';
    }
}
```

## `Address` クラス
<a name="ddb-en-client-adv-features-nested-address"></a>

```
@DynamoDbBean
public class Address {
    private String street;
    private String city;
    private String state;
    private String zipCode;

    public Address() {
    }

    public String getStreet() {
        return this.street;
    }

    public String getCity() {
        return this.city;
    }

    public String getState() {
        return this.state;
    }

    public String getZipCode() {
        return this.zipCode;
    }

    public void setStreet(String street) {
        this.street = street;
    }

    public void setCity(String city) {
        this.city = city;
    }

    public void setState(String state) {
        this.state = state;
    }

    public void setZipCode(String zipCode) {
        this.zipCode = zipCode;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Address address = (Address) o;
        return Objects.equals(street, address.street) && Objects.equals(city, address.city) && Objects.equals(state, address.state) && Objects.equals(zipCode, address.zipCode);
    }

    @Override
    public int hashCode() {
        return Objects.hash(street, city, state, zipCode);
    }

    @Override
    public String toString() {
        return "Address{" +
                "street='" + street + '\'' +
                ", city='" + city + '\'' +
                ", state='" + state + '\'' +
                ", zipCode='" + zipCode + '\'' +
                '}';
    }
}
```

## `PhoneNumber` クラス
<a name="ddb-en-client-adv-features-nested-phonenumber"></a>

```
@DynamoDbBean
public class PhoneNumber {
    String type;
    String number;

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    public String getNumber() {
        return number;
    }

    public void setNumber(String number) {
        this.number = number;
    }

    @Override
    public String toString() {
        return "PhoneNumber{" +
                "type='" + type + '\'' +
                ", number='" + number + '\'' +
                '}';
    }
}
```

## 複合型を保存する
<a name="ddb-en-client-adv-features-nested-mapping"></a>

### 注釈付きデータクラスを使用する
<a name="ddb-en-client-adv-features-nested-map-anno"></a>

カスタムクラスのネストされた属性は、注釈を付けるだけで保存できます。前に示した `Address` クラスと `PhoneNumber` クラスには、`@DynamoDbBean` 注釈のみの注釈が付けられています。DynamoDB Enhanced Client API が次のスニペットを使用して `Person` クラスのテーブルスキーマを構築すると、API は`Address` および `PhoneNumber` クラスの使用を検出し、DynamoDB と動作する対応するマッピングを構築します。

```
TableSchema<Person> personTableSchema = TableSchema.fromBean(Person.class);
```

### ビルダーで抽象スキーマを使用する
<a name="ddb-en-client-adv-features-nested-map-builder"></a>

別の方法は、次のコードに示すように、ネストされた各 Bean クラスに静的テーブルスキーマビルダーを使用することです。

`Address` および `PhoneNumber` クラスのテーブルスキーマは、DynamoDB テーブルでは使用できないという意味で抽象的です。これは、プライマリキーの定義が不足しているためです。ただし、`Person` クラスのテーブルスキーマではネストされたスキーマとして使用されます。

`PERSON_TABLE_SCHEMA` の定義のコメント 1 行目と 2 行目の後に、抽象テーブルスキーマを使用するコードが表示されます。`EnhanceType.documentOf(...)` メソッド内で `documentOf` を使用しても、メソッドが拡張ドキュメント API の `EnhancedDocument` タイプを返すことを示すわけではありません。このコンテキストの `documentOf(...)` メソッドは、テーブルスキーマ引数を使用して DynamoDB テーブル属性との間でクラス引数をマッピングする方法を知っているオブジェクトを返します。

#### 静的スキーマコード
<a name="ddb-en-client-adv-features-nested-map-builder-code"></a>

```
    // Abstract table schema that cannot be used to work with a DynamoDB table,
    // but can be used as a nested schema.
    public static final TableSchema<Address> TABLE_SCHEMA_ADDRESS = TableSchema.builder(Address.class)
        .newItemSupplier(Address::new)
        .addAttribute(String.class, a -> a.name("street")
            .getter(Address::getStreet)
            .setter(Address::setStreet))
        .addAttribute(String.class, a -> a.name("city")
            .getter(Address::getCity)
            .setter(Address::setCity))
        .addAttribute(String.class, a -> a.name("zipcode")
            .getter(Address::getZipCode)
            .setter(Address::setZipCode))
        .addAttribute(String.class, a -> a.name("state")
            .getter(Address::getState)
            .setter(Address::setState))
        .build();

    // Abstract table schema that cannot be used to work with a DynamoDB table,
    // but can be used as a nested schema.
    public static final TableSchema<PhoneNumber> TABLE_SCHEMA_PHONENUMBER = TableSchema.builder(PhoneNumber.class)
        .newItemSupplier(PhoneNumber::new)
        .addAttribute(String.class, a -> a.name("type")
            .getter(PhoneNumber::getType)
            .setter(PhoneNumber::setType))
        .addAttribute(String.class, a -> a.name("number")
            .getter(PhoneNumber::getNumber)
            .setter(PhoneNumber::setNumber))
        .build();

    // A static table schema that can be used with a DynamoDB table.
    // The table schema contains two nested schemas that are used to perform mapping to/from DynamoDB.
    public static final TableSchema<Person> PERSON_TABLE_SCHEMA =
        TableSchema.builder(Person.class)
            .newItemSupplier(Person::new)
            .addAttribute(Integer.class, a -> a.name("id")
                .getter(Person::getId)
                .setter(Person::setId)
                .addTag(StaticAttributeTags.primaryPartitionKey()))
            .addAttribute(String.class, a -> a.name("firstName")
                .getter(Person::getFirstName)
                .setter(Person::setFirstName))
            .addAttribute(String.class, a -> a.name("lastName")
                .getter(Person::getLastName)
                .setter(Person::setLastName))
            .addAttribute(Integer.class, a -> a.name("age")
                .getter(Person::getAge)
                .setter(Person::setAge))
            .addAttribute(EnhancedType.documentOf(Address.class, TABLE_SCHEMA_ADDRESS), a -> a.name("mainAddress")
                .getter(Person::getMainAddress)
                .setter(Person::setMainAddress))
            .addAttribute(EnhancedType.listOf(String.class), a -> a.name("hobbies")
                .getter(Person::getHobbies)
                .setter(Person::setHobbies))
            .addAttribute(EnhancedType.mapOf(
                EnhancedType.of(String.class),
                // 1. Use mapping functionality of the Address table schema.
                EnhancedType.documentOf(Address.class, TABLE_SCHEMA_ADDRESS)), a -> a.name("addresses")
                .getter(Person::getAddresses)
                .setter(Person::setAddresses))
            .addAttribute(EnhancedType.listOf(
                // 2. Use mapping functionality of the PhoneNumber table schema.
                EnhancedType.documentOf(PhoneNumber.class, TABLE_SCHEMA_PHONENUMBER)), a -> a.name("phoneNumbers")
                .getter(Person::getPhoneNumbers)
                .setter(Person::setPhoneNumbers))
            .build();
```

## 複合型のプロジェクト属性
<a name="ddb-en-client-adv-features-nested-projection"></a>

`query()` および `scan()` メソッドでは、`addNestedAttributeToProject()` や `attributesToProject()` などのメソッドの呼び出しを使用して、結果で返される属性を指定できます。DynamoDB 拡張クライアント API は、リクエストが送信される前に Java メソッド呼び出しパラメータを[プロジェクション式](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.ProjectionExpressions.html)に変換します。

次の例では、`Person` テーブルに 2 つの項目を設定し、3 回のスキャンオペレーションを実行します。

1 回目のスキャンでは、結果を他のスキャンオペレーションと比較するために、テーブル内のすべての項目にアクセスします。

2 回目のスキャンでは、[https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/ScanEnhancedRequest.Builder.html#addNestedAttributeToProject(software.amazon.awssdk.enhanced.dynamodb.NestedAttributeName)](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/ScanEnhancedRequest.Builder.html#addNestedAttributeToProject(software.amazon.awssdk.enhanced.dynamodb.NestedAttributeName)) ビルダーメソッドを使用して `street` 属性値のみを返します。

3 回目のスキャンオペレーションでは、[https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/ScanEnhancedRequest.Builder.html#attributesToProject(java.lang.String...)](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/ScanEnhancedRequest.Builder.html#attributesToProject(java.lang.String...)) ビルダーメソッドを使用して第 1 レベルの属性のデータ、`hobbies` を返します。`hobbies` の属性タイプはリストです。個々のリスト項目にアクセスするには、リストに対して `get()` オペレーションを実行します。

```
        personDynamoDbTable = getDynamoDbEnhancedClient().table("Person", PERSON_TABLE_SCHEMA);
        PersonUtils.createPersonTable(personDynamoDbTable, getDynamoDbClient());
        // Use a utility class to add items to the Person table.
        List<Person> personList = PersonUtils.getItemsForCount(2);
        // This utility method performs a put against DynamoDB to save the instances in the list argument.
        PersonUtils.putCollection(getDynamoDbEnhancedClient(), personList, personDynamoDbTable);

        // The first scan logs all items in the table to compare to the results of the subsequent scans.
        final PageIterable<Person> allItems = personDynamoDbTable.scan();
        allItems.items().forEach(p ->
                // 1. Log what is in the table.
                logger.info(p.toString()));

        // Scan for nested attributes.
        PageIterable<Person> streetScanResult = personDynamoDbTable.scan(b -> b
                // Use the 'addNestedAttributeToProject()' or 'addNestedAttributesToProject()' to access data nested in maps in DynamoDB.
                .addNestedAttributeToProject(
                        NestedAttributeName.create("addresses", "work", "street")
                ));

        streetScanResult.items().forEach(p ->
                //2. Log the results of requesting nested attributes.
                logger.info(p.toString()));

        // Scan for a top-level list attribute.
        PageIterable<Person> hobbiesScanResult = personDynamoDbTable.scan(b -> b
                // Use the 'attributesToProject()' method to access first-level attributes.
                .attributesToProject("hobbies"));

        hobbiesScanResult.items().forEach((p) -> {
            // 3. Log the results of the request for the 'hobbies' attribute.
            logger.info(p.toString());
            // To access an item in a list, first get the parent attribute, 'hobbies', then access items in the list.
            String hobby = p.getHobbies().get(1);
            // 4. Log an item in the list.
            logger.info(hobby);
        });
```

```
// Logged results from comment line 1.
Person{id=2, firstName='first name 2', lastName='last name 2', age=11, addresses={work=Address{street='street 21', city='city 21', state='state 21', zipCode='33333'}, home=Address{street='street 2', city='city 2', state='state 2', zipCode='22222'}}, phoneNumbers=[PhoneNumber{type='home', number='222-222-2222'}, PhoneNumber{type='work', number='333-333-3333'}], hobbies=[hobby 2, hobby 21]}
Person{id=1, firstName='first name 1', lastName='last name 1', age=11, addresses={work=Address{street='street 11', city='city 11', state='state 11', zipCode='22222'}, home=Address{street='street 1', city='city 1', state='state 1', zipCode='11111'}}, phoneNumbers=[PhoneNumber{type='home', number='111-111-1111'}, PhoneNumber{type='work', number='222-222-2222'}], hobbies=[hobby 1, hobby 11]}

// Logged results from comment line 2.
Person{id=null, firstName='null', lastName='null', age=null, addresses={work=Address{street='street 21', city='null', state='null', zipCode='null'}}, phoneNumbers=null, hobbies=null}
Person{id=null, firstName='null', lastName='null', age=null, addresses={work=Address{street='street 11', city='null', state='null', zipCode='null'}}, phoneNumbers=null, hobbies=null}

// Logged results from comment lines 3 and 4.
Person{id=null, firstName='null', lastName='null', age=null, addresses=null, phoneNumbers=null, hobbies=[hobby 2, hobby 21]}
hobby 21
Person{id=null, firstName='null', lastName='null', age=null, addresses=null, phoneNumbers=null, hobbies=[hobby 1, hobby 11]}
hobby 11
```

**注記**  
その `attributesToProject()` メソッドが、プロジェクションする属性を追加する他のビルダーメソッドに続く場合は、`attributesToProject()` に渡された属性名のリストは他のすべての属性名を置き換えます。  
次のスニペット `ScanEnhancedRequest` のインスタンスで実行されたスキャンでは、ホビーデータのみが返されます。  

```
ScanEnhancedRequest lastOverwrites = ScanEnhancedRequest.builder()
        .addNestedAttributeToProject(
                NestedAttributeName.create("addresses", "work", "street"))
        .addAttributeToProject("firstName")
        // If the 'attributesToProject()' method follows other builder methods that add attributes for projection,
        // its list of attributes replace all previous attributes.
        .attributesToProject("hobbies")
        .build();
PageIterable<Person> hobbiesOnlyResult = personDynamoDbTable.scan(lastOverwrites);
hobbiesOnlyResult.items().forEach(p ->
        logger.info(p.toString()));

// Logged results.
Person{id=null, firstName='null', lastName='null', age=null, addresses=null, phoneNumbers=null, hobbies=[hobby 2, hobby 21]}
Person{id=null, firstName='null', lastName='null', age=null, addresses=null, phoneNumbers=null, hobbies=[hobby 1, hobby 11]}
```
以下のコード例では、最初に `attributesToProject()` メソッドを使用します。この順序付けでは、要求された他のすべての属性が保持されます。  

```
ScanEnhancedRequest attributesPreserved = ScanEnhancedRequest.builder()
        // Use 'attributesToProject()' first so that the method call does not replace all other attributes
        // that you want to project.
        .attributesToProject("firstName")
        .addNestedAttributeToProject(
                NestedAttributeName.create("addresses", "work", "street"))
        .addAttributeToProject("hobbies")
        .build();
PageIterable<Person> allAttributesResult = personDynamoDbTable.scan(attributesPreserved);
allAttributesResult.items().forEach(p ->
        logger.info(p.toString()));

// Logged results.
Person{id=null, firstName='first name 2', lastName='null', age=null, addresses={work=Address{street='street 21', city='null', state='null', zipCode='null'}}, phoneNumbers=null, hobbies=[hobby 2, hobby 21]}
Person{id=null, firstName='first name 1', lastName='null', age=null, addresses={work=Address{street='street 11', city='null', state='null', zipCode='null'}}, phoneNumbers=null, hobbies=[hobby 1, hobby 11]}
```

## 式で複合型を使用する
<a name="ddb-en-client-adv-features-nested-expressions"></a>

フィルター式や条件式などの式で複合型を使用するには、参照解除演算子を使用して複合型の構造をたどります。Object と Map の場合は `. (dot)` を使用し、List 要素の場合は `[n]` (要素のシーケンス番号を囲む角括弧) を使用します。Set の個々の要素を参照することはできませんが、 [`contains` 関数](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.OperatorsAndFunctions.html#Expressions.OperatorsAndFunctions.Functions)を使用できます。

次の例は、スキャンオペレーションで使用される 2 つのフィルター式を示しています。フィルター式は、結果に含める項目の一致条件を指定します。次の例では、前に示した `Person`、`Address`、および `PhoneNumber` クラスを使用しています。

```
    public void scanUsingFilterOfNestedAttr() {
        // The following is a filter expression for an attribute that is a map of Address objects.
        // By using this filter expression, the SDK returns Person objects that have an address
        // with 'mailing' as a key and 'MS2' for a state value.
        Expression addressFilter = Expression.builder()
                .expression("addresses.#type.#field = :value")
                .putExpressionName("#type", "mailing")
                .putExpressionName("#field", "state")
                .putExpressionValue(":value", AttributeValue.builder().s("MS2").build())
                .build();

        PageIterable<Person> addressFilterResults = personDynamoDbTable.scan(rb -> rb.
                filterExpression(addressFilter));
        addressFilterResults.items().stream().forEach(p -> logger.info("Person: {}", p));

        assert addressFilterResults.items().stream().count() == 1;


        // The following is a filter expression for an attribute that is a list of phone numbers.
        // By using this filter expression, the SDK returns Person objects whose second phone number
        // in the list has a type equal to 'cell'.
        Expression phoneFilter = Expression.builder()
                .expression("phoneNumbers[1].#type = :type")
                .putExpressionName("#type", "type")
                .putExpressionValue(":type", AttributeValue.builder().s("cell").build())
                .build();

        PageIterable<Person> phoneFilterResults = personDynamoDbTable.scan(rb -> rb
                .filterExpression(phoneFilter)
                .attributesToProject("id", "firstName", "lastName", "phoneNumbers")
        );

        phoneFilterResults.items().stream().forEach(p -> logger.info("Person: {}", p));

        assert phoneFilterResults.items().stream().count() == 1;
        assert phoneFilterResults.items().stream().findFirst().get().getPhoneNumbers().get(1).getType().equals("cell");
    }
```

### テーブルに入力されるヘルパーメソッド
<a name="nested-expressions-helper-method"></a>

```
    public static void populateDatabase() {
        Person person1 = new Person();
        person1.setId(1);
        person1.setFirstName("FirstName1");
        person1.setLastName("LastName1");

        Address billingAddr1 = new Address();
        billingAddr1.setState("BS1");
        billingAddr1.setCity("BillingTown1");

        Address mailing1 = new Address();
        mailing1.setState("MS1");
        mailing1.setCity("MailingTown1");

        person1.setAddresses(Map.of("billing", billingAddr1, "mailing", mailing1));

        PhoneNumber pn1_1 = new PhoneNumber();
        pn1_1.setType("work");
        pn1_1.setNumber("111-111-1111");

        PhoneNumber pn1_2 = new PhoneNumber();
        pn1_2.setType("home");
        pn1_2.setNumber("222-222-2222");

        List<PhoneNumber> phoneNumbers1 = List.of(pn1_1, pn1_2);
        person1.setPhoneNumbers(phoneNumbers1);

        personDynamoDbTable.putItem(person1);

        Person person2 = person1;
        person2.setId(2);
        person2.setFirstName("FirstName2");
        person2.setLastName("LastName2");

        Address billingAddress2 = billingAddr1;
        billingAddress2.setCity("BillingTown2");
        billingAddress2.setState("BS2");

        Address mailing2 = mailing1;
        mailing2.setCity("MailingTown2");
        mailing2.setState("MS2");

        person2.setAddresses(Map.of("billing", billingAddress2, "mailing", mailing2));

        PhoneNumber pn2_1 = new PhoneNumber();
        pn2_1.setType("work");
        pn2_1.setNumber("333-333-3333");

        PhoneNumber pn2_2 = new PhoneNumber();
        pn2_2.setType("cell");
        pn2_2.setNumber("444-444-4444");

        List<PhoneNumber> phoneNumbers2 = List.of(pn2_1, pn2_2);
        person2.setPhoneNumbers(phoneNumbers2);

        personDynamoDbTable.putItem(person2);
    }
```

### データベース内の項目の JSON 表現
<a name="nested-attributes-expression-json-items"></a>

```
{
 "id": 1,
 "addresses": {
  "billing": {
   "city": "BillingTown1",
   "state": "BS1",
   "street": null,
   "zipCode": null
  },
  "mailing": {
   "city": "MailingTown1",
   "state": "MS1",
   "street": null,
   "zipCode": null
  }
 },
 "firstName": "FirstName1",
 "lastName": "LastName1",
 "phoneNumbers": [
  {
   "number": "111-111-1111",
   "type": "work"
  },
  {
   "number": "222-222-2222",
   "type": "home"
  }
 ]
}

{
 "id": 2,
 "addresses": {
  "billing": {
   "city": "BillingTown2",
   "state": "BS2",
   "street": null,
   "zipCode": null
  },
  "mailing": {
   "city": "MailingTown2",
   "state": "MS2",
   "street": null,
   "zipCode": null
  }
 },
 "firstName": "FirstName2",
 "lastName": "LastName2",
 "phoneNumbers": [
  {
   "number": "333-333-3333",
   "type": "work"
  },
  {
   "number": "444-444-4444",
   "type": "cell"
  }
 ]
}
```

## 複合型を含む項目の更新
<a name="ddb-en-client-adv-features-nested-updates"></a>

複合型を含む項目を更新するには、2 つの基本的なアプローチがあります。
+ アプローチ 1: まず項目を取得し (`getItem` を使用)、オブジェクトを更新してから、`DynamoDbTable#updateItem` を呼び出します。
+ アプローチ 2: 項目を取得せずに新しいインスタンスを作成し、更新するプロパティを設定し、適切な値の [https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/IgnoreNullsMode.html](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/IgnoreNullsMode.html) を設定してインスタンスを `DynamoDbTable#updateItem` に送信します。このアプローチでは、更新する前に項目を取得する必要はありません。

このセクションに示す例では、前に示した `Person`、`Address`、および `PhoneNumber` クラスを使用します。

### 更新アプローチ 1: 取得してから更新する
<a name="ddb-en-client-adv-features-nested-updates-retreive"></a>

このアプローチを使用することで、更新時にデータが失われないようにします。DynamoDB 拡張クライアント API は、DynamoDB に保存された項目の属性を使用して、複合型の値を含めて Bean を再作成します。次に、ゲッターとセッターを使用して Bean を更新する必要があります。このアプローチの欠点は、最初に項目を取得する際に発生するコストです。

次の例は、更新する前に項目を最初に取得してもデータが失われないことを示しています。

```
    public void retrieveThenUpdateExample()  {
        // Assume that we ran this code yesterday.
        Person person = new Person();
        person.setId(1);
        person.setFirstName("FirstName");
        person.setLastName("LastName");

        Address mainAddress = new Address();
        mainAddress.setStreet("123 MyStreet");
        mainAddress.setCity("MyCity");
        mainAddress.setState("MyState");
        mainAddress.setZipCode("MyZipCode");
        person.setMainAddress(mainAddress);

        PhoneNumber homePhone = new PhoneNumber();
        homePhone.setNumber("1111111");
        homePhone.setType("HOME");
        person.setPhoneNumbers(List.of(homePhone));

        personDynamoDbTable.putItem(person);

        // Assume that we are running this code now.
        // First, retrieve the item
        Person retrievedPerson = personDynamoDbTable.getItem(Key.builder().partitionValue(1).build());

        // Make any updates.
        retrievedPerson.getMainAddress().setCity("YourCity");

        // Save the updated bean. 'updateItem' returns the bean as it appears after the update.
        Person updatedPerson = personDynamoDbTable.updateItem(retrievedPerson);

        // Verify for this example.
        Address updatedMainAddress = updatedPerson.getMainAddress();
        assert updatedMainAddress.getCity().equals("YourCity");
        assert updatedMainAddress.getState().equals("MyState"); // Unchanged.
        // The list of phone numbers remains; it was not set to null;
        assert updatedPerson.getPhoneNumbers().size() == 1;
    }
```

### 更新アプローチ 2: 最初に項目を取得せずに `IgnoreNullsMode` 列挙型を使用する
<a name="ddb-en-client-adv-features-nested-updates-nullmode"></a>

DynamoDB で項目を更新するには、更新するプロパティのみを持つ新しいオブジェクトを指定し、他の値を null のままにします。このアプローチでは、オブジェクトの null 値が SDK によってどのように処理されるかと、動作を制御する方法に注意する必要があります。

SDK で無視する null 値のプロパティを指定するには、[https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/UpdateItemEnhancedRequest.Builder.html](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/UpdateItemEnhancedRequest.Builder.html) を構築するときに `IgnoreNullsMode` 列挙型を指定します。列挙値のいずれかを使用する例として、次のスニペットは `IgnoreNullsMode.SCALAR_ONLY` モードを使用します。

```
// Create a new Person object to update the existing item in DynamoDB.
Person personForUpdate = new Person();
personForUpdate.setId(1);
personForUpdate.setFirstName("updatedFirstName");  // 'firstName' is a top scalar property.

Address addressForUpdate = new Address();
addressForUpdate.setCity("updatedCity");
personForUpdate.setMainAddress(addressForUpdate);

personDynamoDbTable.updateItem(r -> r
                .item(personForUpdate)
                .ignoreNullsMode(IgnoreNullsMode.SCALAR_ONLY));

/* With IgnoreNullsMode.SCALAR_ONLY provided, The SDK ignores all null properties. The SDK adds or replaces
the 'firstName' property with the provided value, "updatedFirstName". The SDK updates the 'city' value of
'mainAddress', as long as the 'mainAddress' attribute already exists in DynamoDB.

In the background, the SDK generates an update expression that it sends in the request to DynamoDB.
The following JSON object is a simplified version of what it sends. Notice that the SDK includes the paths
to 'mainAddress.city' and 'firstName' in the SET clause of the update expression. No null values in
'personForUpdate' are included.

{
  "TableName": "PersonTable",
  "Key": {
    "id": {
      "N": "1"
    }
  },
  "ReturnValues": "ALL_NEW",
  "UpdateExpression": "SET #mainAddress.#city = :mainAddress_city, #firstName = :firstName",
  "ExpressionAttributeNames": {
    "#city": "city",
    "#firstName": "firstName",
    "#mainAddress": "mainAddress"
  },
  "ExpressionAttributeValues": {
    ":firstName": {
      "S": "updatedFirstName"
    },
    ":mainAddress_city": {
      "S": "updatedCity"
    }
  }
}

Had we chosen 'IgnoreNullsMode.DEFAULT' instead of 'IgnoreNullsMode.SCALAR_ONLY', the SDK would have included
null values in the "ExpressionAttributeValues" section of the request as shown in the following snippet.

  "ExpressionAttributeValues": {
    ":mainAddress": {
      "M": {
        "zipCode": {
          "NULL": true
        },
        "city": {
          "S": "updatedCity"
        },
        "street": {
          "NULL": true
        },
        "state": {
          "NULL": true
        }
      }
    },
    ":firstName": {
      "S": "updatedFirstName"
    }
  }
*/
```

[更新式](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.UpdateExpressions.html)の詳細については、「Amazon DynamoDB デベロッパーガイド」を参照してください。

#### `IgnoreNullsMode` オプションの説明
<a name="ignore-nulls-mode-descriptions"></a>
+ `IgnoreNullsMode.SCALAR_ONLY` - この設定を使用して、任意のレベルでスカラー属性を更新します。SDK は、null 以外のスカラー属性のみを DynamoDB に送信する更新ステートメントを作成します。SDK は、Bean または Map の null 値のスカラー属性を無視し、DynamoDB に保存された値を保持します。

  Map または Bean のスカラー属性を更新する場合、Map は DynamoDB に既に存在している必要があります。DynamoDB のオブジェクトにまだ存在しないオブジェクトに Map または Bean を追加すると、「*更新式で指定されたドキュメントパスが更新に対して無効です*」というメッセージと `DynamoDbException` が表示されます。属性を更新する前に、 `MAPS_ONLY` モードを使用して DynamoDB に Bean または Map を追加する必要があります。
+ `IgnoreNullsMode.MAPS_ONLY` - この設定を使用して、 Bean または Map プロパティを追加または置き換えます。SDK は、オブジェクトで提供される Map または Bean を置き換えるか、追加します。オブジェクト内の null の Bean または Map は無視され、DynamoDB に存在する Map が保持されます。
+ `IgnoreNullsMode.DEFAULT` - この設定では、SDK が null 値を無視することはありません。すべてのレベルの null のスカラー属性は、null に更新されます。SDK は、オブジェクト内の null 値の Bean、Map、List、または Set プロパティを DynamoDB で null に更新します。このモードを使用する場合、またはデフォルトモードであるためモードを指定しない場合、更新用のオブジェクトで提供されている値が DynamoDB で null に設定されないように、まず項目を取得する必要があります。ただし、値を null に設定することが意図されている場合は除きます。

すべてのモードで、null 以外の List または Set を持つオブジェクトを `updateItem` に提供すると、List または Set は DynamoDB に保存されます。

#### モードを使用する理由
<a name="ddb-en-client-adv-features-nested-updates-nullmodes-why"></a>

Bean または Map のあるオブジェクトを `updateItem` メソッドに渡すと、SDK は Bean のプロパティ値 (または Map 内のエントリ値) を使用して項目を更新するか、または Bean/Map 全体で DynamoDB に保存されたものを置き換える必要があるかを認識できません。

最初に項目を取得することを示した前の例から、取得なしで `mainAddress` の `city` 属性を更新してみましょう。

```
/* The retrieval example saved the Person object with a 'mainAddress' property whose 'city' property value is "MyCity".
/* Note that we create a new Person with only the necessary information to update the city value
of the mainAddress. */
Person personForUpdate = new Person();
personForUpdate.setId(1);
// The update we want to make changes the city.
Address mainAddressForUpdate = new Address();
mainAddressForUpdate.setCity("YourCity");
personForUpdate.setMainAddress(mainAddressForUpdate);

// Lets' try the following:
Person updatedPerson = personDynamoDbTable.updateItem(personForUpdate);
/*
 Since we haven't retrieved the item, we don't know if the 'mainAddress' property
 already exists, so what update expression should the SDK generate?

A) Should it replace or add the 'mainAddress' with the provided object (setting all attributes to null other than city)
   as shown in the following simplified JSON?

      {
        "TableName": "PersonTable",
        "Key": {
          "id": {
            "N": "1"
          }
        },
        "ReturnValues": "ALL_NEW",
        "UpdateExpression": "SET #mainAddress = :mainAddress",
        "ExpressionAttributeNames": {
          "#mainAddress": "mainAddress"
        },
        "ExpressionAttributeValues": {
          ":mainAddress": {
            "M": {
              "zipCode": {
                "NULL": true
              },
              "city": {
                "S": "YourCity"
              },
              "street": {
                "NULL": true
              },
              "state": {
                "NULL": true
              }
            }
          }
        }
      }
 
B) Or should it update only the 'city' attribute of an existing 'mainAddress' as shown in the following simplified JSON?

      {
        "TableName": "PersonTable",
        "Key": {
          "id": {
            "N": "1"
          }
        },
        "ReturnValues": "ALL_NEW",
        "UpdateExpression": "SET #mainAddress.#city = :mainAddress_city",
        "ExpressionAttributeNames": {
          "#city": "city",
          "#mainAddress": "mainAddress"
        },
        "ExpressionAttributeValues": {
          ":mainAddress_city": {
            "S": "YourCity"
          }
        }
      }

However, assume that we don't know if the 'mainAddress' already exists. If it doesn't exist, the SDK would try to update 
an attribute of a non-existent map, which results in an exception.

In this particular case, we would likely select option B (SCALAR_ONLY) to retain the other values of the 'mainAddress'.
*/
```

次の 2 つの例は、`MAPS_ONLY` と `SCALAR_ONLY` の列挙値の使用を示しています。`MAPS_ONLY` は Map を追加し、`SCALAR_ONLY` は Map を更新します。

##### `IgnoreNullsMode.MAPS_ONLY` の例
<a name="scalar-only-example"></a>

```
    public void mapsOnlyModeExample() {
        // Assume that we ran this code yesterday.
        Person person = new Person();
        person.setId(1);
        person.setFirstName("FirstName");

        personDynamoDbTable.putItem(person);

        // Assume that we are running this code now.

        /* Note that we create a new Person with only the necessary information to update the city value
        of the mainAddress. */
        Person personForUpdate = new Person();
        personForUpdate.setId(1);
        // The update we want to make changes the city.
        Address mainAddressForUpdate = new Address();
        mainAddressForUpdate.setCity("YourCity");
        personForUpdate.setMainAddress(mainAddressForUpdate);


        Person updatedPerson = personDynamoDbTable.updateItem(r -> r
                .item(personForUpdate)
                .ignoreNullsMode(IgnoreNullsMode.MAPS_ONLY)); // Since the mainAddress property does not exist, use MAPS_ONLY mode.
        assert updatedPerson.getMainAddress().getCity().equals("YourCity");
        assert updatedPerson.getMainAddress().getState() == null;
    }
```

##### `IgnoreNullsMode.SCALAR_ONLY example`
<a name="maps-only-example"></a>

```
    public void scalarOnlyExample() {
        // Assume that we ran this code yesterday.
        Person person = new Person();
        person.setId(1);
        Address mainAddress = new Address();
        mainAddress.setCity("MyCity");
        mainAddress.setState("MyState");
        person.setMainAddress(mainAddress);

        personDynamoDbTable.putItem(person);

        // Assume that we are running this code now.

        /* Note that we create a new Person with only the necessary information to update the city value
        of the mainAddress. */
        Person personForUpdate = new Person();
        personForUpdate.setId(1);
        // The update we want to make changes the city.
        Address mainAddressForUpdate = new Address();
        mainAddressForUpdate.setCity("YourCity");
        personForUpdate.setMainAddress(mainAddressForUpdate);

        Person updatedPerson = personDynamoDbTable.updateItem(r -> r
                .item(personForUpdate)
                .ignoreNullsMode(IgnoreNullsMode.SCALAR_ONLY)); // SCALAR_ONLY mode ignores null properties in the in mainAddress.
        assert updatedPerson.getMainAddress().getCity().equals("YourCity");
        assert updatedPerson.getMainAddress().getState().equals("MyState"); // The state property remains the same.
    }
```

モードごとに無視される null 値を確認するには、次の表を参照してください。Bean や Map を使用する場合を除き、多くの場合は `SCALAR_ONLY` と `MAPS_ONLY` のいずれかを使用できます。


**各モードで、 `updateItem` に渡されたオブジェクト内のどの null 値プロパティが SDK によって無視されますか?**  

| プロパティの型 | SCALAR\$1ONLY モードの場合 | MAPS\$1ONLY モードの場合 | DEFAULT モードの場合 | 
| --- | --- | --- | --- | 
| 上位スカラー | はい  | あり | なし | 
| Bean または Map | はい  | あり | なし | 
| Bean または Map エントリのスカラー値 | あり 1 | なし2 | いいえ | 
| List または Set | はい  | あり | なし | 

1これは、Map が既に DynamoDB に存在することを前提としています。更新のためにオブジェクトで指定した Bean または Map のスカラー値 (null または null 以外) には、値へのパスが DynamoDB に存在する必要があります。SDK は、リクエストを送信する前に `. (dot)` 参照解除演算子を使用して、属性へのパスを作成します。

2`MAPS_ONLY` モードを使用して Bean または Map を完全に置き換えたり追加したりするため、Bean または Map 内のすべての null 値は DynamoDB に保存された Map に保持されます。

# `@DynamoDbPreserveEmptyObject` で空のオブジェクトを保存します。
<a name="ddb-en-client-adv-features-empty"></a>

空のオブジェクトを含む Bean を Amazon DynamoDB に保存し、取得時に SDK に空のオブジェクトを再作成させたい場合は、内部 Bean のゲッターに `@DynamoDbPreserveEmptyObject` の注釈を付けます。

注釈の仕組みを説明するために、コード例では次の 2 つの bean を使用しています。

## 例: Bean
<a name="ddb-en-client-adv-features-empty-ex1"></a>

次のデータクラスには 2 つの `InnerBean` フィールドがあります。getter メソッド、`getInnerBeanWithoutAnno()` には `@DynamoDbPreserveEmptyObject` という注釈が付いていません。`getInnerBeanWithAnno()` メソッドには注釈が付けられています。

```
@DynamoDbBean
public class MyBean {

    private String id;
    private String name;
    private InnerBean innerBeanWithoutAnno;
    private InnerBean innerBeanWithAnno;

    @DynamoDbPartitionKey
    public String getId() { return id; }
    public void setId(String id) { this.id = id; }

    public String getName() { return name; }
    public void setName(String name) { this.name = name; }

    public InnerBean getInnerBeanWithoutAnno() { return innerBeanWithoutAnno; }
    public void setInnerBeanWithoutAnno(InnerBean innerBeanWithoutAnno) { this.innerBeanWithoutAnno = innerBeanWithoutAnno; }

    @DynamoDbPreserveEmptyObject
    public InnerBean getInnerBeanWithAnno() { return innerBeanWithAnno; }
    public void setInnerBeanWithAnno(InnerBean innerBeanWithAnno) { this.innerBeanWithAnno = innerBeanWithAnno; }

    @Override
    public String toString() {
        return new StringJoiner(", ", MyBean.class.getSimpleName() + "[", "]")
                .add("innerBeanWithoutAnno=" + innerBeanWithoutAnno)
                .add("innerBeanWithAnno=" + innerBeanWithAnno)
                .add("id='" + id + "'")
                .add("name='" + name + "'")
                .toString();
    }
}
```

以下の `InnerBean` クラスのインスタンスは`MyBean` フィールドであり、サンプルコードで空のオブジェクトとして初期化されます。

```
@DynamoDbBean
public class InnerBean {

    private String innerBeanField;

    public String getInnerBeanField() {
        return innerBeanField;
    }

    public void setInnerBeanField(String innerBeanField) {
        this.innerBeanField = innerBeanField;
    }

    @Override
    public String toString() {
        return "InnerBean{" +
                "innerBeanField='" + innerBeanField + '\'' +
                '}';
    }
}
```

次のコード例では、初期化された内部 Bean を含む `MyBean` オブジェクトを DynamoDB に保存し、その項目を取得します。ログ出力には、`innerBeanWithoutAnno` は初期化されておらず、`innerBeanWithAnno` が作成されたことが示されています。

```
    public MyBean preserveEmptyObjectAnnoUsingGetItemExample(DynamoDbTable<MyBean> myBeanTable) {
        // Save an item to DynamoDB.
        MyBean bean = new MyBean();
        bean.setId("1");
        bean.setInnerBeanWithoutAnno(new InnerBean());   // Instantiate the inner bean.
        bean.setInnerBeanWithAnno(new InnerBean());      // Instantiate the inner bean.
        myBeanTable.putItem(bean);

        GetItemEnhancedRequest request = GetItemEnhancedRequest.builder()
                .key(Key.builder().partitionValue("1").build())
                .build();
        MyBean myBean = myBeanTable.getItem(request);

        logger.info(myBean.toString());
        // Output 'MyBean[innerBeanWithoutAnno=null, innerBeanWithAnno=InnerBean{innerBeanField='null'}, id='1', name='null']'.

        return myBean;
    }
```

## 代わりの静的スキーマ
<a name="ddb-en-client-adv-features-empty-ex1-static"></a>

Bean の注釈の代わりに、以下の `StaticTableSchema` バージョンのテーブルスキーマを使用できます。

```
    public static TableSchema<MyBean> buildStaticSchemas() {

        StaticTableSchema<InnerBean> innerBeanStaticTableSchema =
                StaticTableSchema.builder(InnerBean.class)
                        .newItemSupplier(InnerBean::new)
                        .addAttribute(String.class, a -> a.name("innerBeanField")
                                .getter(InnerBean::getInnerBeanField)
                                .setter(InnerBean::setInnerBeanField))
                        .build();

        return StaticTableSchema.builder(MyBean.class)
                .newItemSupplier(MyBean::new)
                .addAttribute(String.class, a -> a.name("id")
                        .getter(MyBean::getId)
                        .setter(MyBean::setId)
                        .addTag(primaryPartitionKey()))
                .addAttribute(String.class, a -> a.name("name")
                        .getter(MyBean::getName)
                        .setter(MyBean::setName))
                .addAttribute(EnhancedType.documentOf(InnerBean.class,
                                innerBeanStaticTableSchema),
                        a -> a.name("innerBean1")
                                .getter(MyBean::getInnerBeanWithoutAnno)
                                .setter(MyBean::setInnerBeanWithoutAnno))
                .addAttribute(EnhancedType.documentOf(InnerBean.class,
                                innerBeanStaticTableSchema,
                                b -> b.preserveEmptyObject(true)),
                        a -> a.name("innerBean2")
                                .getter(MyBean::getInnerBeanWithAnno)
                                .setter(MyBean::setInnerBeanWithAnno))
                .build();
    }
```

# ネストされたオブジェクトの NULL 属性の保存を避ける
<a name="ddb-en-client-adv-features-ignore-null"></a>

`@DynamoDbIgnoreNulls` 注釈を適用することで、データクラスオブジェクトを DynamoDB に保存するときに、ネストされたオブジェクトの null 属性をスキップできます。これとは対照的に、NULL 値を持つ最上位の属性はデータベースに保存されません。

注釈の仕組みを説明するために、コード例では次の 2 つの Bean を使用しています。

## 例: Bean
<a name="ddb-en-client-adv-features-ignore-null-ex1"></a>

次のデータクラスには 2 つの `InnerBean` フィールドがあります。getter メソッド、`getInnerBeanWithoutAnno()` には注釈が付けられていません。`getInnerBeanWithIgnoreNullsAnno()` メソッドには `@DynamoDbIgnoreNulls` という注釈が付けられています。

```
@DynamoDbBean
public class MyBean {

    private String id;
    private String name;
    private InnerBean innerBeanWithoutAnno;
    private InnerBean innerBeanWithIgnoreNullsAnno;

    @DynamoDbPartitionKey
    public String getId() { return id; }
    public void setId(String id) { this.id = id; }

    public String getName() { return name; }
    public void setName(String name) { this.name = name; }

    public InnerBean getInnerBeanWithoutAnno() { return innerBeanWithoutAnno; }
    public void setInnerBeanWithoutAnno(InnerBean innerBeanWithoutAnno) { this.innerBeanWithoutAnno = innerBeanWithoutAnno; }

    @DynamoDbIgnoreNulls
    public InnerBean getInnerBeanWithIgnoreNullsAnno() { return innerBeanWithIgnoreNullsAnno; }
    public void setInnerBeanWithIgnoreNullsAnno(InnerBean innerBeanWithAnno) { this.innerBeanWithIgnoreNullsAnno = innerBeanWithAnno; }

    @Override
    public String toString() {
        return new StringJoiner(", ", MyBean.class.getSimpleName() + "[", "]")
                .add("innerBeanWithoutAnno=" + innerBeanWithoutAnno)
                .add("innerBeanWithIgnoreNullsAnno=" + innerBeanWithIgnoreNullsAnno)
                .add("id='" + id + "'")
                .add("name='" + name + "'")
                .toString();
    }
}
```

次の `InnerBean` クラスのインスタンスは `MyBean` のフィールドであり、次のコード例で使用されています。

```
@DynamoDbBean
public class InnerBean {

    private String innerBeanFieldString;
    private Integer innerBeanFieldInteger;

    public String getInnerBeanFieldString() { return innerBeanFieldString; }
    public void setInnerBeanFieldString(String innerBeanFieldString) { this.innerBeanFieldString = innerBeanFieldString; }

    public Integer getInnerBeanFieldInteger() { return innerBeanFieldInteger; }
    public void setInnerBeanFieldInteger(Integer innerBeanFieldInteger) { this.innerBeanFieldInteger = innerBeanFieldInteger; }

    @Override
    public String toString() {
        return new StringJoiner(", ", InnerBean.class.getSimpleName() + "[", "]")
                .add("innerBeanFieldString='" + innerBeanFieldString + "'")
                .add("innerBeanFieldInteger=" + innerBeanFieldInteger)
                .toString();
    }
}
```

次のコード例では、`InnerBean` オブジェクトを作成し、その 2 つの属性のうち 1 つだけに値を設定します。

```
    public void ignoreNullsAnnoUsingPutItemExample(DynamoDbTable<MyBean> myBeanTable) {
        // Create an InnerBean object and give only one attribute a value.
        InnerBean innerBeanOneAttributeSet = new InnerBean();
        innerBeanOneAttributeSet.setInnerBeanFieldInteger(200);

        // Create a MyBean instance and use the same InnerBean instance both for attributes.
        MyBean bean = new MyBean();
        bean.setId("1");
        bean.setInnerBeanWithoutAnno(innerBeanOneAttributeSet);
        bean.setInnerBeanWithIgnoreNullsAnno(innerBeanOneAttributeSet);

        Map<String, AttributeValue> itemMap = myBeanTable.tableSchema().itemToMap(bean, true);
        logger.info(itemMap.toString());
        // Log the map that is sent to the database.
        // {innerBeanWithIgnoreNullsAnno=AttributeValue(M={innerBeanFieldInteger=AttributeValue(N=200)}), id=AttributeValue(S=1), innerBeanWithoutAnno=AttributeValue(M={innerBeanFieldInteger=AttributeValue(N=200), innerBeanFieldString=AttributeValue(NUL=true)})}
        
        // Save the MyBean object to the table.
        myBeanTable.putItem(bean);
    }
```

DynamoDB に送信される低レベルのデータを視覚化するために、コードは `MyBean` オブジェクトを保存する前に属性マップをログ記録します。

ログ記録された出力を見ると、`innerBeanWithIgnoreNullsAnno` が 1 つの属性を出力していることが分かります。

```
innerBeanWithIgnoreNullsAnno=AttributeValue(M={innerBeanFieldInteger=AttributeValue(N=200)})
```

`innerBeanWithoutAnno` インスタンスは 2 つの属性を出力します。1 つの属性の値は 200 で、もう 1 つは NULL 値の属性です。

```
innerBeanWithoutAnno=AttributeValue(M={innerBeanFieldInteger=AttributeValue(N=200), innerBeanFieldString=AttributeValue(NUL=true)})
```

## 属性マップの JSON 表現
<a name="ddb-en-client-adv-features-ignore-null-ex2"></a>

次の JSON 表現を使用すると、DynamoDB に保存されたデータを簡単に確認できます。

```
{
  "id": {
    "S": "1"
  },
  "innerBeanWithIgnoreNullsAnno": {
    "M": {
      "innerBeanFieldInteger": {
        "N": "200"
      }
    }
  },
  "innerBeanWithoutAnno": {
    "M": {
      "innerBeanFieldInteger": {
        "N": "200"
      },
      "innerBeanFieldString": {
        "NULL": true
      }
    }
  }
}
```

## 代わりの静的スキーマ
<a name="ddb-en-client-adv-features-empty-ex1-static"></a>

次の `StaticTableSchema` バージョンのテーブルスキーマをデータクラス注釈の代わりに使用できます。

```
public static TableSchema<MyBean> buildStaticSchemas() {

    StaticTableSchema<InnerBean> innerBeanStaticTableSchema =
        StaticTableSchema.builder(InnerBean.class)
            .newItemSupplier(InnerBean::new)
            .addAttribute(String.class, a -> a.name("innerBeanFieldString")
                .getter(InnerBean::getInnerBeanFieldString)
                .setter(InnerBean::setInnerBeanFieldString))
            .addAttribute(Integer.class, a -> a.name("innerBeanFieldInteger")
                .getter(InnerBean::getInnerBeanFieldInteger)
                .setter(InnerBean::setInnerBeanFieldInteger))
            .build();

    return StaticTableSchema.builder(MyBean.class)
        .newItemSupplier(MyBean::new)
        .addAttribute(String.class, a -> a.name("id")
            .getter(MyBean::getId)
            .setter(MyBean::setId)
            .addTag(primaryPartitionKey()))
        .addAttribute(String.class, a -> a.name("name")
            .getter(MyBean::getName)
            .setter(MyBean::setName))
        .addAttribute(EnhancedType.documentOf(InnerBean.class,
                innerBeanStaticTableSchema),
            a -> a.name("innerBeanWithoutAnno")
                .getter(MyBean::getInnerBeanWithoutAnno)
                .setter(MyBean::setInnerBeanWithoutAnno))
        .addAttribute(EnhancedType.documentOf(InnerBean.class,
                innerBeanStaticTableSchema,
                b -> b.ignoreNulls(true)),
            a -> a.name("innerBeanWithIgnoreNullsAnno")
                .getter(MyBean::getInnerBeanWithIgnoreNullsAnno)
                .setter(MyBean::setInnerBeanWithIgnoreNullsAnno))
        .build();
}
```

# DynamoDB 用の拡張ドキュメント API を使用して JSON ドキュメントを操作する
<a name="ddb-en-client-doc-api"></a>

の[拡張ドキュメント API](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/document/package-summary.html) AWS SDK for Java 2.x は、固定スキーマを持たないドキュメント指向のデータで動作するように設計されています。ただし、カスタムクラスを使用して個々の属性をマップすることもできます。

 拡張ドキュメント API は、v1.x の[ドキュメント API](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/dynamodbv2/document/DynamoDB.html) AWS SDK for Java の後継です。

**Contents**
+ [拡張ドキュメント API の使用を開始する](ddb-en-client-doc-api-steps.md)
  + [`DocumentTableSchema` および `DynamoDbTable` を作成する](ddb-en-client-doc-api-steps.md#ddb-en-client-doc-api-steps-createschema)
+ [拡張ドキュメントを構築する](ddb-en-client-doc-api-steps-create-ed.md)
  + [JSON 文字列から構築する](ddb-en-client-doc-api-steps-create-ed.md#ddb-en-client-doc-api-steps-create-ed-fromJson)
  + [個々の要素から構築する](ddb-en-client-doc-api-steps-create-ed.md#ddb-en-client-doc-api-steps-create-ed-fromparts)
+ [CRUD オペレーションを実行する](ddb-en-client-doc-api-steps-use.md)
+ [拡張ドキュメント属性にはカスタムオブジェクトとしてアクセスできます。](ddb-en-client-doc-api-convert.md)
+ [DynamoDB を使用せずに `EnhancedDocument` を使用する](ddb-en-client-doc-api-standalone.md)

# 拡張ドキュメント API の使用を開始する
<a name="ddb-en-client-doc-api-steps"></a>

拡張ドキュメント API には、DynamoDB 拡張クライアント API に必要なものと同じ[依存関係](ddb-en-client-getting-started.md#ddb-en-client-gs-dep)が必要です。また、このトピックの冒頭で示したように、[`DynamoDbEnhancedClient` インスタンス](ddb-en-client-getting-started-dynamodbTable.md#ddb-en-client-getting-started-dynamodbTable-eclient)も必要です。

Enhanced Document API は のバージョン 2.20.3 でリリースされたため AWS SDK for Java 2.x、そのバージョン以降が必要です。

## `DocumentTableSchema` および `DynamoDbTable` を作成する
<a name="ddb-en-client-doc-api-steps-createschema"></a>

拡張ドキュメント API を使用して DynamoDB テーブルに対してコマンドを呼び出すには、テーブルをクライアント側の [DynamoDbTable<EnhancedDocument>](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/DynamoDbTable.html) リソースオブジェクトに関連付けます。

拡張クライアントの `table()` メソッドは `DynamoDbTable<EnhancedDocument>` インスタンスを作成し、DynamoDB テーブル名と `DocumentTableSchema` のパラメータを必要とします。

[DocumentTableSchema](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/document/DocumentTableSchema.html) のビルダーには、プライマリインデックスキーと 1 つ以上の属性コンバータープロバイダーが必要です。この `AttributeConverterProvider.defaultProvider()` メソッドは[デフォルトタイプ](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/internal/converter/attribute/package-summary.html)のコンバーターを提供します。カスタム属性コンバータープロバイダーを提供する場合でも、指定する必要があります。オプションのセカンダリインデックスキーをビルダーに追加できます。

次のコードスニペットは、スキーマレス `person` オブジェクトを格納する DynamoDB `EnhancedDocument` テーブルのクライアント側表現を生成するコードを示しています。

```
DynamoDbTable<EnhancedDocument> documentDynamoDbTable = 
                enhancedClient.table("person",
                        TableSchema.documentSchemaBuilder()
                            // Specify the primary key attributes.
                            .addIndexPartitionKey(TableMetadata.primaryIndexName(),"id", AttributeValueType.S)
                            .addIndexSortKey(TableMetadata.primaryIndexName(), "lastName", AttributeValueType.S)
                            // Specify attribute converter providers. Minimally add the default one.
                            .attributeConverterProviders(AttributeConverterProvider.defaultProvider())
                            .build());
                                                         
// Call documentTable.createTable() if "person" does not exist in DynamoDB.
// createTable() should be called only one time.
```

このセクション全体で使用される `person` オブジェクトの JSON 表現を以下に示します。

### JSON `person` オブジェクト
<a name="ddb-en-client-doc-api-steps-createschema-obj"></a>

```
{
  "id": 1,
  "firstName": "Richard",
  "lastName": "Roe",
  "age": 25,
  "addresses":
    {
      "home": {
        "zipCode": "00000",
        "city": "Any Town",
        "state": "FL",
        "street": "123 Any Street"
      },
      "work": {
        "zipCode": "00001",
        "city": "Anywhere",
        "state": "FL",
        "street": "100 Main Street"
      }
    },
  "hobbies": [
    "Hobby 1",
    "Hobby 2"
  ],
  "phoneNumbers": [
    {
      "type": "Home",
      "number": "555-0100"
    },
    {
      "type": "Work",
      "number": "555-0119"
    }
  ]
}
```

# 拡張ドキュメントを構築する
<a name="ddb-en-client-doc-api-steps-create-ed"></a>

`[EnhancedDocument](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/document/EnhancedDocument.html)` は、ネストされた属性を持ち、複雑な構造を持つドキュメントタイプのオブジェクトを表します。`EnhancedDocument` には、`DocumentTableSchema` に指定されたプライマリキー属性と一致する最上位の属性が必要です。残りの内容は任意で、最上位の属性だけでなく、深くネストされた属性で構成することもできます。

`EnhancedDocument` インスタンスを作成するには、複数の方法で要素を追加できるビルダーを使用します。

## JSON 文字列から構築する
<a name="ddb-en-client-doc-api-steps-create-ed-fromJson"></a>

JSON 文字列を使用して、1 つのメソッド呼び出しに `EnhancedDocument` を構築できます。次のスニペットは、`jsonPerson()` ヘルパーメソッドから返された JSON 文字列から `EnhancedDocument` を作成します。この `jsonPerson()` メソッドは、前に示した [person オブジェクト](ddb-en-client-doc-api-steps.md#ddb-en-client-doc-api-steps-createschema-obj)の JSON 文字列バージョンを返します。

```
EnhancedDocument document = 
        EnhancedDocument.builder()
                        .json( jsonPerson() )
                        .build());
```

## 個々の要素から構築する
<a name="ddb-en-client-doc-api-steps-create-ed-fromparts"></a>

また、ビルダーのタイプセーフメソッドを使用して個々のコンポーネントから `EnhancedDocument` インスタンスを構築することもできます。

次の例では、前の例の JSON 文字列から作成された拡張ドキュメントと同様の `person` 拡張ドキュメントを作成します。

```
        /* Define the shape of an address map whose JSON representation looks like the following.
           Use 'addressMapEnhancedType' in the following EnhancedDocument.builder() to simplify the code.
           "home": {
             "zipCode": "00000",
             "city": "Any Town",
             "state": "FL",
             "street": "123 Any Street"
           }*/
        EnhancedType<Map<String, String>> addressMapEnhancedType =
                EnhancedType.mapOf(EnhancedType.of(String.class), EnhancedType.of(String.class));


        //  Use the builder's typesafe methods to add elements to the enhanced document.
        EnhancedDocument personDocument = EnhancedDocument.builder()
                .putNumber("id", 50)
                .putString("firstName", "Shirley")
                .putString("lastName", "Rodriguez")
                .putNumber("age", 53)
                .putNull("nullAttribute")
                .putJson("phoneNumbers", phoneNumbersJSONString())
                /* Add the map of addresses whose JSON representation looks like the following.
                        {
                          "home": {
                            "zipCode": "00000",
                            "city": "Any Town",
                            "state": "FL",
                            "street": "123 Any Street"
                          }
                        } */
                .putMap("addresses", getAddresses(), EnhancedType.of(String.class), addressMapEnhancedType)
                .putList("hobbies", List.of("Theater", "Golf"), EnhancedType.of(String.class))
                .build();
```

### ヘルパーメソッド
<a name="ddb-en-client-doc-api-steps-use-fromparts-helpers"></a>

```
    private static String phoneNumbersJSONString() {
        return "  [" +
                "    {" +
                "      \"type\": \"Home\"," +
                "      \"number\": \"555-0140\"" +
                "    }," +
                "    {" +
                "      \"type\": \"Work\"," +
                "      \"number\": \"555-0155\"" +
                "    }" +
                "  ]";
    }

    private static Map<String, Map<String, String>> getAddresses() {
        return Map.of(
                "home", Map.of(
                        "zipCode", "00002",
                        "city", "Any Town",
                        "state", "ME",
                        "street", "123 Any Street"));

    }
```

# CRUD オペレーションを実行する
<a name="ddb-en-client-doc-api-steps-use"></a>

`EnhancedDocument` インスタンスを定義したら、DynamoDB テーブルに保存できます。次のコードスニペットでは、個々の要素から作成された [personDocument](ddb-en-client-doc-api-steps-create-ed.md#ddb-en-client-doc-api-steps-create-ed-fromparts) を使用しています。

```
documentDynamoDbTable.putItem(personDocument);
```

DynamoDB から拡張ドキュメントインスタンスを読み取った後、`personDocument` から保存されたデータにアクセスする次のコードスニペットに示すように、ゲッターを使用して個々の属性値を抽出することができます。または、サンプルコードの最後の部分に示されているように、コンテンツ全体を JSON 文字列に抽出することもできます。

```
        // Read the item.
        EnhancedDocument personDocFromDb = documentDynamoDbTable.getItem(Key.builder().partitionValue(50).build());

        // Access top-level attributes.
        logger.info("Name: {} {}", personDocFromDb.getString("firstName"), personDocFromDb.getString("lastName"));
        // Name: Shirley Rodriguez

        // Typesafe access of a deeply nested attribute. The addressMapEnhancedType shown previously defines the shape of an addresses map.
        Map<String, Map<String, String>> addresses = personDocFromDb.getMap("addresses", EnhancedType.of(String.class), addressMapEnhancedType);
        addresses.keySet().forEach(k -> logger.info(addresses.get(k).toString()));
        // {zipCode=00002, city=Any Town, street=123 Any Street, state=ME}

        // Alternatively, work with AttributeValue types checking along the way for deeply nested attributes.
        Map<String, AttributeValue> addressesMap = personDocFromDb.getMapOfUnknownType("addresses");
        addressesMap.keySet().forEach((String k) -> {
            logger.info("Looking at data for [{}] address", k);
            // Looking at data for [home] address
            AttributeValue value = addressesMap.get(k);
            AttributeValue cityValue = value.m().get("city");
            if (cityValue != null) {
                logger.info(cityValue.s());
                // Any Town
            }
        });

        List<AttributeValue> phoneNumbers = personDocFromDb.getListOfUnknownType("phoneNumbers");
        phoneNumbers.forEach((AttributeValue av) -> {
            if (av.hasM()) {
                AttributeValue type = av.m().get("type");
                if (type.s() != null) {
                    logger.info("Type of phone: {}", type.s());
                    // Type of phone: Home
                    // Type of phone: Work
                }
            }
        });

        String jsonPerson = personDocFromDb.toJson();
        logger.info(jsonPerson);
        // {"firstName":"Shirley","lastName":"Rodriguez","addresses":{"home":{"zipCode":"00002","city":"Any Town","street":"123 Any Street","state":"ME"}},"hobbies":["Theater","Golf"],
        //     "id":50,"nullAttribute":null,"age":53,"phoneNumbers":[{"number":"555-0140","type":"Home"},{"number":"555-0155","type":"Work"}]}
```

`EnhancedDocument` インスタンスは、マッピングされたデータクラスの代わりに、`[DynamoDbTable](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/DynamoDbTable.html)` または [DynamoDbEnhancedClient](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/DynamoDbEnhancedClient.html) の任意のメソッドで使用できます。

# 拡張ドキュメント属性にはカスタムオブジェクトとしてアクセスできます。
<a name="ddb-en-client-doc-api-convert"></a>

拡張ドキュメント API では、スキーマレス構造の属性を読み書きするための API を提供するだけでなく、カスタムクラスのインスタンスとの間で属性を変換できます。

拡張ドキュメント API は、DynamoDB 拡張クライアント API の一部として[コントロール属性変換](ddb-en-client-adv-features-conversion.md)セクションに表示された `AttributeConverterProvider` と `AttributeConverter` を使用します。

次の例では、`CustomAttributeConverterProvider` をネストされた `AddressConverter` クラスとともに使用して `Address` オブジェクトを変換します。

この例は、クラスからのデータと、必要に応じて構築された構造からのデータを組み合わせることができることを示しています。この例はまた、カスタムクラスはネストされた構造のどのレベルでも使用できることを示しています。この例の `Address` オブジェクトはマップで使用される値です。

```
    public static void attributeToAddressClassMappingExample(DynamoDbEnhancedClient enhancedClient, DynamoDbClient standardClient) {
        String tableName = "customer";

        // Define the DynamoDbTable for an enhanced document.
        // The schema builder provides methods for attribute converter providers and keys.
        DynamoDbTable<EnhancedDocument> documentDynamoDbTable = enhancedClient.table(tableName,
                DocumentTableSchema.builder()
                        // Add the CustomAttributeConverterProvider along with the default when you build the table schema.
                        .attributeConverterProviders(
                                List.of(
                                        new CustomAttributeConverterProvider(),
                                        AttributeConverterProvider.defaultProvider()))
                        .addIndexPartitionKey(TableMetadata.primaryIndexName(), "id", AttributeValueType.N)
                        .addIndexSortKey(TableMetadata.primaryIndexName(), "lastName", AttributeValueType.S)
                        .build());
        // Create the DynamoDB table if needed.
        documentDynamoDbTable.createTable();
        waitForTableCreation(tableName, standardClient);


        // The getAddressesForCustomMappingExample() helper method that provides 'addresses' shows the use of a custom Address class
        // rather than using a Map<String, Map<String, String> to hold the address data.
        Map<String, Address> addresses = getAddressesForCustomMappingExample();

        // Build an EnhancedDocument instance to save an item with a mix of structures defined as needed and static classes.
        EnhancedDocument personDocument = EnhancedDocument.builder()
                .putNumber("id", 50)
                .putString("firstName", "Shirley")
                .putString("lastName", "Rodriguez")
                .putNumber("age", 53)
                .putNull("nullAttribute")
                .putJson("phoneNumbers", phoneNumbersJSONString())
                // Note the use of 'EnhancedType.of(Address.class)' instead of the more generic
                // 'EnhancedType.mapOf(EnhancedType.of(String.class), EnhancedType.of(String.class))' that was used in a previous example.
                .putMap("addresses", addresses, EnhancedType.of(String.class), EnhancedType.of(Address.class))
                .putList("hobbies", List.of("Hobby 1", "Hobby 2"), EnhancedType.of(String.class))
                .build();
        // Save the item to DynamoDB.
        documentDynamoDbTable.putItem(personDocument);

        // Retrieve the item just saved.
        EnhancedDocument srPerson = documentDynamoDbTable.getItem(Key.builder().partitionValue(50).sortValue("Rodriguez").build());

        // Access the addresses attribute.
        Map<String, Address> srAddresses = srPerson.get("addresses",
                EnhancedType.mapOf(EnhancedType.of(String.class), EnhancedType.of(Address.class)));

        srAddresses.keySet().forEach(k -> logger.info(addresses.get(k).toString()));

        documentDynamoDbTable.deleteTable();

// The content logged to the console shows that the saved maps were converted to Address instances.
Address{street='123 Main Street', city='Any Town', state='NC', zipCode='00000'}
Address{street='100 Any Street', city='Any Town', state='NC', zipCode='00000'}
```

## `CustomAttributeConverterProvider` コード
<a name="ddb-en-client-doc-api-convert-provider"></a>

```
public class CustomAttributeConverterProvider implements AttributeConverterProvider {

    private final Map<EnhancedType<?>, AttributeConverter<?>> converterCache = ImmutableMap.of(
            // 1. Add AddressConverter to the internal cache.
            EnhancedType.of(Address.class), new AddressConverter());

    public static CustomAttributeConverterProvider create() {
        return new CustomAttributeConverterProvider();
    }

    // 2. The enhanced client queries the provider for attribute converters if it
    //    encounters a type that it does not know how to convert.
    @SuppressWarnings("unchecked")
    @Override
    public <T> AttributeConverter<T> converterFor(EnhancedType<T> enhancedType) {
        return (AttributeConverter<T>) converterCache.get(enhancedType);
    }

    // 3. Custom attribute converter
    private class AddressConverter implements AttributeConverter<Address> {
        // 4. Transform an Address object into a DynamoDB map.
        @Override
        public AttributeValue transformFrom(Address address) {

            Map<String, AttributeValue> attributeValueMap = Map.of(
                    "street", AttributeValue.fromS(address.getStreet()),
                    "city", AttributeValue.fromS(address.getCity()),
                    "state", AttributeValue.fromS(address.getState()),
                    "zipCode", AttributeValue.fromS(address.getZipCode()));

            return AttributeValue.fromM(attributeValueMap);
        }

        // 5. Transform the DynamoDB map attribute to an Address oject.
        @Override
        public Address transformTo(AttributeValue attributeValue) {
            Map<String, AttributeValue> m = attributeValue.m();
            Address address = new Address();
            address.setStreet(m.get("street").s());
            address.setCity(m.get("city").s());
            address.setState(m.get("state").s());
            address.setZipCode(m.get("zipCode").s());

            return address;
        }

        @Override
        public EnhancedType<Address> type() {
            return EnhancedType.of(Address.class);
        }

        @Override
        public AttributeValueType attributeValueType() {
            return AttributeValueType.M;
        }
    }
}
```

## `Address` クラス
<a name="ddb-en-client-doc-api-convert-address"></a>

```
public class Address {
                  private String street;
                  private String city;
                  private String state;
                  private String zipCode;

                  public Address() {
                  }

                  public String getStreet() {
                  return this.street;
                  }

                  public String getCity() {
                  return this.city;
                  }

                  public String getState() {
                  return this.state;
                  }

                  public String getZipCode() {
                  return this.zipCode;
                  }

                  public void setStreet(String street) {
                  this.street = street;
                  }

                  public void setCity(String city) {
                  this.city = city;
                  }

                  public void setState(String state) {
                  this.state = state;
                  }

                  public void setZipCode(String zipCode) {
                  this.zipCode = zipCode;
                  }
                  }
```

## アドレスを提供するヘルパーメソッド
<a name="ddb-en-client-doc-api-convert-helper"></a>

次のヘルパーメソッドは、値にジェネリック `Map<String, String>` インスタンスではなく、値にカスタム `Address` インスタンスを使用するマップを提供します。

```
    private static Map<String, Address> getAddressesForCustomMappingExample() {
        Address homeAddress = new Address();
        homeAddress.setStreet("100 Any Street");
        homeAddress.setCity("Any Town");
        homeAddress.setState("NC");
        homeAddress.setZipCode("00000");

        Address workAddress = new Address();
        workAddress.setStreet("123 Main Street");
        workAddress.setCity("Any Town");
        workAddress.setState("NC");
        workAddress.setZipCode("00000");

        return Map.of("home", homeAddress,
                "work", workAddress);
    }
```

# DynamoDB を使用せずに `EnhancedDocument` を使用する
<a name="ddb-en-client-doc-api-standalone"></a>

通常、`EnhancedDocument` のインスタンスはドキュメントタイプの DynamoDB アイテムの読み取りと書き込みに使用しますが、DynamoDB とは独立して使用することもできます。

JSON 文字列やカスタムオブジェクトを、次の例のように `AttributeValues` の低レベルのマップに変換できるようにするために `EnhancedDocuments` を使用できます。

```
    public static void conversionWithoutDynamoDbExample() {
        Address address = new Address();
        address.setCity("my city");
        address.setState("my state");
        address.setStreet("my street");
        address.setZipCode("00000");

        // Build an EnhancedDocument instance for its conversion functionality alone.
        EnhancedDocument addressEnhancedDoc = EnhancedDocument.builder()
                // Important: You must specify attribute converter providers when you build an EnhancedDocument instance not used with a DynamoDB table.
                .attributeConverterProviders(new CustomAttributeConverterProvider(), DefaultAttributeConverterProvider.create())
                .put("addressDoc", address, Address.class)
                .build();

        // Convert address to a low-level item representation.
        final Map<String, AttributeValue> addressAsAttributeMap = addressEnhancedDoc.getMapOfUnknownType("addressDoc");
        logger.info("addressAsAttributeMap: {}", addressAsAttributeMap.toString());

        // Convert address to a JSON string.
        String addressAsJsonString = addressEnhancedDoc.getJson("addressDoc");
        logger.info("addressAsJsonString: {}", addressAsJsonString);
        // Convert addressEnhancedDoc back to an Address instance.
        Address addressConverted =  addressEnhancedDoc.get("addressDoc", Address.class);
        logger.info("addressConverted: {}", addressConverted.toString());
    }

   /* Console output:
          addressAsAttributeMap: {zipCode=AttributeValue(S=00000), state=AttributeValue(S=my state), street=AttributeValue(S=my street), city=AttributeValue(S=my city)}
          addressAsJsonString: {"zipCode":"00000","state":"my state","street":"my street","city":"my city"}
          addressConverted: Address{street='my street', city='my city', state='my state', zipCode='00000'}
   */
```

**注記**  
DynamoDB テーブルから独立した拡張ドキュメントを使用する場合は、必ずビルダーに属性コンバータープロバイダーを明示的に設定してください。  
対照的に、拡張ドキュメントを DynamoDB テーブルで使用すると、ドキュメントテーブルスキーマがコンバータープロバイダーに提供されます。

# 拡張機能を使用して DynamoDB 拡張クライアントオペレーションをカスタマイズする
<a name="ddb-en-client-extensions"></a>

DynamoDB 拡張クライアント API は、マッピング操作以外の機能を提供するプラグイン拡張機能をサポートしています。拡張機能は、読み取りおよび書き込みオペレーション中に 2 つのフックメソッドを使用してデータを変更します。
+ `beforeWrite()` - 発生する前に書き込みオペレーションを変更する
+ `afterRead()` - 読み取りオペレーションの実行後にその結果を変更する

一部のオペレーション (アイテムの更新など) は書き込みと読み取りの両方を実行するため、両方のフックメソッドが呼び出されます。

## 拡張機能のロード方法
<a name="ddb-en-client-extensions-loading"></a>

拡張機能は、拡張クライアントビルダーで指定された順序でロードされます。1 つのエクステンションが以前のエクステンションによって変換された値に作用する可能性があるため、ロード順序は重要な場合があります。

デフォルトでは、拡張クライアントは 2 つの拡張機能をロードします。
+ `[VersionedRecordExtension](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/extensions/VersionedRecordExtension.html)` - 楽観的ロックを提供する
+ `[AtomicCounterExtension](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/extensions/AtomicCounterExtension.html)` - カウンター属性を自動的に増分する

拡張クライアントビルダーでデフォルトの動作を上書きして、任意の拡張機能を読み込むことができます。デフォルトの拡張機能を使いたくない場合は、none を指定することもできます。

**重要**  
独自の拡張機能をロードしても、拡張クライアントはデフォルトの拡張機能をロードしません。いずれかのデフォルトの拡張機能と同じ動作をさせたい場合は、拡張機能のリストに明示的に追加する必要があります。

次の例は、 `VersionedRecordExtension` の後に `verifyChecksumExtension` という名前のカスタム拡張機能をロードする方法を示しています。この例では、`AtomicCounterExtension` はロードされていません。

```
DynamoDbEnhancedClientExtension versionedRecordExtension = VersionedRecordExtension.builder().build();

DynamoDbEnhancedClient enhancedClient = 
    DynamoDbEnhancedClient.builder()
                          .dynamoDbClient(dynamoDbClient)
                          .extensions(versionedRecordExtension, verifyChecksumExtension)
                          .build();
```

## 利用可能な拡張機能の詳細と設定
<a name="ddb-en-client-extensions-details"></a>

以下のセクションでは、 SDK で使用可能な各拡張機能に関する詳細情報を記載します。

### `VersionedRecordExtension` を使用して楽観的ロックを実装する
<a name="ddb-en-client-extensions-VRE"></a>

`VersionedRecordExtension` 拡張機能は、アイテムがデータベースに書き込まれるとアイテムのバージョン番号を増加して追跡することで、楽観的ロックを提供します。実際に保存されているアイテムのバージョン番号がアプリケーションが最後に読み取った値と一致しない場合、書き込みが失敗する原因となる条件が書き込みごとに追加されます。

#### 設定
<a name="ddb-en-client-extensions-VRE-conf"></a>

アイテムのバージョン番号を追跡するために使用する属性を指定するには、テーブルスキーマの数値属性にタグを付けます。

次のスニペットでは、`version` 属性がアイテムのバージョン番号を保持するように指定しています。

```
    @DynamoDbVersionAttribute
    public Integer getVersion() {...};
    public void setVersion(Integer version) {...};
```

これと同等の静的テーブルスキーマのアプローチは、次のスニペットで示されます。

```
    .addAttribute(Integer.class, a -> a.name("version")
                                       .getter(Customer::getVersion)
                                       .setter(Customer::setVersion)
                                        // Apply the 'version' tag to the attribute.
                                       .tags(VersionedRecordExtension.AttributeTags.versionAttribute())
```

#### 仕組み
<a name="ddb-en-client-extensions-VRE-how-it-works"></a>

`VersionedRecordExtension` を使用した楽観的ロックは、次の `DynamoDbEnhancedClient` および `DynamoDbTable` メソッドに対して以下のような影響があります。

**`putItem`**  
新しいアイテムには、初期バージョン値 0 が割り当てられます。これは `@DynamoDbVersionAttribute(startAt = X)` で設定できます。

**`updateItem`**  
項目を取得し、その項目の 1 つ以上のプロパティを更新して変更を保存する場合には、クライアント側とサーバー側のバージョン番号が一致する場合のみ、オペレーションが成功します。  
成功すると、バージョン番号は自動的に 1 ずつ増加します。これは `@DynamoDbVersionAttribute(incrementBy = X)` で設定できます。

**`deleteItem`**  
`DynamoDbVersionAttribute` 注釈は効力を発揮しません。アイテムを削除するときは、条件式を手動で追加する必要があります。  
次の例では、条件式を追加して、削除されたアイテムが読み取られたアイテムであることを確認します。次の例では、`recordVersion` は `@DynamoDbVersionAttribute` で注釈を付けた Bean の属性です。  

```
// 1. Read the item and get its current version.
Customer item = customerTable.getItem(Key.builder().partitionValue("someId").build());
// `recordVersion` is the bean's attribute that is annotated with `@DynamoDbVersionAttribute`.
AttributeValue currentVersion = item.getRecordVersion();

// 2. Create conditional delete with the `currentVersion` value.
DeleteItemEnhancedRequest deleteItemRequest =
    DeleteItemEnhancedRequest.builder()
       .key(KEY)
       .conditionExpression(Expression.builder()
           .expression("recordVersion = :current_version_value")
           .putExpressionValue(":current_version_value", currentVersion)
           .build()).build();

customerTable.deleteItem(deleteItemRequest);
```

**`transactWriteItems`**  
+ `addPutItem`: このメソッドの動作は `putItem` と同じです。
+ `addUpdateItem`: このメソッドの動作は `updateItem` と同じです。
+ `addDeleteItem`: このメソッドの動作は `deleteItem` と同じです。

**`batchWriteItem`**  
+ `addPutItem`: このメソッドの動作は `putItem` と同じです。
+ `addDeleteItem`: このメソッドの動作は `deleteItem` と同じです。

**注記**  
DynamoDB グローバルテーブルでは[最終書き込み者優先](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/V2globaltables_HowItWorks.html#V2globaltables_HowItWorks.consistency-modes)を使用して、同時更新間の調整を行い、DynamoDB は最終書き込み者を判断するために最善を尽くします。グローバルテーブルを使用する場合、この「最終書き込み者優先」ポリシーは、すべてのレプリカが最終的に DynamoDB によって決定された最後の書き込みに基づいて収束するため、ロック戦略が期待どおりに機能しない可能性があることを意味します。

#### 無効にする方法
<a name="ddb-en-client-extensions-VRE-how-to-disable"></a>

楽観的ロックを無効にするには、`@DynamoDbVersionAttribute` 注釈を使用しないようにします。

### `AtomicCounterExtension` を使用してカウンターを実装する
<a name="ddb-en-client-extensions-ACE"></a>

`AtomicCounterExtension` 拡張機能は、レコードがデータベースに書き込まれるたびに、タグ付きの数値属性を増やします。開始値と増分値を指定できます。値を指定しない場合、開始値は 0 に設定され、属性の値は 1 ずつ増加します。

#### 設定
<a name="ddb-en-client-extensions-ACE-conf"></a>

どの属性がカウンターかを指定するには、テーブルスキーマのタイプ `Long` の属性にタグを付けます。

次のスニペットは、`counter` 属性のデフォルトの開始値と増分値の使用方法を示しています。

```
    @DynamoDbAtomicCounter
    public Long getCounter() {...};
    public void setCounter(Long counter) {...};
```

次のスニペットは、静的テーブルスキーマのアプローチを示しています。アトミックカウンタ拡張機能は、開始値を 10 に設定し、レコードが書き込まれるたびに値を 5 ずつ増やします。

```
    .addAttribute(Integer.class, a -> a.name("counter")
                                       .getter(Customer::getCounter)
                                       .setter(Customer::setCounter)
                                        // Apply the 'atomicCounter' tag to the attribute with start and increment values.
                                       .tags(StaticAttributeTags.atomicCounter(10L, 5L))
```

### `AutoGeneratedTimestampRecordExtension` でタイムスタンプを追加する
<a name="ddb-en-client-extensions-AGTE"></a>

`AutoGeneratedTimestampRecordExtension` 拡張機能は、アイテムがデータベースに正常に書き込まれるたびに、そのタイプ `[Instant](https://docs.oracle.com/javase/8/docs/api/java/time/Instant.html)` のタグ付き属性を現在のタイムスタンプで自動的に更新します。このエクステンションはデフォルトではロードされません。

#### 設定
<a name="ddb-en-client-extensions-AGTE-conf"></a>

現在のタイムスタンプで更新する属性を指定するには、テーブルスキーマの `Instant` 属性にタグを付けます。

次のスニペットでは、`lastUpdate` 属性が拡張機能の動作の対象となります。属性は `Instant` タイプでなければならないという要件に注意してください。

```
    @DynamoDbAutoGeneratedTimestampAttribute
    public Instant getLastUpdate() {...}
    public void setLastUpdate(Instant lastUpdate) {...}
```

これと同等の静的テーブルスキーマのアプローチは、次のスニペットで示されます。

```
     .addAttribute(Instant.class, a -> a.name("lastUpdate")
                                        .getter(Customer::getLastUpdate)
                                        .setter(Customer::setLastUpdate)
                                        // Applying the 'autoGeneratedTimestamp' tag to the attribute.
                                        .tags(AutoGeneratedTimestampRecordExtension.AttributeTags.autoGeneratedTimestampAttribute())
```

### AutoGeneratedUuidExtension を使用して UUID を生成する
<a name="ddb-en-client-extensions-AGUE"></a>

`AutoGeneratedUuidExtension` 拡張機能は、新しいレコードがデータベースに書き込まれるときに、属性の一意の UUID (ユニバーサル一意識別子) を生成します。Java JDK [UUID.randomUUID()](https://docs.oracle.com/javase/8/docs/api/java/util/UUID.html#randomUUID--) メソッドを使用し、`java.lang.String` 型の属性に適用されます。このエクステンションはデフォルトではロードされません。

#### 設定
<a name="ddb-en-client-extensions-AGUE-conf"></a>

次のスニペットでは、`uniqueId` 属性が拡張機能の動作の対象となります。

```
    @AutoGeneratedUuidExtension
    public String getUniqueId() {...}
    public void setUniqueId(String uniqueId) {...}
```

これと同等の静的テーブルスキーマのアプローチは、次のスニペットで示されます。

```
     .addAttribute(String.class, a -> a.name("uniqueId")
                                        .getter(Customer::getUniqueId)
                                        .setter(Customer::setUniqueId)
                                        // Applying the 'autoGeneratedUuid' tag to the attribute.
                                        .tags(AutoGeneratedUuidExtension.AttributeTags.autoGeneratedUuidAttribute())
```

拡張機能で `putItem` メソッドに対してのみ UUID に入力されるようにし、`updateItem` メソッドに対しては入力されないようにするには、次のスニペットに示すように、[更新動作](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/mapper/UpdateBehavior.html)の注釈を追加します。

```
    @AutoGeneratedUuidExtension
    @DynamoDbUpdateBehavior(UpdateBehavior.WRITE_IF_NOT_EXISTS)
    public String getUniqueId() {...}
    public void setUniqueId(String uniqueId) {...}
```

静的テーブルスキーマアプローチを使用する場合は、次の同等のコードを使用します。

```
     .addAttribute(String.class, a -> a.name("uniqueId")
                                        .getter(Customer::getUniqueId)
                                        .setter(Customer::setUniqueId)
                                        // Applying the 'autoGeneratedUuid' tag to the attribute.
                                        .tags(AutoGeneratedUuidExtension.AttributeTags.autoGeneratedUuidAttribute(),
                                              StaticAttributeTags.updateBehavior(UpdateBehavior.WRITE_IF_NOT_EXISTS))
```

# カスタム拡張機能の例
<a name="ddb-en-client-extensions-custom"></a>

`DynamoDbEnhancedClientExtension` インターフェイスを実装することで、カスタム拡張機能を作成できます。次のカスタム拡張機能クラスは、データベース内の項目にまだ属性がない場合に、更新式を使用して `registrationDate` 属性を設定する `beforeWrite()` メソッドを示しています。

```
public final class CustomExtension implements DynamoDbEnhancedClientExtension {

    // 1. In a custom extension, use an UpdateExpression to define what action to take before
    //    an item is updated.
    @Override
    public WriteModification beforeWrite(DynamoDbExtensionContext.BeforeWrite context) {
        if ( context.operationContext().tableName().equals("Customer")
                && context.operationName().equals(OperationName.UPDATE_ITEM)) {
            return WriteModification.builder()
                    .updateExpression(createUpdateExpression())
                    .build();
        }
        return WriteModification.builder().build();  // Return an "empty" WriteModification instance if the extension should not be applied.
                                                     // In this case, if the code is not updating an item on the Customer table.
    }

    private static UpdateExpression createUpdateExpression() {

        // 2. Use a SetAction, a subclass of UpdateAction, to provide the values in the update.
        SetAction setAction =
                SetAction.builder()
                        .path("registrationDate")
                        .value("if_not_exists(registrationDate, :regValue)")
                        .putExpressionValue(":regValue", AttributeValue.fromS(Instant.now().toString()))
                        .build();
        // 3. Build the UpdateExpression with one or more UpdateAction.
        return UpdateExpression.builder()
                .addAction(setAction)
                .build();
    }
}
```

# DynamoDB 拡張クライアント API を非同期的に使用する
<a name="ddb-en-client-async"></a>

アプリケーションで DynamoDB へのノンブロッキングの非同期呼び出しが必要な場合は、[DynamoDbEnhancedAsyncClient](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/DynamoDbEnhancedAsyncClient.html) を使用できます。同期実装と似ていますが、次の主な違いがあります。

1. `DynamoDbEnhancedAsyncClient` を構築するときは、次のスニペットに示すように、標準クライアントの非同期バージョン、`DynamoDbAsyncClient` を指定する必要があります。

   ```
    DynamoDbEnhancedAsyncClient enhancedClient = 
        DynamoDbEnhancedAsyncClient.builder()
                                   .dynamoDbClient(dynamoDbAsyncClient)
                                   .build();
   ```

1. 1 つのデータオブジェクトを返すメソッドは、結果だけではなく結果の `CompletableFuture` を返します。そうすることで、アプリケーションは結果をブロックせずに他の処理を行うことができます。次のスニペットは、非同期 `getItem()` メソッドを示しています。

   ```
   CompletableFuture<Customer> result = customerDynamoDbTable.getItem(customer);
   // Perform other work here.
   return result.join();   // Now block and wait for the result.
   ```

1. ページ分割された結果リストを返すメソッドは、同期 `DynamoDbEnhanceClient` が同じメソッドで返す [https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/core/pagination/sync/SdkIterable.html](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/core/pagination/sync/SdkIterable.html) の代わりに、[https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/core/async/SdkPublisher.html](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/core/async/SdkPublisher.html) を返します。その後、アプリケーションはハンドラーをそのパブリッシャーにサブスクライブして、結果をブロックせずに非同期的に処理できます。

   ```
   PagePublisher<Customer> results = customerDynamoDbTable.query(r -> r.queryConditional(keyEqualTo(k -> k.partitionValue("Smith"))));
   results.subscribe(myCustomerResultsProcessor);
   // Perform other work and let the processor handle the results asynchronously.
   ```

   `SdkPublisher API` のより詳細な使用例については、このガイドの非同期 `scan()` メソッドについて説明しているセクションの[例](ddb-en-client-use-multirecord.md#ddb-en-client-use-multirecord-scan-async)を参照してください。

# データクラス注釈
<a name="ddb-en-client-anno-index"></a>

次の表は、データクラスで使用できる注釈の一覧と、このガイドの情報と例へのリンクを示しています。テーブルは、注釈名別にアルファベット順に昇順に並べ替えられます。


**このガイドで使用されているデータクラス注釈**  

| 注釈名 | 次に適用される注釈1 | その内容 | このガイドに記載されている場所 | 
| --- | --- | --- | --- | 
| DynamoDbAtomicCounter | 属性2 | レコードがデータベースに書き込まれるたびに、タグ付きの数値属性を増やします。 | [概要とディスカッション。](ddb-en-client-extensions.md#ddb-en-client-extensions-ACE) | 
| DynamoDbAttribute | 属性 | DynamoDB テーブル属性にマップされる Bean プロパティを定義または名前を変更します。 |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ja_jp/sdk-for-java/latest/developer-guide/ddb-en-client-anno-index.html)  | 
| DynamoDbAutoGeneratedTimestampAttribute | 属性 | 項目がデータベースに正常に書き込まれるたびに、タグ付き属性を現在のタイムスタンプで更新します。 | [概要とディスカッション](ddb-en-client-extensions.md#ddb-en-client-extensions-AGTE)。 | 
| DynamoDbAutoGeneratedUuid | 属性 | 新しいレコードがデータベースに書き込まれるときに、属性の一意の UUID (ユニバーサル一意識別子) を生成します。 | [概要とディスカッション。](ddb-en-client-extensions.md#ddb-en-client-extensions-AGUE) | 
| DynamoDbBean | class | データクラスをテーブルスキーマにマッピング可能としてマークします。 | 「はじめに」セクションの[カスタマークラス](ddb-en-client-gs-tableschema.md#ddb-en-client-gs-tableschema-anno-bean-cust)で初めに使用します。このガイドでは、いくつかの使用法が説明されています。 | 
| DynamoDbConvertedBy | 属性 | カスタム AttributeConverter を注釈付きの属性に関連付けます。 | [最初のディスカッションと例。](ddb-en-client-adv-features-conversion.md#ddb-en-client-adv-features-conversion-single) | 
| DynamoDbFlatten | 属性 | 個別の DynamoDB データクラスのすべての属性をフラット化し、データベースに読み書きされるレコードに最上位の属性として追加します。 |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ja_jp/sdk-for-java/latest/developer-guide/ddb-en-client-anno-index.html)  | 
| DynamoDbIgnore | 属性 |  その結果、属性はマップされないままの状態となります。  |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ja_jp/sdk-for-java/latest/developer-guide/ddb-en-client-anno-index.html)  | 
| DynamoDbIgnoreNulls | 属性 | ネストされた DynamoDB オブジェクトの NULL 属性が保存されないようにします。 | [ディスカッションと例。](ddb-en-client-adv-features-ignore-null.md) | 
| DynamoDbImmutable | class |  変更不可能なデータクラスをテーブルスキーマにマッピング可能としてマークします。  |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ja_jp/sdk-for-java/latest/developer-guide/ddb-en-client-anno-index.html)  | 
| DynamoDbPartitionKey | 属性 |  属性を DynamoDB テーブルのプライマリパーティションキー (ハッシュキー) としてマークします。  |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ja_jp/sdk-for-java/latest/developer-guide/ddb-en-client-anno-index.html)  | 
| DynamoDbPreserveEmptyObject | 属性 |  注釈付き属性にマップされたオブジェクトにデータが存在しない場合、オブジェクトはすべて NULL フィールドで初期化されるように指定します。  | [ディスカッションと例。](ddb-en-client-adv-features-empty.md) | 
| DynamoDbSecondaryPartitionKey | 属性 |  グローバルセカンダリインデックスのパーティションキーとして属性をマークします。  |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ja_jp/sdk-for-java/latest/developer-guide/ddb-en-client-anno-index.html)  | 
| DynamoDbSecondarySortKey | 属性 |  属性をグローバルまたはローカルのセカンダリインデックスのオプションのソートキーとしてマークします。  |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ja_jp/sdk-for-java/latest/developer-guide/ddb-en-client-anno-index.html)  | 
| DynamoDbSortKey | 属性 |  属性をオプションのプライマリソートキー (レンジキー) としてマークします。  |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ja_jp/sdk-for-java/latest/developer-guide/ddb-en-client-anno-index.html)  | 
| DynamoDbUpdateBehavior | 属性 |  UpdateItem などの「更新」オペレーションの一部としてこの属性が更新されたときの動作を指定します。  | [概要と例。](ddb-en-client-adv-features-upd-behavior.md) | 
| DynamoDbVersionAttribute | 属性 | アイテムのバージョン番号を増やします。 | [概要とディスカッション。](ddb-en-client-extensions.md#ddb-en-client-extensions-VRE) | 

1属性レベルの注釈はゲッターまたはセッターに適用できますが、両方に適用することはできません。このガイドでは、ゲッターの注釈を示します。

2通常、`property` という用語は JavaBean データクラスにカプセル化された値に使用されます。ただし、このガイドでは、DynamoDB で使用されている用語との一貫性を保つため、代わりに `attribute` という用語を使用しています。

# Amazon EC2 を使用する
<a name="examples-ec2"></a>

このセクションでは、AWS SDK for Java 2.x を使用して [Amazon EC2](https://docs.aws.amazon.com/ec2/) をプログラムする例を示します。

**Topics**
+ [Amazon EC2 インスタンスの管理](examples-ec2-instances.md)
+ [AWS リージョン とアベイラビリティーゾーンを使用する](examples-ec2-regions-zones.md)
+ [Amazon EC2 でセキュリティグループを操作する](examples-ec2-security-groups.md)
+ [Amazon EC2 インスタンスメタデータを操作する](examples-ec2-IMDS.md)

# Amazon EC2 インスタンスの管理
<a name="examples-ec2-instances"></a>

## インスタンスを作成する
<a name="create-an-instance"></a>

[Ec2Client](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/ec2/Ec2Client.html) の [https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/ec2/Ec2Client.html#runInstances(software.amazon.awssdk.services.ec2.model.RunInstancesRequest)](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/ec2/Ec2Client.html#runInstances(software.amazon.awssdk.services.ec2.model.RunInstancesRequest))メソッドを呼び出して新しい Amazon EC2 インスタンスを作成し、使用する [Amazon マシンイメージ (AMI)](https://docs.aws.amazon.com//AWSEC2/latest/UserGuide/AMIs.html) と[インスタンスタイプ](https://docs.aws.amazon.com//AWSEC2/latest/UserGuide/instance-types.html)を含む [RunInstancesRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/ec2/model/RunInstancesRequest.html) を提供します。

 **インポート** 

```
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.ec2.Ec2Client;
import software.amazon.awssdk.services.ec2.model.InstanceType;
import software.amazon.awssdk.services.ec2.model.RunInstancesRequest;
import software.amazon.awssdk.services.ec2.model.RunInstancesResponse;
import software.amazon.awssdk.services.ec2.model.Tag;
import software.amazon.awssdk.services.ec2.model.CreateTagsRequest;
import software.amazon.awssdk.services.ec2.model.Ec2Exception;
```

 **Code** 

```
   public static String createEC2Instance(Ec2Client ec2,String name, String amiId ) {

        RunInstancesRequest runRequest = RunInstancesRequest.builder()
                .imageId(amiId)
                .instanceType(InstanceType.T1_MICRO)
                .maxCount(1)
                .minCount(1)
                .build();

        RunInstancesResponse response = ec2.runInstances(runRequest);
        String instanceId = response.instances().get(0).instanceId();

        Tag tag = Tag.builder()
                .key("Name")
                .value(name)
                .build();

        CreateTagsRequest tagRequest = CreateTagsRequest.builder()
                .resources(instanceId)
                .tags(tag)
                .build();

        try {
            ec2.createTags(tagRequest);
            System.out.printf(
                    "Successfully started EC2 Instance %s based on AMI %s",
                    instanceId, amiId);

          return instanceId;

        } catch (Ec2Exception e) {
            System.err.println(e.awsErrorDetails().errorMessage());
            System.exit(1);
        }

        return "";
    }
```

[GitHub](https://github.com/awsdocs/aws-doc-sdk-examples/blob/ac748d8ef99cd17e297cb74fe13aa671e2679088/javav2/example_code/ec2/src/main/java/com/example/ec2/CreateInstance.java) で完全な例をご覧ください。

## インスタンスの開始
<a name="start-an-instance"></a>

 Amazon EC2 インスタンスを起動するには、Ec2Client の [https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/ec2/Ec2Client.html#startInstances(software.amazon.awssdk.services.ec2.model.StartInstancesRequest)](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/ec2/Ec2Client.html#startInstances(software.amazon.awssdk.services.ec2.model.StartInstancesRequest))メソッドを呼び出し、起動するインスタンスの ID を含む [StartInstancesRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/ec2/model/StartInstancesRequest.html) を指定します。

 **インポート** 

```
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.ec2.Ec2Client;
import software.amazon.awssdk.services.ec2.model.StartInstancesRequest;
import software.amazon.awssdk.services.ec2.model.StopInstancesRequest;
```

 **Code** 

```
    public static void startInstance(Ec2Client ec2, String instanceId) {

        StartInstancesRequest request = StartInstancesRequest.builder()
                .instanceIds(instanceId)
                .build();

        ec2.startInstances(request);
        System.out.printf("Successfully started instance %s", instanceId);
    }
```

[GitHub](https://github.com/awsdocs/aws-doc-sdk-examples/blob/ac748d8ef99cd17e297cb74fe13aa671e2679088/javav2/example_code/ec2/src/main/java/com/example/ec2/StartStopInstance.java) で完全な例をご覧ください。

## インスタンスの停止
<a name="stop-an-instance"></a>

 Amazon EC2 インスタンスを停止するには、Ec2Client の [https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/ec2/Ec2Client.html#stopInstances(software.amazon.awssdk.services.ec2.model.StopInstancesRequest)](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/ec2/Ec2Client.html#stopInstances(software.amazon.awssdk.services.ec2.model.StopInstancesRequest))メソッドを呼び出し、停止するインスタンスの ID を含む [StopInstancesRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/ec2/model/StopInstancesRequest.html) を指定します。

 **インポート** 

```
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.ec2.Ec2Client;
import software.amazon.awssdk.services.ec2.model.StartInstancesRequest;
import software.amazon.awssdk.services.ec2.model.StopInstancesRequest;
```

 **Code** 

```
    public static void stopInstance(Ec2Client ec2, String instanceId) {

        StopInstancesRequest request = StopInstancesRequest.builder()
                .instanceIds(instanceId)
                .build();

        ec2.stopInstances(request);
        System.out.printf("Successfully stopped instance %s", instanceId);
    }
```

[GitHub](https://github.com/awsdocs/aws-doc-sdk-examples/blob/ac748d8ef99cd17e297cb74fe13aa671e2679088/javav2/example_code/ec2/src/main/java/com/example/ec2/StartStopInstance.java) で完全な例をご覧ください。

## インスタンスの再起動
<a name="reboot-an-instance"></a>

 Amazon EC2 インスタンスを再起動するには、Ec2Client の [https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/ec2/Ec2Client.html#rebootInstances(software.amazon.awssdk.services.ec2.model.RebootInstancesRequest)](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/ec2/Ec2Client.html#rebootInstances(software.amazon.awssdk.services.ec2.model.RebootInstancesRequest))メソッドを呼び出し、再起動するインスタンスの ID を含む [RebootInstancesRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/ec2/model/RebootInstancesRequest.html) を指定します。

 **インポート** 

```
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.ec2.Ec2Client;
import software.amazon.awssdk.services.ec2.model.Ec2Exception;
import software.amazon.awssdk.services.ec2.model.RebootInstancesRequest;
```

 **Code** 

```
    public static void rebootEC2Instance(Ec2Client ec2, String instanceId) {

      try {
            RebootInstancesRequest request = RebootInstancesRequest.builder()
                .instanceIds(instanceId)
                    .build();

            ec2.rebootInstances(request);
            System.out.printf(
                "Successfully rebooted instance %s", instanceId);
    } catch (Ec2Exception e) {
          System.err.println(e.awsErrorDetails().errorMessage());
          System.exit(1);
     }
  }
```

[GitHub](https://github.com/awsdocs/aws-doc-sdk-examples/blob/ac748d8ef99cd17e297cb74fe13aa671e2679088/javav2/example_code/ec2/src/main/java/com/example/ec2/RebootInstance.java) で完全な例をご覧ください。

## インスタンスの説明
<a name="describe-instances"></a>

インスタンスをリスト表示するには、[DescribeInstancesRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/ec2/model/DescribeInstancesRequest.html) を作成し、Ec2Client の [https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/ec2/Ec2Client.html#describeInstances(software.amazon.awssdk.services.ec2.model.DescribeInstancesRequest)](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/ec2/Ec2Client.html#describeInstances(software.amazon.awssdk.services.ec2.model.DescribeInstancesRequest)) メソッドを呼び出します。アカウントとリージョンの Amazon EC2 インスタンスを一覧表示するために使用できる [DescribeInstancesResponse](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/ec2/model/DescribeInstancesResponse.html) オブジェクトが返されます。

インスタンスは*予約*ごとにグループ化されています。それぞれの予約は、インスタンスを起動した `startInstances` の呼び出しに対応しています。インスタンスを一覧表示するには、まず `DescribeInstancesResponse` クラスの `reservations` メソッドを呼び出してから、返るそれぞれの `instances`Reservation[ オブジェクトの ](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/ec2/model/Reservation.html) を呼び出します。

 **インポート** 

```
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.ec2.Ec2Client;
import software.amazon.awssdk.services.ec2.model.DescribeInstancesRequest;
import software.amazon.awssdk.services.ec2.model.DescribeInstancesResponse;
import software.amazon.awssdk.services.ec2.model.Instance;
import software.amazon.awssdk.services.ec2.model.Reservation;
import software.amazon.awssdk.services.ec2.model.Ec2Exception;
```

 **[コード]** 

```
    public static void describeEC2Instances( Ec2Client ec2){

        String nextToken = null;

        try {

            do {
                DescribeInstancesRequest request = DescribeInstancesRequest.builder().maxResults(6).nextToken(nextToken).build();
                DescribeInstancesResponse response = ec2.describeInstances(request);

                for (Reservation reservation : response.reservations()) {
                    for (Instance instance : reservation.instances()) {
                        System.out.println("Instance Id is " + instance.instanceId());
                        System.out.println("Image id is "+  instance.imageId());
                        System.out.println("Instance type is "+  instance.instanceType());
                        System.out.println("Instance state name is "+  instance.state().name());
                        System.out.println("monitoring information is "+  instance.monitoring().state());

                }
            }
                nextToken = response.nextToken();
            } while (nextToken != null);

        } catch (Ec2Exception e) {
            System.err.println(e.awsErrorDetails().errorMessage());
            System.exit(1);
        }
    }
```

結果はページ分割されます。さらに結果を取得するには、結果オブジェクトの `nextToken` メソッドから返る値を新しいリクエストオブジェクトの `nextToken` メソッドに渡した後、次の `describeInstances` の呼び出しでその新しいリクエストオブジェクトを使用します。

[GitHub](https://github.com/awsdocs/aws-doc-sdk-examples/blob/ac748d8ef99cd17e297cb74fe13aa671e2679088/javav2/example_code/ec2/src/main/java/com/example/ec2/DescribeInstances.java) で完全な例をご覧ください。

## インスタンスのモニタリング
<a name="monitor-an-instance"></a>

CPU とネットワークの使用率、使用可能なメモリ、残りのディスク容量など、 Amazon EC2 インスタンスのさまざまな側面をモニタリングできます。インスタンスのモニタリングの詳細については、Linux インスタンス用 Amazon EC2 ユーザーガイドの[「モニタリング Amazon EC2](https://docs.aws.amazon.com//AWSEC2/latest/UserGuide/monitoring_ec2.html)」を参照してください。

インスタンスのモニタリングを開始するには、モニタリングするインスタンスの ID で [MonitorInstancesRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/ec2/model/MonitorInstancesRequest.html) を作成し、Ec2Client の [https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/ec2/Ec2Client.html#monitorInstances(software.amazon.awssdk.services.ec2.model.MonitorInstancesRequest)](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/ec2/Ec2Client.html#monitorInstances(software.amazon.awssdk.services.ec2.model.MonitorInstancesRequest)) メソッドに渡します。

 **インポート** 

```
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.ec2.Ec2Client;
import software.amazon.awssdk.services.ec2.model.MonitorInstancesRequest;
import software.amazon.awssdk.services.ec2.model.UnmonitorInstancesRequest;
```

 **Code** 

```
    public static void monitorInstance( Ec2Client ec2, String instanceId) {

        MonitorInstancesRequest request = MonitorInstancesRequest.builder()
                .instanceIds(instanceId).build();

        ec2.monitorInstances(request);
        System.out.printf(
                "Successfully enabled monitoring for instance %s",
                instanceId);
    }
```

[GitHub](https://github.com/awsdocs/aws-doc-sdk-examples/blob/ac748d8ef99cd17e297cb74fe13aa671e2679088/javav2/example_code/ec2/src/main/java/com/example/ec2/MonitorInstance.java) で完全な例をご覧ください。

## インスタンスのモニタリング停止
<a name="stop-instance-monitoring"></a>

インスタンスのモニタリングを停止するには、モニタリングを停止するインスタンスの ID で [UnmonitorInstancesRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/ec2/model/UnmonitorInstancesRequest.html) を作成し、Ec2Client の [https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/ec2/Ec2Client.html#unmonitorInstances(software.amazon.awssdk.services.ec2.model.UnmonitorInstancesRequest)](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/ec2/Ec2Client.html#unmonitorInstances(software.amazon.awssdk.services.ec2.model.UnmonitorInstancesRequest)) メソッドに渡します。

 **インポート** 

```
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.ec2.Ec2Client;
import software.amazon.awssdk.services.ec2.model.MonitorInstancesRequest;
import software.amazon.awssdk.services.ec2.model.UnmonitorInstancesRequest;
```

 **Code** 

```
    public static void unmonitorInstance(Ec2Client ec2, String instanceId) {
        UnmonitorInstancesRequest request = UnmonitorInstancesRequest.builder()
                .instanceIds(instanceId).build();

        ec2.unmonitorInstances(request);

        System.out.printf(
                "Successfully disabled monitoring for instance %s",
                instanceId);
    }
```

[GitHub](https://github.com/awsdocs/aws-doc-sdk-examples/blob/ac748d8ef99cd17e297cb74fe13aa671e2679088/javav2/example_code/ec2/src/main/java/com/example/ec2/MonitorInstance.java) で完全な例をご覧ください。

## 詳細情報
<a name="more-information"></a>
+  Amazon EC2 API リファレンスの [RunInstances](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_RunInstances.html) 
+  Amazon EC2 API リファレンスの [DescribeInstances](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeInstances.html) 
+  Amazon EC2 API リファレンスの [StartInstances](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_StartInstances.html) 
+  Amazon EC2 API リファレンスの [StopInstances](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_StopInstances.html) 
+  Amazon EC2 API リファレンスの [RebootInstances](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_RebootInstances.html) 
+  Amazon EC2 API リファレンスの [MonitorInstances](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_MonitorInstances.html) 
+  Amazon EC2 API リファレンスの [UnmonitorInstances](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_UnmonitorInstances.html) 

# AWS リージョン とアベイラビリティーゾーンを使用する
<a name="examples-ec2-regions-zones"></a>

## リージョンの記述
<a name="describe-regions"></a>

アカウントに使用可能なリージョンを一覧表示するには、Ec2Client の `describeRegions` メソッドを呼び出します。これにより [DescribeRegionsResponse](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/ec2/model/DescribeRegionsResponse.html) が返されます。返されたオブジェクトの `regions` メソッドを呼び出して、各リージョンを表す [Region](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/ec2/model/Region.html) オブジェクトの一覧を取得します。

 **インポート** 

```
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.ec2.Ec2AsyncClient;
import software.amazon.awssdk.services.ec2.model.DescribeRegionsResponse;
import software.amazon.awssdk.services.ec2.model.DescribeAvailabilityZonesResponse;
import java.util.concurrent.CompletableFuture;
```

 **Code** 

```
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.ec2.Ec2AsyncClient;
import software.amazon.awssdk.services.ec2.model.DescribeRegionsResponse;
import software.amazon.awssdk.services.ec2.model.DescribeAvailabilityZonesResponse;
import java.util.concurrent.CompletableFuture;

/**
 * Before running this Java V2 code example, set up your development
 * environment, including your credentials.
 *
 * For more information, see the following documentation topic:
 *
 * https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/get-started.html
 */
public class DescribeRegionsAndZones {
    public static void main(String[] args) {
        Ec2AsyncClient ec2AsyncClient = Ec2AsyncClient.builder()
            .region(Region.US_EAST_1)
            .build();

        try {
            CompletableFuture<Void> future = describeEC2RegionsAndZonesAsync(ec2AsyncClient);
            future.join(); // Wait for both async operations to complete.
        } catch (RuntimeException rte) {
            System.err.println("An exception occurred: " + (rte.getCause() != null ? rte.getCause().getMessage() : rte.getMessage()));
        }
    }

    /**
     * Asynchronously describes the EC2 regions and availability zones.
     *
     * @param ec2AsyncClient the EC2 async client used to make the API calls
     * @return a {@link CompletableFuture} that completes when both the region and availability zone descriptions are complete
     */
    public static CompletableFuture<Void> describeEC2RegionsAndZonesAsync(Ec2AsyncClient ec2AsyncClient) {
        // Initiate the asynchronous request to describe regions
        CompletableFuture<DescribeRegionsResponse> regionsResponse = ec2AsyncClient.describeRegions();

        // Handle the response or exception for regions
        CompletableFuture<DescribeRegionsResponse> regionsFuture = regionsResponse.whenComplete((regionsResp, ex) -> {
            if (ex != null) {
                // Handle the exception by throwing a RuntimeException
                throw new RuntimeException("Failed to describe EC2 regions.", ex);
            } else if (regionsResp == null || regionsResp.regions().isEmpty()) {
                // Throw an exception if the response is null or the result is empty
                throw new RuntimeException("No EC2 regions found.");
            } else {
                // Process the response if no exception occurred and the result is not empty
                regionsResp.regions().forEach(region -> {
                    System.out.printf(
                        "Found Region %s with endpoint %s%n",
                        region.regionName(),
                        region.endpoint());
                });
            }
        });

        CompletableFuture<DescribeAvailabilityZonesResponse> zonesResponse = ec2AsyncClient.describeAvailabilityZones();
        CompletableFuture<DescribeAvailabilityZonesResponse> zonesFuture = zonesResponse.whenComplete((zonesResp, ex) -> {
            if (ex != null) {
                throw new RuntimeException("Failed to describe EC2 availability zones.", ex);
            } else if (zonesResp == null || zonesResp.availabilityZones().isEmpty()) {
                throw new RuntimeException("No EC2 availability zones found.");
            } else {
                zonesResp.availabilityZones().forEach(zone -> {
                    System.out.printf(
                        "Found Availability Zone %s with status %s in region %s%n",
                        zone.zoneName(),
                        zone.state(),
                        zone.regionName()
                    );
                });
            }
        });

        return CompletableFuture.allOf(regionsFuture, zonesFuture);
    }
}
```

[GitHub](https://github.com/awsdocs/aws-doc-sdk-examples/blob/7486a1a092aa8e16a21698ef26f9d524fef62e55/javav2/example_code/ec2/src/main/java/com/example/ec2/DescribeRegionsAndZones.java) で完全な例をご覧ください。

## アベイラビリティーゾーンの詳細を表示する
<a name="describe-availability-zones"></a>

アカウントに使用可能な各アベイラビリティーゾーンを一覧表示するには、Ec2Client の `describeAvailabilityZones` メソッドを呼び出します。これにより [DescribeAvailabilityZonesResponse](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/ec2/model/DescribeAvailabilityZonesResponse.html) が返されます。それの `availabilityZones` メソッドを呼び出して、各アベイラビリティーゾーンを表す [AvailabilityZone](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/ec2/model/AvailabilityZone.html) オブジェクトの一覧を取得します。

 **インポート** 

```
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.ec2.Ec2AsyncClient;
import software.amazon.awssdk.services.ec2.model.DescribeRegionsResponse;
import software.amazon.awssdk.services.ec2.model.DescribeAvailabilityZonesResponse;
import java.util.concurrent.CompletableFuture;
```

 **[コード]** 

Ec2Client を作成します。

```
        Ec2AsyncClient ec2AsyncClient = Ec2AsyncClient.builder()
            .region(Region.US_EAST_1)
            .build();
```

次に、describeAvailabilityZones() を呼び出し、結果を取得します。

```
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.ec2.Ec2AsyncClient;
import software.amazon.awssdk.services.ec2.model.DescribeRegionsResponse;
import software.amazon.awssdk.services.ec2.model.DescribeAvailabilityZonesResponse;
import java.util.concurrent.CompletableFuture;

/**
 * Before running this Java V2 code example, set up your development
 * environment, including your credentials.
 *
 * For more information, see the following documentation topic:
 *
 * https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/get-started.html
 */
public class DescribeRegionsAndZones {
    public static void main(String[] args) {
        Ec2AsyncClient ec2AsyncClient = Ec2AsyncClient.builder()
            .region(Region.US_EAST_1)
            .build();

        try {
            CompletableFuture<Void> future = describeEC2RegionsAndZonesAsync(ec2AsyncClient);
            future.join(); // Wait for both async operations to complete.
        } catch (RuntimeException rte) {
            System.err.println("An exception occurred: " + (rte.getCause() != null ? rte.getCause().getMessage() : rte.getMessage()));
        }
    }

    /**
     * Asynchronously describes the EC2 regions and availability zones.
     *
     * @param ec2AsyncClient the EC2 async client used to make the API calls
     * @return a {@link CompletableFuture} that completes when both the region and availability zone descriptions are complete
     */
    public static CompletableFuture<Void> describeEC2RegionsAndZonesAsync(Ec2AsyncClient ec2AsyncClient) {
        // Initiate the asynchronous request to describe regions
        CompletableFuture<DescribeRegionsResponse> regionsResponse = ec2AsyncClient.describeRegions();

        // Handle the response or exception for regions
        CompletableFuture<DescribeRegionsResponse> regionsFuture = regionsResponse.whenComplete((regionsResp, ex) -> {
            if (ex != null) {
                // Handle the exception by throwing a RuntimeException
                throw new RuntimeException("Failed to describe EC2 regions.", ex);
            } else if (regionsResp == null || regionsResp.regions().isEmpty()) {
                // Throw an exception if the response is null or the result is empty
                throw new RuntimeException("No EC2 regions found.");
            } else {
                // Process the response if no exception occurred and the result is not empty
                regionsResp.regions().forEach(region -> {
                    System.out.printf(
                        "Found Region %s with endpoint %s%n",
                        region.regionName(),
                        region.endpoint());
                });
            }
        });

        CompletableFuture<DescribeAvailabilityZonesResponse> zonesResponse = ec2AsyncClient.describeAvailabilityZones();
        CompletableFuture<DescribeAvailabilityZonesResponse> zonesFuture = zonesResponse.whenComplete((zonesResp, ex) -> {
            if (ex != null) {
                throw new RuntimeException("Failed to describe EC2 availability zones.", ex);
            } else if (zonesResp == null || zonesResp.availabilityZones().isEmpty()) {
                throw new RuntimeException("No EC2 availability zones found.");
            } else {
                zonesResp.availabilityZones().forEach(zone -> {
                    System.out.printf(
                        "Found Availability Zone %s with status %s in region %s%n",
                        zone.zoneName(),
                        zone.state(),
                        zone.regionName()
                    );
                });
            }
        });

        return CompletableFuture.allOf(regionsFuture, zonesFuture);
    }
}
```

[GitHub](https://github.com/awsdocs/aws-doc-sdk-examples/blob/7486a1a092aa8e16a21698ef26f9d524fef62e55/javav2/example_code/ec2/src/main/java/com/example/ec2/DescribeRegionsAndZones.java) で完全な例をご覧ください。

## アカウントの説明
<a name="describe-accounts"></a>

アカウントの EC2 関連情報を一覧表示するには、Ec2Client の `describeAccountAttributes` メソッドを呼び出します。このメソッドは、[DescribeAccountAttributesResponse](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/ec2/model/DescribeAccountAttributesResponse.html) オブジェクトを返します。このオブジェクト `accountAttributes` メソッドを呼び出して、[AccountAttribute](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/ec2/model/AccountAttribute.html) オブジェクトのリストを取得します。リストを反復処理して、`AccountAttribute` オブジェクトを取得できます。

アカウントの属性値は、`AccountAttribute` オブジェクトの `attributeValues` メソッドを呼び出すことで取得できます。このメソッドは、[AccountAttributeValue](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/ec2/model/AccountAttributeValue.html) オブジェクトのリストを返します。この 2 番目のリストを反復処理して、属性の値を表示できます (次のコード例を参照)。

 **インポート** 

```
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.ec2.Ec2AsyncClient;
import software.amazon.awssdk.services.ec2.model.DescribeAccountAttributesResponse;
import java.util.concurrent.CompletableFuture;
```

 **Code** 

```
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.ec2.Ec2AsyncClient;
import software.amazon.awssdk.services.ec2.model.DescribeAccountAttributesResponse;
import java.util.concurrent.CompletableFuture;

/**
 * Before running this Java V2 code example, set up your development
 * environment, including your credentials.
 *
 * For more information, see the following documentation topic:
 *
 * https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/get-started.html
 */
public class DescribeAccount {
    public static void main(String[] args) {
        Ec2AsyncClient ec2AsyncClient = Ec2AsyncClient.builder()
            .region(Region.US_EAST_1)
            .build();

        try {
            CompletableFuture<DescribeAccountAttributesResponse> future = describeEC2AccountAsync(ec2AsyncClient);
            future.join();
            System.out.println("EC2 Account attributes described successfully.");
        } catch (RuntimeException rte) {
            System.err.println("An exception occurred: " + (rte.getCause() != null ? rte.getCause().getMessage() : rte.getMessage()));
        }
    }

    /**
     * Describes the EC2 account attributes asynchronously.
     *
     * @param ec2AsyncClient the EC2 asynchronous client to use for the operation
     * @return a {@link CompletableFuture} containing the {@link DescribeAccountAttributesResponse} with the account attributes
     */
    public static CompletableFuture<DescribeAccountAttributesResponse> describeEC2AccountAsync(Ec2AsyncClient ec2AsyncClient) {
        CompletableFuture<DescribeAccountAttributesResponse> response = ec2AsyncClient.describeAccountAttributes();
        return response.whenComplete((accountResults, ex) -> {
            if (ex != null) {
                // Handle the exception by throwing a RuntimeException.
                throw new RuntimeException("Failed to describe EC2 account attributes.", ex);
            } else if (accountResults == null || accountResults.accountAttributes().isEmpty()) {
                // Throw an exception if the response is null or no account attributes are found.
                throw new RuntimeException("No account attributes found.");
            } else {
                // Process the response if no exception occurred.
                accountResults.accountAttributes().forEach(attribute -> {
                    System.out.println("\nThe name of the attribute is " + attribute.attributeName());
                    attribute.attributeValues().forEach(
                        myValue -> System.out.println("The value of the attribute is " + myValue.attributeValue()));
                });
            }
        });
    }
}
```

[GitHub](https://github.com/awsdocs/aws-doc-sdk-examples/blob/7486a1a092aa8e16a21698ef26f9d524fef62e55/javav2/example_code/ec2/src/main/java/com/example/ec2/DescribeAccount.java) で完全な例をご覧ください。

## 詳細情報
<a name="more-information"></a>
+  Linux インスタンス用 Amazon EC2 ユーザーガイドの[「リージョンとアベイラビリティーゾーン](https://docs.aws.amazon.com//AWSEC2/latest/UserGuide/using-regions-availability-zones.html)」
+  Amazon EC2 API リファレンスの [DescribeRegions](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeRegions.html) 
+  Amazon EC2 API リファレンスの [DescribeAvailabilityZones](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeAvailabilityZones.html) 

# Amazon EC2 でセキュリティグループを操作する
<a name="examples-ec2-security-groups"></a>

## セキュリティグループの作成
<a name="create-a-security-group"></a>

セキュリティグループを作成するには、そのキーの名前を含む `createSecurityGroup`CreateSecurityGroupRequest[ を使用して Ec2Client の ](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/ec2/model/CreateSecurityGroupRequest.html) メソッドを呼び出します。

 **インポート** 

```
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.ec2.Ec2Client;
import software.amazon.awssdk.services.ec2.model.CreateSecurityGroupRequest;
import software.amazon.awssdk.services.ec2.model.AuthorizeSecurityGroupIngressRequest;
import software.amazon.awssdk.services.ec2.model.AuthorizeSecurityGroupIngressResponse;
import software.amazon.awssdk.services.ec2.model.Ec2Exception;
import software.amazon.awssdk.services.ec2.model.IpPermission;
import software.amazon.awssdk.services.ec2.model.CreateSecurityGroupResponse;
import software.amazon.awssdk.services.ec2.model.IpRange;
```

 **コード** 

```
            CreateSecurityGroupRequest createRequest = CreateSecurityGroupRequest.builder()
                .groupName(groupName)
                .description(groupDesc)
                .vpcId(vpcId)
                .build();

            CreateSecurityGroupResponse resp= ec2.createSecurityGroup(createRequest);
```

[GitHub](https://github.com/awsdocs/aws-doc-sdk-examples/blob/0b1785e42949ebf959eaa0f0da4dc2a48f92ea25/javav2/example_code/ec2/src/main/java/com/example/ec2/CreateSecurityGroup.java) で完全な例をご覧ください。

## セキュリティグループを設定する
<a name="configure-a-security-group"></a>

セキュリティグループは、Amazon EC2 インスタンスへのインバウンド (ingress) とアウトバウンド (egress) トラフィックの両方を制御できます。

セキュリティグループに Ingress ルールを追加するには、Ec2Client の `authorizeSecurityGroupIngress` メソッドを使用して、セキュリティグループの名前と [AuthorizeSecurityGroupIngressRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/ec2/model/IpPermission.html) オブジェクト内で割り当てるアクセスルール ([IpPermission](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/ec2/model/AuthorizeSecurityGroupIngressRequest.html)) を指定します。以下の例では、セキュリティグループへの IP のアクセス許可の追加方法を説明します。

 **インポート** 

```
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.ec2.Ec2Client;
import software.amazon.awssdk.services.ec2.model.CreateSecurityGroupRequest;
import software.amazon.awssdk.services.ec2.model.AuthorizeSecurityGroupIngressRequest;
import software.amazon.awssdk.services.ec2.model.AuthorizeSecurityGroupIngressResponse;
import software.amazon.awssdk.services.ec2.model.Ec2Exception;
import software.amazon.awssdk.services.ec2.model.IpPermission;
import software.amazon.awssdk.services.ec2.model.CreateSecurityGroupResponse;
import software.amazon.awssdk.services.ec2.model.IpRange;
```

 **コード** 

最初に、Ec2Client を作成します

```
        Region region = Region.US_WEST_2;
        Ec2Client ec2 = Ec2Client.builder()
                .region(region)
                .build();
```

その後、Ec2Client の `authorizeSecurityGroupIngress` メソッドを使用します。

```
            IpRange ipRange = IpRange.builder()
                .cidrIp("0.0.0.0/0").build();

            IpPermission ipPerm = IpPermission.builder()
                .ipProtocol("tcp")
                .toPort(80)
                .fromPort(80)
                .ipRanges(ipRange)
                .build();

            IpPermission ipPerm2 = IpPermission.builder()
                .ipProtocol("tcp")
                .toPort(22)
                .fromPort(22)
                .ipRanges(ipRange)
                .build();

            AuthorizeSecurityGroupIngressRequest authRequest =
                AuthorizeSecurityGroupIngressRequest.builder()
                        .groupName(groupName)
                        .ipPermissions(ipPerm, ipPerm2)
                        .build();

            AuthorizeSecurityGroupIngressResponse authResponse =
            ec2.authorizeSecurityGroupIngress(authRequest);

            System.out.printf(
                "Successfully added ingress policy to Security Group %s",
                groupName);

            return resp.groupId();

        } catch (Ec2Exception e) {
            System.err.println(e.awsErrorDetails().errorMessage());
            System.exit(1);
        }
        return "";
    }
```

セキュリティグループに egress ルールを追加するには、同様のデータを Ec2Client の `authorizeSecurityGroupEgress` メソッドに [AuthorizeSecurityGroupEgressRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/ec2/model/AuthorizeSecurityGroupEgressRequest.html) で指定します。

[GitHub](https://github.com/awsdocs/aws-doc-sdk-examples/blob/0b1785e42949ebf959eaa0f0da4dc2a48f92ea25/javav2/example_code/ec2/src/main/java/com/example/ec2/CreateSecurityGroup.java) で完全な例をご覧ください。

## セキュリティグループを記述する
<a name="describe-security-groups"></a>

セキュリティグループについて記述、またはそれらに関する情報を収集するには、Ec2Client の `describeSecurityGroups` メソッドを呼び出します。これにより [DescribeSecurityGroupsResponse](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/ec2/model/DescribeSecurityGroupsResponse.html) が返されます。SecurityGroup オブジェクトのリストを返す `securityGroups` メソッドを呼び出し、このオブジェクトを渡すことで、[セキュリティグループ](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/ec2/model/SecurityGroup.html)のリストにアクセスできます。

 **インポート** 

```
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.ec2.Ec2Client;
import software.amazon.awssdk.services.ec2.model.DescribeSecurityGroupsRequest;
import software.amazon.awssdk.services.ec2.model.DescribeSecurityGroupsResponse;
import software.amazon.awssdk.services.ec2.model.SecurityGroup;
import software.amazon.awssdk.services.ec2.model.Ec2Exception;
```

 **コード** 

```
     public static void describeEC2SecurityGroups(Ec2Client ec2, String groupId) {

        try {
            DescribeSecurityGroupsRequest request =
                DescribeSecurityGroupsRequest.builder()
                        .groupIds(groupId).build();

            DescribeSecurityGroupsResponse response =
                ec2.describeSecurityGroups(request);

             for(SecurityGroup group : response.securityGroups()) {
                System.out.printf(
                    "Found Security Group with id %s, " +
                            "vpc id %s " +
                            "and description %s",
                    group.groupId(),
                    group.vpcId(),
                    group.description());
            }
        } catch (Ec2Exception e) {
            System.err.println(e.awsErrorDetails().errorMessage());
            System.exit(1);
        }
    }
```

[GitHub](https://github.com/awsdocs/aws-doc-sdk-examples/blob/0b1785e42949ebf959eaa0f0da4dc2a48f92ea25/javav2/example_code/ec2/src/main/java/com/example/ec2/DescribeSecurityGroups.java) で完全な例をご覧ください。

## セキュリティグループを削除する
<a name="delete-a-security-group"></a>

セキュリティグループを削除するには、Ec2Client の `deleteSecurityGroup` メソッドを呼び出し、それに削除するセキュリティグループの ID を含む [DeleteSecurityGroupRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/ec2/model/DeleteSecurityGroupRequest.html) を渡します。

 **インポート** 

```
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.ec2.Ec2Client;
import software.amazon.awssdk.services.ec2.model.DeleteSecurityGroupRequest;
import software.amazon.awssdk.services.ec2.model.Ec2Exception;
```

 **コード** 

```
    public static void deleteEC2SecGroup(Ec2Client ec2,String groupId) {

        try {
            DeleteSecurityGroupRequest request = DeleteSecurityGroupRequest.builder()
                .groupId(groupId)
                .build();

            ec2.deleteSecurityGroup(request);
            System.out.printf(
                "Successfully deleted Security Group with id %s", groupId);

        } catch (Ec2Exception e) {
            System.err.println(e.awsErrorDetails().errorMessage());
            System.exit(1);
        }
     }
```

[GitHub](https://github.com/awsdocs/aws-doc-sdk-examples/blob/0b1785e42949ebf959eaa0f0da4dc2a48f92ea25/javav2/example_code/ec2/src/main/java/com/example/ec2/DeleteSecurityGroup.java) で完全な例をご覧ください。

## 詳細情報
<a name="more-information"></a>
+  「Linux インスタンス用 Amazon EC2 ユーザーガイド」の [Amazon EC2 セキュリティグループ](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-security-groups.html)
+  「Amazon EC2 Linux インスタンス用ユーザーガイド」の「[Linux インスタンスのインバウンドトラフィックの承認](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/authorizing-access-to-an-instance.html)」
+  Amazon EC2 API リファレンスの [CreateSecurityGroup](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_CreateSecurityGroup.html)
+  Amazon EC2 API リファレンスの [DescribeSecurityGroups](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeSecurityGroups.html)
+  Amazon EC2 API リファレンスの [DeleteSecurityGroup](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DeleteSecurityGroup.html)
+  Amazon EC2 API リファレンスの [AuthorizeSecurityGroupIngress](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_AuthorizeSecurityGroupIngress.html)

# Amazon EC2 インスタンスメタデータを操作する
<a name="examples-ec2-IMDS"></a>

Amazon EC2 インスタンスメタデータサービスの Java SDK クライアント (メタデータクライアント) を使用すると、アプリケーションはローカル EC2 インスタンスのメタデータにアクセスできます。メタデータクライアントは [IMDSv2](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/configuring-instance-metadata-service.html) のローカルインスタンス (インスタンスメタデータサービス v2) と連携し、セッション指向のリクエストを使用します。

SDK には 2 つのクライアントクラスがあります。同期 `[Ec2MetadataClient](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/imds/Ec2MetadataClient.html)` はブロッッキングオペレーション用で、[https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/imds/Ec2MetadataAsyncClient.html](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/imds/Ec2MetadataAsyncClient.html) は非同期、ノンブロッキングのユースケース用です。

## はじめに
<a name="examples-ec2-IMDS-getstarted"></a>

メタデータクライアントを使用するには、`imds` Maven アーティファクトをプロジェクトに追加します。クラスパスには `[SdkHttpClient](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/http/SdkHttpClient.html)` (または非同期バリアントの場合は `[SdkAsyncHttpClient](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/http/async/SdkAsyncHttpClient.html)`) のクラスも必要です。

次の Maven XML は、同期 [UrlConnectionHttpClient](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/http/urlconnection/UrlConnectionHttpClient.html) を使用するための依存関係のスニペットと、メタデータクライアントの依存関係を示しています。

```
<dependencyManagement>
   <dependencies>
        <dependency>
            <groupId>software.amazon.awssdk</groupId>
            <artifactId>bom</artifactId>
            <version>VERSION</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

<dependencies>
    <dependency>
        <groupId>software.amazon.awssdk</groupId>
        <artifactId>imds</artifactId>
    </dependency>
    <dependency>
        <groupId>software.amazon.awssdk</groupId>
        <artifactId>url-connection-client</artifactId>
    </dependency>
    <!-- other dependencies --> 
</dependencies>
```

[Maven central リポジトリ](https://central.sonatype.com/artifact/software.amazon.awssdk/bom)で `bom` アーティファクトの最新バージョンを検索してください。

非同期 HTTP クライアントを使用するには、`url-connection-client` アーティファクトの依存関係スニペットを置き換えてください。たとえば、次のスニペットでは [NettyNioAsyncHttpClient](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/http/nio/netty/NettyNioAsyncHttpClient.html) の実装が取り込まれています。

```
    <dependency>
        <groupId>software.amazon.awssdk</groupId>
        <artifactId>netty-nio-client</artifactId>
    </dependency>
```

## メタデータクライアントを使用する
<a name="examples-ec2-IMDS-use"></a>

### メタデータクライアントをインスタンス化する
<a name="examples-ec2-IMDS-use-create"></a>

クラスパスに `SdkHttpClient` インタフェースの実装が 1 つしかない場合は、同期 `Ec2MetadataClient` のインスタンスをインスタンス化できます。そのためには、以下のスニペットに示すように静的 `Ec2MetadataClient#create()` メソッドを呼び出します。

```
Ec2MetadataClient client = Ec2MetadataClient.create(); // 'Ec2MetadataAsyncClient#create' is the asynchronous version.
```

アプリケーションに `SdkHttpClient` または `SdkHttpAsyncClient` インターフェースの実装が複数ある場合は、[設定可能な HTTP クライアント](#examples-ec2-IMDS-features-http) セクションに示されているように、メタデータクライアントが使用する実装を指定する必要があります。

**注記**  
Amazon S3 などのほとんどのサービスクライアントでは、SDK for Java は `SdkHttpClient` または `SdkHttpAsyncClient` インターフェイスの実装を自動的に追加します。メタデータクライアントが同じ実装を使用している場合は、`Ec2MetadataClient#create()` は問題なく動作します。別の実装が必要な場合は、メタデータクライアントの作成時にその実装を指定する必要があります。

### リクエストを送信する
<a name="examples-ec2-IMDS-use-req"></a>

インスタンスメタデータを取得するには、`EC2MetadataClient` クラスをインスタンス化し、[インスタンスメタデータカテゴリ](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instancedata-data-categories.html)を指定するパスパラメータを使用して `get` メソッドを呼び出します。

次の例では、`ami-id` キーに関連付けられた値をコンソールに出力します。

```
Ec2MetadataClient client = Ec2MetadataClient.create();
Ec2MetadataResponse response = client.get("/latest/meta-data/ami-id");
System.out.println(response.asString());
client.close(); // Closes the internal resources used by the Ec2MetadataClient class.
```

パスが無効な場合、`get` メソッドは例外を投げます。

`close` 同じクライアントインスタンスを複数のリクエストに再利用し、リソースを解放する必要がなくなったらクライアントを呼び出します。クローズメソッドが呼び出されると、クライアントインスタンスは使用できなくなります。

### レスポンスを解析する
<a name="examples-ec2-IMDS-use-pares"></a>

EC2 インスタンスメタデータはさまざまな形式で出力できます。プレーンテキストと JSON が最も一般的に使用される形式です。メタデータクライアントには、これらの形式を処理する方法が用意されています。

次の例に示すように、`asString` メソッドを使用してデータを Java 文字列として取得します。`asList` メソッドを使用して、複数行を返すプレーンテキストレスポンスを区切ることもできます。

```
Ec2MetadataClient client = Ec2MetadataClient.create();
Ec2MetadataResponse response = client.get("/latest/meta-data/");
String fullResponse = response.asString();
List<String> splits = response.asList();
```

レスポンスが JSON の場合は、次のコードスニペットに示すように、`Ec2MetadataResponse#asDocument` メソッドを使用して JSON レスポンスを解析して[ドキュメント](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/core/document/Document.html)インスタンスにします。

```
Document fullResponse = response.asDocument();
```

メタデータの形式が JSON でない場合は例外が発生します。レスポンスが正常に解析されたら、[ドキュメント API](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/core/document/package-summary.html) を使用してレスポンスをより詳細に調べることができます。JSON 形式のレスポンスを返すメタデータカテゴリについては、インスタンスの「[metadata category chart](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instancedata-data-categories.html)」を参照してください。

## メタデータクライアントを設定する
<a name="examples-ec2-IMDS-config"></a>

### 再試行
<a name="examples-ec2-IMDS-config-retries"></a>

メタデータクライアントには再試行メカニズムを設定できます。そうすることで、クライアントは予期しない理由で失敗したリクエストを自動的に再試行できます。デフォルトでは、クライアントは失敗したリクエストに対し、エクスポネンシャルバックオフ時間を置いて 3 回再試行します。

ユースケースで別の再試行メカニズムが必要な場合は、ビルダーの `retryPolicy` メソッドを使用してクライアントをカスタマイズできます。たとえば、次の例は、試行間隔が 2 秒、再試行が 5 回になるように設定された同期クライアントを示しています。

```
BackoffStrategy fixedBackoffStrategy = FixedDelayBackoffStrategy.create(Duration.ofSeconds(2));
Ec2MetadataClient client =
    Ec2MetadataClient.builder()
                     .retryPolicy(retryPolicyBuilder -> retryPolicyBuilder.numRetries(5)
                                                                           .backoffStrategy(fixedBackoffStrategy))
                     .build();
```

メタデータクライアントで使用できる [BackoffStrategies](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/core/retry/backoff/package-summary.html) はいくつかあります。

次のスニペットに示すように、リトライメカニズムを完全に無効にすることもできます。

```
Ec2MetadataClient client =
    Ec2MetadataClient.builder()
                    .retryPolicy(Ec2MetadataRetryPolicy.none())
                    .build();
```

`Ec2MetadataRetryPolicy#none()` を使用すると、メタデータクライアントが再試行しないように、デフォルトの再試行ポリシーが無効になります。

### IP バージョン
<a name="examples-ec2-IMDS-config-ipversion"></a>

デフォルトでは、メタデータクライアントは `http://169.254.169.254` の IPV4 エンドポイントを使用します。IPV6 バージョンを使用するようにクライアントを変更するには、ビルダーの `endpointMode` または `endpoint` メソッドを使用します。ビルダーで両方のメソッドが呼び出されると、例外が発生します。

次の例は、両方の IPV6 オプションを示しています。

```
Ec2MetadataClient client =
    Ec2MetadataClient.builder()
                     .endpointMode(EndpointMode.IPV6)
                     .build();
```

```
Ec2MetadataClient client =
    Ec2MetadataClient.builder()
                     .endpoint(URI.create("http://[fd00:ec2::254]"))
                     .build();
```

## 主な特徴
<a name="examples-ec2-IMDS-features"></a>

### 非同期クライアント
<a name="examples-ec2-IMDS-features-async"></a>

ノンブロッキングバージョンのクライアントを使用するには、`Ec2MetadataAsyncClient` クラスのインスタンスをインスタンス化します。次の例のコードは、デフォルト設定で非同期クライアントを作成し、`get` メソッドを使用して `ami-id` キーの値を取得します。

```
Ec2MetadataAsyncClient asyncClient = Ec2MetadataAsyncClient.create();
CompletableFuture<Ec2MetadataResponse> response = asyncClient.get("/latest/meta-data/ami-id");
```

`get` メソッドから返された `java.util.concurrent.CompletableFuture` は、レスポンスが返された時点で完了します。次の例では、`ami-id` メタデータをコンソールに出力します。

```
response.thenAccept(metadata -> System.out.println(metadata.asString()));
```

### 設定可能な HTTP クライアント
<a name="examples-ec2-IMDS-features-http"></a>

各メタデータクライアントのビルダーには、カスタマイズされた HTTP クライアントを提供するために使用できる `httpClient` メソッドがあります。

次の例はカスタム `UrlConnectionHttpClient` インスタンスのコードを示しています。

```
SdkHttpClient httpClient =
    UrlConnectionHttpClient.builder()
                           .socketTimeout(Duration.ofMinutes(5))
                           .proxyConfiguration(proxy -> proxy.endpoint(URI.create("http://proxy.example.net:8888"))))
                           .build();
Ec2MetadataClient metaDataClient =
    Ec2MetadataClient.builder()
                     .httpClient(httpClient)
                     .build();
// Use the metaDataClient instance.
metaDataClient.close();   // Close the instance when no longer needed.
```

次の例は、非同期メタデータクライアントを使用するカスタム `NettyNioAsyncHttpClient` インスタンスのコードを示しています。

```
SdkAsyncHttpClient httpAsyncClient = 
    NettyNioAsyncHttpClient.builder()
                           .connectionTimeout(Duration.ofMinutes(5))
                           .maxConcurrency(100)
                           .build();
Ec2MetadataAsyncClient asyncMetaDataClient =
    Ec2MetadataAsyncClient.builder()
                          .httpClient(httpAsyncClient)
                          .build();
// Use the asyncMetaDataClient instance.
asyncMetaDataClient.close();   // Close the instance when no longer needed.
```

このガイドの [で HTTP クライアントを設定する AWS SDK for Java 2.x](http-configuration.md) トピックでは、SDK for Java で使用可能な HTTP クライアントの設定方法について詳しく説明しています。

### トークンキャッシュ
<a name="examples-ec2-IMDS-features-token"></a>

メタデータクライアントは IMDSv2 を使用するため、すべてのリクエストはセッションに関連付けられます。セッションは、メタデータクライアントが管理する有効期限のあるトークンによって定義されます。メタデータをリクエストするたびに、トークンは有効期限が切れるまで自動的に再利用されます。

デフォルトでは、トークンは 6 時間 (21,600 秒) 持続します。特定のユースケースで高度な設定が必要でない限り、有効期間をデフォルト値のままにしておくことをお勧めします。

必要に応じて、`tokenTtl` ビルダーメソッドを使用して期間を設定します。たとえば、次のスニペットのコードでは、セッション期間が 5 分のクライアントを作成します。

```
Ec2MetadataClient client =
    Ec2MetadataClient.builder()
                     .tokenTtl(Duration.ofMinutes(5))
                     .build();
```

ビルダーで `tokenTtl` メソッドを呼び出さない場合は、代わりにデフォルトの継続時間である 21,600 が使用されます。

# の使用 IAM
<a name="examples-iam"></a>

このセクションでは、 AWS SDK for Java 2.x を使用した programming AWS Identity and Access Management (IAM) の例を示します。

 AWS Identity and Access Management (IAM) を使用すると、ユーザーの AWS サービスとリソースへのアクセスを安全に制御できます。を使用すると IAM、 AWS ユーザーとグループを作成および管理し、アクセス許可を使用して AWS リソースへのアクセスを許可または拒否できます。の詳細なガイドについては IAM、 [IAM ユーザーガイド](https://docs.aws.amazon.com//IAM/latest/UserGuide/introduction.html)を参照してください。

次の例には各手法を示すのに必要なコードのみが含まれます。[完全なサンプルコードは GitHub で入手できます](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/javav2)。そこから、単一のソースファイルをダウンロードするかリポジトリをローカルにクローン作成して、ビルドし実行するためのすべての例を取得できます。

**Topics**
+ [IAM アクセスキーを管理する](examples-iam-access-keys.md)
+ [IAM ユーザーを管理する](examples-iam-users.md)
+ [IAM ポリシーを作成する](feature-iam-policy-builder.md)
+ [IAM ポリシーの使用](examples-iam-policies.md)
+ [IAM サーバー証明書の使用](examples-iam-server-certificates.md)

# IAM アクセスキーを管理する
<a name="examples-iam-access-keys"></a>

## アクセスキーの作成
<a name="create-an-access-key"></a>

IAM アクセスキーを作成するには、`IamClient’s` `createAccessKey` メソッドを [https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/iam/model/CreateAccessKeyRequest.html](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/iam/model/CreateAccessKeyRequest.html) オブジェクトを使用して呼び出します。

**注記**  
** はグローバルサービスであるため、** が呼び出せるように、リージョンを `IamClient`AWS\$1GLOBALIAM を設定する必要があります。

 **インポート** 

```
import software.amazon.awssdk.services.iam.model.CreateAccessKeyRequest;
import software.amazon.awssdk.services.iam.model.CreateAccessKeyResponse;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.iam.IamClient;
import software.amazon.awssdk.services.iam.model.IamException;
```

 **Code** 

```
    public static String createIAMAccessKey(IamClient iam,String user) {

        try {
            CreateAccessKeyRequest request = CreateAccessKeyRequest.builder()
                .userName(user).build();

            CreateAccessKeyResponse response = iam.createAccessKey(request);
           String keyId = response.accessKey().accessKeyId();
           return keyId;

        } catch (IamException e) {
            System.err.println(e.awsErrorDetails().errorMessage());
            System.exit(1);
        }
        return "";
    }
```

[GitHub](https://github.com/awsdocs/aws-doc-sdk-examples/blob/f807d60010caf3d14fe4cd0801b842fb8e9511ca/javav2/example_code/iam/src/main/java/com/example/iam/CreateAccessKey.java) で完全な例をご覧ください。

## アクセスキーの一覧表示
<a name="list-access-keys"></a>

特定のユーザーのアクセスキーを一覧表示するには、キーの一覧表示の対象となるユーザー名を含む [https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/iam/model/ListAccessKeysRequest.html](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/iam/model/ListAccessKeysRequest.html) オブジェクトを作成し、それを `IamClient’s` `listAccessKeys` メソッドに渡します。

**注記**  
ユーザー名を `listAccessKeys` に渡さない場合は、リクエストに署名した AWS アカウント に関連付けられているアクセスキーの一覧表示を試行します。

 **インポート** 

```
import software.amazon.awssdk.services.iam.model.AccessKeyMetadata;
import software.amazon.awssdk.services.iam.model.IamException;
import software.amazon.awssdk.services.iam.model.ListAccessKeysRequest;
import software.amazon.awssdk.services.iam.model.ListAccessKeysResponse;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.iam.IamClient;
```

 **Code** 

```
    public static void listKeys( IamClient iam,String userName ){

        try {
            boolean done = false;
            String newMarker = null;

            while (!done) {
                ListAccessKeysResponse response;

            if(newMarker == null) {
                ListAccessKeysRequest request = ListAccessKeysRequest.builder()
                        .userName(userName).build();
                response = iam.listAccessKeys(request);
            } else {
                ListAccessKeysRequest request = ListAccessKeysRequest.builder()
                        .userName(userName)
                        .marker(newMarker).build();
                response = iam.listAccessKeys(request);
            }

            for (AccessKeyMetadata metadata :
                    response.accessKeyMetadata()) {
                System.out.format("Retrieved access key %s",
                        metadata.accessKeyId());
            }

            if (!response.isTruncated()) {
                done = true;
            } else {
                newMarker = response.marker();
            }
        }

        } catch (IamException e) {
            System.err.println(e.awsErrorDetails().errorMessage());
            System.exit(1);
        }
    }
```

`listAccessKeys` の結果はページ分割されます (デフォルトで最大 1 回の呼び出しごとに 100 レコード)。返された [https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/iam/model/ListAccessKeysResponse.html](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/iam/model/ListAccessKeysResponse.html) オブジェクトで `isTruncated` を呼び出し、より少ない結果を返されたクエリが利用可能かどうか確認することができます。利用可能な場合は、`marker` で `ListAccessKeysResponse` を呼び出して、新しいリクエストを作成するときに使用します。この新しいリクエストを `listAccessKeys` の次の呼び出しで使用します。

[GitHub](https://github.com/awsdocs/aws-doc-sdk-examples/blob/f807d60010caf3d14fe4cd0801b842fb8e9511ca/javav2/example_code/iam/src/main/java/com/example/iam/ListAccessKeys.java) で完全な例をご覧ください。

## アクセスキーの最終使用時刻の取得
<a name="retrieve-an-access-key-s-last-used-time"></a>

アクセスキーが最後に使用された時刻を取得するには、そのアクセスキーの ID ([https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/iam/model/GetAccessKeyLastUsedRequest.html](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/iam/model/GetAccessKeyLastUsedRequest.html) オブジェクトの使用時に渡すことができる) で `IamClient’s` `getAccessKeyLastUsed` メソッドを呼び出します。

返された [https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/iam/model/GetAccessKeyLastUsedResponse.html](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/iam/model/GetAccessKeyLastUsedResponse.html) オブジェクトを使用して、キーの最終使用時刻を取得できます。

 **インポート** 

```
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.iam.IamClient;
import software.amazon.awssdk.services.iam.model.GetAccessKeyLastUsedRequest;
import software.amazon.awssdk.services.iam.model.GetAccessKeyLastUsedResponse;
import software.amazon.awssdk.services.iam.model.IamException;
```

 **Code** 

```
    public static void getAccessKeyLastUsed(IamClient iam, String accessId ){

        try {
            GetAccessKeyLastUsedRequest request = GetAccessKeyLastUsedRequest.builder()
                    .accessKeyId(accessId).build();

            GetAccessKeyLastUsedResponse response = iam.getAccessKeyLastUsed(request);

            System.out.println("Access key was last used at: " +
                    response.accessKeyLastUsed().lastUsedDate());

        } catch (IamException e) {
            System.err.println(e.awsErrorDetails().errorMessage());
            System.exit(1);
        }
        System.out.println("Done");
    }
```

[GitHub](https://github.com/awsdocs/aws-doc-sdk-examples/blob/f807d60010caf3d14fe4cd0801b842fb8e9511ca/javav2/example_code/iam/src/main/java/com/example/iam/AccessKeyLastUsed.java) で完全な例をご覧ください。

## アクセスキーのアクティブ化または非アクティブ化
<a name="iam-access-keys-update"></a>

アクセスキーをアクティブ化または非アクティブ化するには、[https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/iam/model/UpdateAccessKeyRequest.html](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/iam/model/UpdateAccessKeyRequest.html)オブジェクトを作成し、アクセスキー ID、オプションでユーザー名、また目的の [https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/iam/model/StatusType.html](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/iam/model/StatusType.html) を渡して、次にそのリクエストオブジェクトを `IamClient’s` `updateAccessKey` メソッドに渡します。

 **インポート** 

```
import software.amazon.awssdk.services.iam.model.IamException;
import software.amazon.awssdk.services.iam.model.StatusType;
import software.amazon.awssdk.services.iam.model.UpdateAccessKeyRequest;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.iam.IamClient;
```

 **Code** 

```
       public static void updateKey(IamClient iam, String username, String accessId, String status ) {

          try {
              if (status.toLowerCase().equalsIgnoreCase("active")) {
                  statusType = StatusType.ACTIVE;
              } else if (status.toLowerCase().equalsIgnoreCase("inactive")) {
                  statusType = StatusType.INACTIVE;
              } else {
                  statusType = StatusType.UNKNOWN_TO_SDK_VERSION;
              }
              UpdateAccessKeyRequest request = UpdateAccessKeyRequest.builder()
                .accessKeyId(accessId)
                .userName(username)
                .status(statusType)
                .build();

              iam.updateAccessKey(request);

              System.out.printf(
                "Successfully updated the status of access key %s to" +
                        "status %s for user %s", accessId, status, username);

        } catch (IamException e) {
            System.err.println(e.awsErrorDetails().errorMessage());
            System.exit(1);
        }
    }
```

[GitHub](https://github.com/awsdocs/aws-doc-sdk-examples/blob/f807d60010caf3d14fe4cd0801b842fb8e9511ca/javav2/example_code/iam/src/main/java/com/example/iam/UpdateAccessKey.java) で完全な例をご覧ください。

## アクセスキーの削除
<a name="delete-an-access-key"></a>

アクセスキーを完全に削除するには、`IamClient’s` `deleteKey` メソッドを呼び出し、それにアクセスキーの ID とユーザーネームを含む [https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/iam/model/DeleteAccessKeyRequest.html](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/iam/model/DeleteAccessKeyRequest.html) を渡します。

**注記**  
削除してしまうと、キーは取得することも使用することもできなくなります。後で再度アクティブ化できるようキーを一時的に非アクティブ化するには、代わりに [`updateAccessKey`](#iam-access-keys-update) メソッドを使用します。

 **インポート** 

```
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.iam.IamClient;
import software.amazon.awssdk.services.iam.model.DeleteAccessKeyRequest;
import software.amazon.awssdk.services.iam.model.IamException;
```

 **Code** 

```
    public static void deleteKey(IamClient iam ,String username, String accessKey ) {

        try {
            DeleteAccessKeyRequest request = DeleteAccessKeyRequest.builder()
                    .accessKeyId(accessKey)
                    .userName(username)
                    .build();

            iam.deleteAccessKey(request);
            System.out.println("Successfully deleted access key " + accessKey +
                " from user " + username);

        } catch (IamException e) {
            System.err.println(e.awsErrorDetails().errorMessage());
            System.exit(1);
        }
    }
```

[GitHub](https://github.com/awsdocs/aws-doc-sdk-examples/blob/f807d60010caf3d14fe4cd0801b842fb8e9511ca/javav2/example_code/iam/src/main/java/com/example/iam/DeleteAccessKey.java) で完全な例をご覧ください。

## 詳細情報
<a name="more-information"></a>
+  IAM API リファレンスの [CreateAccessKey](https://docs.aws.amazon.com/IAM/latest/APIReference/API_CreateAccessKey.html)
+  IAM API リファレンスの [ListAccessKeys](https://docs.aws.amazon.com/IAM/latest/APIReference/API_ListAccessKeys.html)
+  IAM API リファレンスの [GetAccessKeyLastUsed](https://docs.aws.amazon.com/IAM/latest/APIReference/API_GetAccessKeyLastUsed.html)
+  IAM API リファレンスの [UpdateAccessKey](https://docs.aws.amazon.com/IAM/latest/APIReference/API_UpdateAccessKey.html)
+  IAM API リファレンスの [DeleteAccessKey](https://docs.aws.amazon.com/IAM/latest/APIReference/API_DeleteAccessKey.html)

# IAM ユーザーを管理する
<a name="examples-iam-users"></a>

## ユーザーの作成
<a name="creating-a-user"></a>

新しい IAM ユーザーを作成するには、ユーザー名を含む [CreateUserRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/iam/model/CreateUserRequest.html) オブジェクトを使用して、IamClient の `createUser` メソッドにユーザー名を渡します。

 **インポート** 

```
import software.amazon.awssdk.core.waiters.WaiterResponse;
import software.amazon.awssdk.services.iam.model.CreateUserRequest;
import software.amazon.awssdk.services.iam.model.CreateUserResponse;
import software.amazon.awssdk.services.iam.model.IamException;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.iam.IamClient;
import software.amazon.awssdk.services.iam.waiters.IamWaiter;
import software.amazon.awssdk.services.iam.model.GetUserRequest;
import software.amazon.awssdk.services.iam.model.GetUserResponse;
```

 **Code** 

```
    public static String createIAMUser(IamClient iam, String username ) {

        try {
            // Create an IamWaiter object
            IamWaiter iamWaiter = iam.waiter();

            CreateUserRequest request = CreateUserRequest.builder()
                    .userName(username)
                    .build();

            CreateUserResponse response = iam.createUser(request);

            // Wait until the user is created
            GetUserRequest userRequest = GetUserRequest.builder()
                    .userName(response.user().userName())
                    .build();

            WaiterResponse<GetUserResponse> waitUntilUserExists = iamWaiter.waitUntilUserExists(userRequest);
            waitUntilUserExists.matched().response().ifPresent(System.out::println);
            return response.user().userName();

        } catch (IamException e) {
            System.err.println(e.awsErrorDetails().errorMessage());
            System.exit(1);
        }
       return "";
    }
```

[GitHub](https://github.com/awsdocs/aws-doc-sdk-examples/blob/cf25559da654a7b74bec039c0ab9397dc5951dd4/javav2/example_code/iam/src/main/java/com/example/iam/CreateUser.java) で完全な例をご覧ください。

## ユーザーのリスト取得
<a name="listing-users"></a>

アカウントの IAM ユーザーを一覧表示するには、新しい [ListUsersRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/iam/model/ListUsersRequest.html) を作成して、それを IamClient の `listUsers` メソッドに渡します。返された `users`ListUsersResponse[ オブジェクトで ](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/iam/model/ListUsersResponse.html) を呼び出すことでユーザーのリストを取得できます。

`listUsers` によって返されたユーザーのリストはページ分割されます。取得できる結果がさらにあることを確認するには、応答オブジェクトの `isTruncated` メソッドを呼び出します。`true` が返った場合は、応答オブジェクトの `marker()` メソッドを呼び出します。マーカー値を使用して、新しいリクエストオブジェクトを作成します。次に、`listUsers` メソッドを新しいリクエストで再度呼び出します。

 **インポート** 

```
import software.amazon.awssdk.services.iam.model.IamException;
import software.amazon.awssdk.services.iam.model.ListUsersRequest;
import software.amazon.awssdk.services.iam.model.ListUsersResponse;
import software.amazon.awssdk.services.iam.model.User;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.iam.IamClient;
```

 **Code** 

```
    public static void listAllUsers(IamClient iam ) {

        try {

             boolean done = false;
             String newMarker = null;

             while(!done) {
                ListUsersResponse response;

                if (newMarker == null) {
                    ListUsersRequest request = ListUsersRequest.builder().build();
                    response = iam.listUsers(request);
                } else {
                    ListUsersRequest request = ListUsersRequest.builder()
                        .marker(newMarker).build();
                    response = iam.listUsers(request);
                }

                for(User user : response.users()) {
                 System.out.format("\n Retrieved user %s", user.userName());
                }

                if(!response.isTruncated()) {
                  done = true;
                } else {
                    newMarker = response.marker();
                }
            }
        } catch (IamException e) {
            System.err.println(e.awsErrorDetails().errorMessage());
            System.exit(1);
        }
    }
```

[GitHub](https://github.com/awsdocs/aws-doc-sdk-examples/blob/cf25559da654a7b74bec039c0ab9397dc5951dd4/javav2/example_code/iam/src/main/java/com/example/iam/ListUsers.java) で完全な例をご覧ください。

## ユーザーの更新
<a name="updating-a-user"></a>

ユーザーを更新するには、IamClient オブジェクトの `updateUser` メソッドを呼び出し、それが取得する [UpdateUserRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/iam/model/UpdateUserRequest.html) オブジェクトを使用して、ユーザーの*名前*または*パス*を変更します。

 **インポート** 

```
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.iam.IamClient;
import software.amazon.awssdk.services.iam.model.IamException;
import software.amazon.awssdk.services.iam.model.UpdateUserRequest;
```

 **Code** 

```
    public static void updateIAMUser(IamClient iam, String curName,String newName ) {

        try {
            UpdateUserRequest request = UpdateUserRequest.builder()
                    .userName(curName)
                    .newUserName(newName)
                    .build();

            iam.updateUser(request);
            System.out.printf("Successfully updated user to username %s",
                newName);
        } catch (IamException e) {
            System.err.println(e.awsErrorDetails().errorMessage());
            System.exit(1);
        }
      }
```

[GitHub](https://github.com/awsdocs/aws-doc-sdk-examples/blob/cf25559da654a7b74bec039c0ab9397dc5951dd4/javav2/example_code/iam/src/main/java/com/example/iam/UpdateUser.java) で完全な例をご覧ください。

## ユーザーを削除する
<a name="deleting-a-user"></a>

ユーザーを削除するには、[UpdateUserRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/iam/model/UpdateUserRequest.html) オブジェクトに削除するユーザー名を設定して、IamClient の `deleteUser` リクエストを呼び出します。

 **インポート** 

```
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.iam.IamClient;
import software.amazon.awssdk.services.iam.model.DeleteUserRequest;
import software.amazon.awssdk.services.iam.model.IamException;
```

 **Code** 

```
    public static void deleteIAMUser(IamClient iam, String userName) {

        try {
            DeleteUserRequest request = DeleteUserRequest.builder()
                    .userName(userName)
                    .build();

            iam.deleteUser(request);
            System.out.println("Successfully deleted IAM user " + userName);
        } catch (IamException e) {
            System.err.println(e.awsErrorDetails().errorMessage());
            System.exit(1);
        }
    }
```

[GitHub](https://github.com/awsdocs/aws-doc-sdk-examples/blob/cf25559da654a7b74bec039c0ab9397dc5951dd4/javav2/example_code/iam/src/main/java/com/example/iam/DeleteUser.java) で完全な例をご覧ください。

## 詳細情報
<a name="more-information"></a>
+  「IAM ユーザーガイド」の [IAM ユーザー](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_users.html)
+  IAM ユーザーガイドの [IAM ユーザーの管理](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_users_manage.html)
+  IAM API リファレンスの [CreateUser](https://docs.aws.amazon.com/IAM/latest/APIReference/API_CreateUser.html)
+  IAM API リファレンスの [ListUsers](https://docs.aws.amazon.com/IAM/latest/APIReference/API_ListUsers.html)
+  IAM API リファレンスの [UpdateUser](https://docs.aws.amazon.com/IAM/latest/APIReference/API_UpdateUser.html)
+  IAM API リファレンスの [DeleteUser](https://docs.aws.amazon.com/IAM/latest/APIReference/API_DeleteUser.html)

# を使用して IAM ポリシーを作成する AWS SDK for Java 2.x
<a name="feature-iam-policy-builder"></a>

[IAM Policy Builder API](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/policybuilder/iam/package-summary.html) は、Java で [IAM ポリシー](https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html)を構築して AWS Identity and Access Management (IAM) にアップロードするために使用できるライブラリです。

この API では、JSON 文字列を手動で組み立てたりファイルを読み取ったりして IAM ポリシーを構築する代わりに、クライアント側のオブジェクト指向の方法で JSON 文字列を生成します。JSON 形式の既存の IAM ポリシーを読み取ると、API はそのポリシーを [IamPolicy](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/policybuilder/iam/IamPolicy.html) インスタンスに変換して処理します。

IAM Policy Builder API は SDK のバージョン 2.20.105 で利用できるようになったため、Maven ビルドファイルではそのバージョンまたはそれ以降のバージョンを使用してください。SDK の最新バージョン番号は [Maven central にリスト](https://central.sonatype.com/artifact/software.amazon.awssdk/iam-policy-builder)があります。

次のスニペットは、Maven `pom.xml` ファイルの依存関係ブロック例を示しています。これにより、IAM Policy Builder API をプロジェクトで使用できるようになります。

```
<dependency>
    <groupId>software.amazon.awssdk</groupId>
    <artifactId>iam-policy-builder</artifactId>
    <version>2.27.21</version>
</dependency>
```

## `IamPolicy` を作成します。
<a name="iam-policy-builder-create"></a>

このセクションでは、IAM Policy Builder API を使用してポリシーを構築する方法の例をいくつか示します。

以下の各例では、`[IamPolicy.Builder](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/policybuilder/iam/IamPolicy.Builder.html)` から始めて、`addStatement` メソッドを使用して 1 つ以上のステートメントを追加します。このパターンに従い、[IamStatement.Builder](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/policybuilder/iam/IamStatement.Builder.html) にはエフェクト、アクション、リソース、条件をステートメントに追加するメソッドが用意されています。

### 例: 時間ベースのポリシーを作成する
<a name="iam-policy-builder-create-ex-time-based"></a>

次の例では、2 つの時点間の Amazon DynamoDB `GetItem` アクションを許可するアイデンティティベースのポリシーを作成します。

```
    public String timeBasedPolicyExample() {
        IamPolicy policy = IamPolicy.builder()
                .addStatement(b -> b
                        .effect(IamEffect.ALLOW)
                        .addAction("dynamodb:GetItem")
                        .addResource(IamResource.ALL)
                        .addCondition(b1 -> b1
                                .operator(IamConditionOperator.DATE_GREATER_THAN)
                                .key("aws:CurrentTime")
                                .value("2020-04-01T00:00:00Z"))
                        .addCondition(b1 -> b1
                                .operator(IamConditionOperator.DATE_LESS_THAN)
                                .key("aws:CurrentTime")
                                .value("2020-06-30T23:59:59Z")))
                .build();

        // Use an IamPolicyWriter to write out the JSON string to a more readable format.
        return policy.toJson(IamPolicyWriter.builder()
                        .prettyPrint(true)
                        .build());
    }
```

#### JSON 出力
<a name="iam-builder-ex-json-date"></a>

前の例の最後のステートメントは、次の JSON 文字列を返します。

[この例](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_examples_aws-dates.html)の詳細については、「*AWS Identity and Access Management ユーザーガイド*」を参照してください。

------
#### [ JSON ]

****  

```
{
    "Version":"2012-10-17",		 	 	 
    "Statement": {
        "Effect": "Allow",
        "Action": "dynamodb:GetItem",
        "Resource": "*",
        "Condition": {
            "DateGreaterThan": {
                "aws:CurrentTime": "2020-04-01T00:00:00Z"
            },
            "DateLessThan": {
                "aws:CurrentTime": "2020-06-30T23:59:59Z"
            }
        }
    }
}
```

------

### 例: 複数の条件を指定する
<a name="iam-policy-builder-create-ex-multi-conditions"></a>

次の例では、特定の DynamoDB 属性へのアクセスを許可する ID ベースポリシーを作成する方法を示します。ポリシーには 2 つの条件が含まれています。

```
    public String multipleConditionsExample() {
        IamPolicy policy = IamPolicy.builder()
                .addStatement(b -> b
                        .effect(IamEffect.ALLOW)
                        .addAction("dynamodb:GetItem")
                        .addAction("dynamodb:BatchGetItem")
                        .addAction("dynamodb:Query")
                        .addAction("dynamodb:PutItem")
                        .addAction("dynamodb:UpdateItem")
                        .addAction("dynamodb:DeleteItem")
                        .addAction("dynamodb:BatchWriteItem")
                        .addResource("arn:aws:dynamodb:*:*:table/table-name")
                        .addConditions(IamConditionOperator.STRING_EQUALS.addPrefix("ForAllValues:"),
                                "dynamodb:Attributes",
                                List.of("column-name1", "column-name2", "column-name3"))
                        .addCondition(b1 -> b1.operator(IamConditionOperator.STRING_EQUALS.addSuffix("IfExists"))
                                .key("dynamodb:Select")
                                .value("SPECIFIC_ATTRIBUTES")))
                .build();

        return policy.toJson(IamPolicyWriter.builder()
                .prettyPrint(true).build());
    }
```

#### JSON 出力
<a name="iam-builder-ex-json-multi-cond"></a>

前の例の最後のステートメントは、次の JSON 文字列を返します。

[この例](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_examples_dynamodb_attributes.html)の詳細については、「*AWS Identity and Access Management ユーザーガイド*」を参照してください。

------
#### [ JSON ]

****  

```
{
    "Version":"2012-10-17",		 	 	 
    "Statement": {
        "Effect": "Allow",
        "Action": [
            "dynamodb:GetItem",
            "dynamodb:BatchGetItem",
            "dynamodb:Query",
            "dynamodb:PutItem",
            "dynamodb:UpdateItem",
            "dynamodb:DeleteItem",
            "dynamodb:BatchWriteItem"
        ],
        "Resource": "arn:aws:dynamodb:*:*:table/table-name",
        "Condition": {
            "ForAllValues:StringEquals": {
                "dynamodb:Attributes": [
                    "column-name1",
                    "column-name2",
                    "column-name3"
                ]
            },
            "StringEqualsIfExists": {
                "dynamodb:Select": "SPECIFIC_ATTRIBUTES"
            }
        }
    }
}
```

------

### 例: プリンシパルを指定する
<a name="iam-policy-builder-create-ex-principals"></a>

次の例は、条件で指定されたものを除くすべてのプリンシパルのバケットへのアクセスを拒否するリソースベースのポリシーを作成する方法を示しています。

```
    public String specifyPrincipalsExample() {
        IamPolicy policy = IamPolicy.builder()
                .addStatement(b -> b
                        .effect(IamEffect.DENY)
                        .addAction("s3:*")
                        .addPrincipal(IamPrincipal.ALL)
                        .addResource("arn:aws:s3:::BUCKETNAME/*")
                        .addResource("arn:aws:s3:::BUCKETNAME")
                        .addCondition(b1 -> b1
                                .operator(IamConditionOperator.ARN_NOT_EQUALS)
                                .key("aws:PrincipalArn")
                                .value("arn:aws:iam::444455556666:user/user-name")))
                .build();
        return policy.toJson(IamPolicyWriter.builder()
                .prettyPrint(true).build());
    }
```

#### JSON 出力
<a name="iam-policy-builder-create-json-ex-principals"></a>

前の例の最後のステートメントは、次の JSON 文字列を返します。

[この例](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements_principal.html#principal-anonymous)の詳細については、「*AWS Identity and Access Management ユーザーガイド*」を参照してください。

------
#### [ JSON ]

****  

```
{
  "Version":"2012-10-17",		 	 	 
  "Statement" : {
    "Effect" : "Deny",
    "Principal" : "*",
    "Action" : "s3:*",
    "Resource" : [ "arn:aws:s3:::BUCKETNAME/*", "arn:aws:s3:::BUCKETNAME" ],
    "Condition" : {
      "ArnNotEquals" : {
        "aws:PrincipalArn" : "arn:aws:iam::444455556666:user/user-name"
      }
    }
  }
}
```

------

### 例: クロスアカウントアクセスを許可します。
<a name="iam-policy-builder-create-ex-cross-account"></a>

次の例は、アップロードされたオブジェクトの完全な所有者制御を維持しながら、他のユーザー AWS アカウント がバケットにオブジェクトをアップロードできるようにする方法を示しています。

```
    public String allowCrossAccountAccessExample() {
        IamPolicy policy = IamPolicy.builder()
                .addStatement(b -> b
                        .effect(IamEffect.ALLOW)
                        .addPrincipal(IamPrincipalType.AWS, "111122223333")
                        .addAction("s3:PutObject")
                        .addResource("arn:aws:s3:::amzn-s3-demo-bucket/*")
                        .addCondition(b1 -> b1
                                .operator(IamConditionOperator.STRING_EQUALS)
                                .key("s3:x-amz-acl")
                                .value("bucket-owner-full-control")))
                .build();
        return policy.toJson(IamPolicyWriter.builder()
                .prettyPrint(true).build());
    }
```

#### JSON 出力
<a name="iam-policy-builder-create-ex-json-cross-account"></a>

前の例の最後のステートメントは、次の JSON 文字列を返します。

[この例](https://docs.aws.amazon.com/AmazonS3/latest/userguide/example-bucket-policies.html#example-bucket-policies-acl-2)の詳細については、「*Amazon Simple Storage Service ユーザーガイド」を参照ください*。

------
#### [ JSON ]

****  

```
{
  "Version":"2012-10-17",		 	 	 
  "Statement" : {
    "Effect" : "Allow",
    "Principal" : {
      "AWS" : "111122223333"
    },
    "Action" : "s3:PutObject",
    "Resource" : "arn:aws:s3:::amzn-s3-demo-bucket/*",
    "Condition" : {
      "StringEquals" : {
        "s3:x-amz-acl" : "bucket-owner-full-control"
      }
    }
  }
}
```

------

## IAM で `IamPolicy` を使用する
<a name="iam-policy-builder-work-with-service"></a>

`IamPolicy` インスタンスを作成したら、[https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/iam/IamClient.html](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/iam/IamClient.html) を使用して IAM サービスを利用します。

次の例では、[IAM ID](https://docs.aws.amazon.com/IAM/latest/UserGuide/id.html) が `accountID` パラメータで指定されたアカウントの DynamoDB テーブルに項目を書き込むことを許可するポリシーを構築します。次に、ポリシーが JSON 文字列として IAM にアップロードされます。

```
    public String createAndUploadPolicyExample(IamClient iam, String accountID, String policyName) {
        // Build the policy.
        IamPolicy policy =
                IamPolicy.builder() // 'version' defaults to "2012-10-17".
                        .addStatement(IamStatement.builder()
                                .effect(IamEffect.ALLOW)
                                .addAction("dynamodb:PutItem")
                                .addResource("arn:aws:dynamodb:us-east-1:" + accountID + ":table/exampleTableName")
                                .build())
                        .build();
        // Upload the policy.
        iam.createPolicy(r -> r.policyName(policyName).policyDocument(policy.toJson()));
        return policy.toJson(IamPolicyWriter.builder().prettyPrint(true).build());
    }
```

次の例は、前述の例に基づいています。コードはポリシーをダウンロードし、ステートメントをコピーして変更することで新しいポリシーの基礎として使用します。その後、新しいポリシーがアップロードされます。

```
    public String createNewBasedOnExistingPolicyExample(IamClient iam, String accountID, String policyName, String newPolicyName) {

        String policyArn = "arn:aws:iam::" + accountID + ":policy/" + policyName;
        GetPolicyResponse getPolicyResponse = iam.getPolicy(r -> r.policyArn(policyArn));

        String policyVersion = getPolicyResponse.policy().defaultVersionId();
        GetPolicyVersionResponse getPolicyVersionResponse =
                iam.getPolicyVersion(r -> r.policyArn(policyArn).versionId(policyVersion));

        // Create an IamPolicy instance from the JSON string returned from IAM.
        String decodedPolicy = URLDecoder.decode(getPolicyVersionResponse.policyVersion().document(), StandardCharsets.UTF_8);
        IamPolicy policy = IamPolicy.fromJson(decodedPolicy);

            /*
             All IamPolicy components are immutable, so use the copy method that creates a new instance that
             can be altered in the same method call.

             Add the ability to get an item from DynamoDB as an additional action.
            */
        IamStatement newStatement = policy.statements().get(0).copy(s -> s.addAction("dynamodb:GetItem"));

        // Create a new statement that replaces the original statement.
        IamPolicy newPolicy = policy.copy(p -> p.statements(Arrays.asList(newStatement)));

        // Upload the new policy. IAM now has both policies.
        iam.createPolicy(r -> r.policyName(newPolicyName)
                .policyDocument(newPolicy.toJson()));

        return newPolicy.toJson(IamPolicyWriter.builder().prettyPrint(true).build());
    }
```

### IamClient
<a name="iam-policy-builder-work-with-serivce-create-client"></a>

前の例では、次のスニペットで示される `IamClient` 引数を使用します。

```
IamClient iam = IamClient.builder().region(Region.AWS_GLOBAL).build();
```

### JSON のポリシー
<a name="iam-policy-builder-work-with-serivce-json"></a>

例では次の JSON 文字列が返されます。

```
First example
{
  "Version": "2012-10-17",		 	 	 
  "Statement" : {
    "Effect" : "Allow",
    "Action" : "dynamodb:PutItem",
    "Resource" : "arn:aws:dynamodb:us-east-1:111122223333:table/exampleTableName"
  }
}

Second example
{
  "Version": "2012-10-17",		 	 	 
  "Statement" : {
    "Effect" : "Allow",
    "Action" : [ "dynamodb:PutItem", "dynamodb:GetItem" ],
    "Resource" : "arn:aws:dynamodb:us-east-1:111122223333:table/exampleTableName"
  }
}
```

# IAM ポリシーの使用
<a name="examples-iam-policies"></a>

## ポリシーの作成
<a name="create-a-policy"></a>

新しいポリシーを作成するには、[CreatePolicyRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/iam/model/CreatePolicyRequest.html) 内のポリシーの名前および JSON 形式のポリシードキュメントを IamClient の `createPolicy` メソッドに渡します。

 **インポート** 

```
import software.amazon.awssdk.core.waiters.WaiterResponse;
import software.amazon.awssdk.services.iam.model.CreatePolicyRequest;
import software.amazon.awssdk.services.iam.model.CreatePolicyResponse;
import software.amazon.awssdk.services.iam.model.GetPolicyRequest;
import software.amazon.awssdk.services.iam.model.GetPolicyResponse;
import software.amazon.awssdk.services.iam.model.IamException;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.iam.IamClient;
import software.amazon.awssdk.services.iam.waiters.IamWaiter;
```

 **Code** 

```
    public static String createIAMPolicy(IamClient iam, String policyName ) {

        try {
            // Create an IamWaiter object
            IamWaiter iamWaiter = iam.waiter();

            CreatePolicyRequest request = CreatePolicyRequest.builder()
                .policyName(policyName)
                .policyDocument(PolicyDocument).build();

            CreatePolicyResponse response = iam.createPolicy(request);

            // Wait until the policy is created
            GetPolicyRequest polRequest = GetPolicyRequest.builder()
                    .policyArn(response.policy().arn())
                    .build();

            WaiterResponse<GetPolicyResponse> waitUntilPolicyExists = iamWaiter.waitUntilPolicyExists(polRequest);
            waitUntilPolicyExists.matched().response().ifPresent(System.out::println);
            return response.policy().arn();

         } catch (IamException e) {
            System.err.println(e.awsErrorDetails().errorMessage());
            System.exit(1);
        }
        return "" ;
    }
```

[GitHub](https://github.com/awsdocs/aws-doc-sdk-examples/blob/e41bacfd5e671e7ef1a9f73e972540dc6a434664/javav2/example_code/iam/src/main/java/com/example/iam/CreatePolicy.java) で完全な例をご覧ください。

## ポリシーの取得
<a name="get-a-policy"></a>

既存のポリシーを取得するには、IamClient の `getPolicy` メソッドを呼び出して、[GetPolicyRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/iam/model/GetPolicyRequest.html) オブジェクト内のポリシーの ARN を渡します。

 **インポート** 

```
import software.amazon.awssdk.services.iam.model.GetPolicyRequest;
import software.amazon.awssdk.services.iam.model.GetPolicyResponse;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.iam.IamClient;
import software.amazon.awssdk.services.iam.model.IamException;
```

 **Code** 

```
    public static void getIAMPolicy(IamClient iam, String policyArn) {

        try {
            GetPolicyRequest request = GetPolicyRequest.builder()
                .policyArn(policyArn).build();

            GetPolicyResponse response = iam.getPolicy(request);
            System.out.format("Successfully retrieved policy %s",
                response.policy().policyName());

        } catch (IamException e) {
            System.err.println(e.awsErrorDetails().errorMessage());
            System.exit(1);
        }
    }
```

[GitHub](https://github.com/awsdocs/aws-doc-sdk-examples/blob/cf25559da654a7b74bec039c0ab9397dc5951dd4/javav2/example_code/iam/src/main/java/com/example/iam/GetPolicy.java) で完全な例をご覧ください。

## ロールポリシーのアタッチ
<a name="attach-a-role-policy"></a>

ポリシーを IAM [ロール](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles.html)にアタッチするには、IamClient の `attachRolePolicy` メソッドを呼び出し、それに [AttachRolePolicyRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/iam/model/AttachRolePolicyRequest.html) 内のロール名およびポリシー ARN を渡します。

 **インポート** 

```
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.iam.IamClient;
import software.amazon.awssdk.services.iam.model.IamException;
import software.amazon.awssdk.services.iam.model.AttachRolePolicyRequest;
import software.amazon.awssdk.services.iam.model.AttachedPolicy;
import software.amazon.awssdk.services.iam.model.ListAttachedRolePoliciesRequest;
import software.amazon.awssdk.services.iam.model.ListAttachedRolePoliciesResponse;
import java.util.List;
```

 **Code** 

```
    public static void attachIAMRolePolicy(IamClient iam, String roleName, String policyArn ) {

        try {

             ListAttachedRolePoliciesRequest request = ListAttachedRolePoliciesRequest.builder()
                    .roleName(roleName)
                    .build();

            ListAttachedRolePoliciesResponse  response = iam.listAttachedRolePolicies(request);
            List<AttachedPolicy> attachedPolicies = response.attachedPolicies();

            // Ensure that the policy is not attached to this role
            String polArn = "";
            for (AttachedPolicy policy: attachedPolicies) {
                polArn = policy.policyArn();
                if (polArn.compareTo(policyArn)==0) {
                   System.out.println(roleName +
                            " policy is already attached to this role.");
                    return;
                }
          }

            AttachRolePolicyRequest attachRequest =
                AttachRolePolicyRequest.builder()
                        .roleName(roleName)
                        .policyArn(policyArn)
                        .build();

            iam.attachRolePolicy(attachRequest);

            System.out.println("Successfully attached policy " + policyArn +
                " to role " + roleName);

         } catch (IamException e) {
                System.err.println(e.awsErrorDetails().errorMessage());
                System.exit(1);
          }

     System.out.println("Done");
    }
```

[GitHub](https://github.com/awsdocs/aws-doc-sdk-examples/blob/cf25559da654a7b74bec039c0ab9397dc5951dd4/javav2/example_code/iam/src/main/java/com/example/iam/AttachRolePolicy.java) で完全な例をご覧ください。

## アタッチ済みロールポリシーの一覧表示
<a name="list-attached-role-policies"></a>

ロールのアタッチ済みポリシーを一覧表示するには、IamClient の `listAttachedRolePolicies` メソッドを呼び出します。このメソッドは、ポリシーを一覧表示するロール名を含む [ListAttachedRolePoliciesRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/iam/model/ListAttachedRolePoliciesRequest.html) オブジェクトを受け取ります。

返された [ListAttachedRolePoliciesResponse](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/iam/model/ListAttachedRolePoliciesResponse.html) オブジェクトで `getAttachedPolicies` を呼び出し、アタッチ済みポリシーのリストを取得します。結果は切り捨てられる場合があります。`ListAttachedRolePoliciesResponse` オブジェクトの `isTruncated` メソッドが `true` を返す場合は、`ListAttachedRolePoliciesResponse` オブジェクトの `marker` メソッドを呼び出します。返るマーカーを使用して新しいリクエストを作成します。また、それを使用して `listAttachedRolePolicies` を再び呼び出し、結果の次のバッチを取得します。

 **インポート** 

```
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.iam.IamClient;
import software.amazon.awssdk.services.iam.model.IamException;
import software.amazon.awssdk.services.iam.model.AttachRolePolicyRequest;
import software.amazon.awssdk.services.iam.model.AttachedPolicy;
import software.amazon.awssdk.services.iam.model.ListAttachedRolePoliciesRequest;
import software.amazon.awssdk.services.iam.model.ListAttachedRolePoliciesResponse;
import java.util.List;
```

 **Code** 

```
    public static void attachIAMRolePolicy(IamClient iam, String roleName, String policyArn ) {

        try {

             ListAttachedRolePoliciesRequest request = ListAttachedRolePoliciesRequest.builder()
                    .roleName(roleName)
                    .build();

            ListAttachedRolePoliciesResponse  response = iam.listAttachedRolePolicies(request);
            List<AttachedPolicy> attachedPolicies = response.attachedPolicies();

            // Ensure that the policy is not attached to this role
            String polArn = "";
            for (AttachedPolicy policy: attachedPolicies) {
                polArn = policy.policyArn();
                if (polArn.compareTo(policyArn)==0) {
                   System.out.println(roleName +
                            " policy is already attached to this role.");
                    return;
                }
          }

            AttachRolePolicyRequest attachRequest =
                AttachRolePolicyRequest.builder()
                        .roleName(roleName)
                        .policyArn(policyArn)
                        .build();

            iam.attachRolePolicy(attachRequest);

            System.out.println("Successfully attached policy " + policyArn +
                " to role " + roleName);

         } catch (IamException e) {
                System.err.println(e.awsErrorDetails().errorMessage());
                System.exit(1);
          }

     System.out.println("Done");
    }
```

[GitHub](https://github.com/awsdocs/aws-doc-sdk-examples/blob/cf25559da654a7b74bec039c0ab9397dc5951dd4/javav2/example_code/iam/src/main/java/com/example/iam/AttachRolePolicy.java) で完全な例をご覧ください。

## ロールポリシーのデタッチ
<a name="detach-a-role-policy"></a>

ロールからポリシーをデタッチするには、IamClient の `detachRolePolicy` メソッドを呼び出し、それに [DetachRolePolicyRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/iam/model/DetachRolePolicyRequest.html) 内のロール名およびポリシー ARN を渡します。

 **インポート** 

```
import software.amazon.awssdk.services.iam.model.DetachRolePolicyRequest;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.iam.IamClient;
import software.amazon.awssdk.services.iam.model.IamException;
```

 **Code** 

```
    public static void detachPolicy(IamClient iam, String roleName, String policyArn ) {

        try {
            DetachRolePolicyRequest request = DetachRolePolicyRequest.builder()
                    .roleName(roleName)
                    .policyArn(policyArn)
                    .build();

            iam.detachRolePolicy(request);
            System.out.println("Successfully detached policy " + policyArn +
                " from role " + roleName);

        } catch (IamException e) {
            System.err.println(e.awsErrorDetails().errorMessage());
            System.exit(1);
        }
    }
```

[GitHub](https://github.com/awsdocs/aws-doc-sdk-examples/blob/cf25559da654a7b74bec039c0ab9397dc5951dd4/javav2/example_code/iam/src/main/java/com/example/iam/DetachRolePolicy.java) で完全な例をご覧ください。

## 詳細情報
<a name="more-information"></a>
+  IAM ユーザーガイドの [IAM ポリシーの概要](https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html)。
+ IAM ユーザーガイドの [AWS IAM ポリシーのリファレンス](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies.html)。
+  IAM API リファレンスの [CreatePolicy](https://docs.aws.amazon.com/IAM/latest/APIReference/API_CreatePolicy.html)
+  IAM API リファレンスの [GetPolicy](https://docs.aws.amazon.com/IAM/latest/APIReference/API_GetPolicy.html)
+  IAM API リファレンスの [AttachRolePolicy](https://docs.aws.amazon.com/IAM/latest/APIReference/API_AttachRolePolicy.html)
+  IAM API リファレンスの [ListAttachedRolePolicies](https://docs.aws.amazon.com/IAM/latest/APIReference/API_ListAttachedRolePolicies.html)
+  IAM API リファレンスの [DetachRolePolicy](https://docs.aws.amazon.com/IAM/latest/APIReference/API_DetachRolePolicy.html)

# IAM サーバー証明書の使用
<a name="examples-iam-server-certificates"></a>

でウェブサイトまたはアプリケーションへの HTTPS 接続を有効にするには AWS、SSL/TLS *サーバー証明書*が必要です。が提供するサーバー証明書、 AWS Certificate Manager または外部プロバイダーから取得したサーバー証明書を使用できます。

サーバー証明書のプロビジョニング、管理、デプロイ ACM には、 を使用することをお勧めします。 ACM を使用すると、証明書をリクエストし、 AWS リソースにデプロイして、 が証明書の更新 ACM を処理できます。が提供する証明書 ACM は無料です。詳細については ACM、[AWS Certificate Manager 「 ユーザーガイド](https://docs.aws.amazon.com/acm/latest/userguide/acm-overview.html)」を参照してください。

## サーバー証明書の取得
<a name="get-a-server-certificate"></a>

サーバー証明書を取得するには、IamClient の `getServerCertificate` メソッドを呼び出し、それに証明書の名前を含む [GetServerCertificateRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/iam/model/GetServerCertificateRequest.html) を渡します。

 **インポート** 

```
import software.amazon.awssdk.services.iam.model.GetServerCertificateRequest;
import software.amazon.awssdk.services.iam.model.GetServerCertificateResponse;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.iam.IamClient;
import software.amazon.awssdk.services.iam.model.IamException;
```

 **コード** 

```
    public static void getCertificate(IamClient iam,String certName ) {

        try {
            GetServerCertificateRequest request = GetServerCertificateRequest.builder()
                    .serverCertificateName(certName)
                    .build();

            GetServerCertificateResponse response = iam.getServerCertificate(request);
            System.out.format("Successfully retrieved certificate with body %s",
                response.serverCertificate().certificateBody());

         } catch (IamException e) {
            System.err.println(e.awsErrorDetails().errorMessage());
            System.exit(1);
        }
    }
```

[GitHub](https://github.com/awsdocs/aws-doc-sdk-examples/blob/0b1785e42949ebf959eaa0f0da4dc2a48f92ea25/javav2/example_code/iam/src/main/java/com/example/iam/GetServerCertificate.java) で完全な例をご覧ください。

## サーバー証明書の一覧表示
<a name="list-server-certificates"></a>

サーバー証明書を一覧表示するには、`listServerCertificates`ListServerCertificatesRequest[ を使用して IamClient の ](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/iam/model/ListServerCertificatesRequest.html) メソッドを呼び出します。これにより [ListServerCertificatesResponse](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/iam/model/ListServerCertificatesResponse.html) が返されます。

返された `ListServerCertificateResponse` オブジェクトの `serverCertificateMetadataList` メソッドを呼び出して、各証明書についての情報を取得するために使用できる [ServerCertificateMetadata](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/iam/model/ServerCertificateMetadata.html) オブジェクトの一覧を取得します。

結果は切り捨てられる場合があります。`ListServerCertificateResponse` オブジェクトの `isTruncated` メソッドが `true` を返す場合は、`ListServerCertificatesResponse` オブジェクトの `marker` メソッドを呼び出します。その後、マーカーを使用して新しいリクエストを作成します。この新しいリクエストを使用して、再度 `listServerCertificates` を呼び出し、結果の次のバッチを取得します。

 **インポート** 

```
import software.amazon.awssdk.services.iam.model.IamException;
import software.amazon.awssdk.services.iam.model.ListServerCertificatesRequest;
import software.amazon.awssdk.services.iam.model.ListServerCertificatesResponse;
import software.amazon.awssdk.services.iam.model.ServerCertificateMetadata;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.iam.IamClient;
```

 **コード** 

```
    public static void listCertificates(IamClient iam) {

        try {
            boolean done = false;
            String newMarker = null;

            while(!done) {
              ListServerCertificatesResponse response;

            if (newMarker == null) {
                ListServerCertificatesRequest request =
                        ListServerCertificatesRequest.builder().build();
                response = iam.listServerCertificates(request);
            } else {
                ListServerCertificatesRequest request =
                        ListServerCertificatesRequest.builder()
                                .marker(newMarker).build();
                response = iam.listServerCertificates(request);
            }

            for(ServerCertificateMetadata metadata :
                    response.serverCertificateMetadataList()) {
                System.out.printf("Retrieved server certificate %s",
                        metadata.serverCertificateName());
            }

            if(!response.isTruncated()) {
                done = true;
            } else {
                newMarker = response.marker();
            }
        }

        } catch (IamException e) {
            System.err.println(e.awsErrorDetails().errorMessage());
            System.exit(1);
        }
    }
```

[GitHub](https://github.com/awsdocs/aws-doc-sdk-examples/blob/0b1785e42949ebf959eaa0f0da4dc2a48f92ea25/javav2/example_code/iam/src/main/java/com/example/iam/ListServerCertificates.java) で完全な例をご覧ください。

## サーバー証明書の更新
<a name="update-a-server-certificate"></a>

サーバー証明書の名前やパスを更新するには、IamClient の `updateServerCertificate` メソッドを呼び出します。サーバー証明書の現在の名前および使用する新しい名前か新しいパスのいずれかを使って設定した [UpdateServerCertificateRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/iam/model/UpdateServerCertificateRequest.html) オブジェクトが使用されます。

 **インポート** 

```
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.iam.IamClient;
import software.amazon.awssdk.services.iam.model.IamException;
import software.amazon.awssdk.services.iam.model.UpdateServerCertificateRequest;
import software.amazon.awssdk.services.iam.model.UpdateServerCertificateResponse;
```

 **コード** 

```
    public static void updateCertificate(IamClient iam, String curName, String newName) {

        try {
            UpdateServerCertificateRequest request =
                UpdateServerCertificateRequest.builder()
                        .serverCertificateName(curName)
                        .newServerCertificateName(newName)
                        .build();

            UpdateServerCertificateResponse response =
                iam.updateServerCertificate(request);


            System.out.printf("Successfully updated server certificate to name %s",
                newName);

        } catch (IamException e) {
             System.err.println(e.awsErrorDetails().errorMessage());
             System.exit(1);
        }
     }
```

[GitHub](https://github.com/awsdocs/aws-doc-sdk-examples/blob/0b1785e42949ebf959eaa0f0da4dc2a48f92ea25/javav2/example_code/iam/src/main/java/com/example/iam/UpdateServerCertificate.java) で完全な例をご覧ください。

## サーバー証明書の削除
<a name="delete-a-server-certificate"></a>

サーバー証明書を削除するには、証明書の名前を含む [DeleteServerCertificateRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/iam/model/DeleteServerCertificateRequest.html) を使用して、IamClient の `deleteServerCertificate` メソッドを呼び出します。

 **インポート** 

```
import software.amazon.awssdk.services.iam.model.DeleteServerCertificateRequest;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.iam.IamClient;
import software.amazon.awssdk.services.iam.model.IamException;
```

 **コード** 

```
    public static void deleteCert(IamClient iam,String certName ) {

        try {
            DeleteServerCertificateRequest request =
                DeleteServerCertificateRequest.builder()
                        .serverCertificateName(certName)
                        .build();

            iam.deleteServerCertificate(request);
            System.out.println("Successfully deleted server certificate " +
                    certName);

        } catch (IamException e) {
            System.err.println(e.awsErrorDetails().errorMessage());
            System.exit(1);
        }
    }
```

[GitHub](https://github.com/awsdocs/aws-doc-sdk-examples/blob/0b1785e42949ebf959eaa0f0da4dc2a48f92ea25/javav2/example_code/iam/src/main/java/com/example/iam/DeleteServerCertificate.java) で完全な例をご覧ください。

## 詳細情報
<a name="more-information"></a>
+  IAM ユーザーガイド[のサーバー証明書の使用](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_server-certs.html) 
+  IAM API リファレンスの [GetServerCertificate](https://docs.aws.amazon.com/IAM/latest/APIReference/API_GetServerCertificate.html) 
+  IAM API リファレンスの [ListServerCertificates](https://docs.aws.amazon.com/IAM/latest/APIReference/API_ListServerCertificates.html) 
+  IAM API リファレンスの [UpdateServerCertificate](https://docs.aws.amazon.com/IAM/latest/APIReference/API_UpdateServerCertificate.html) 
+  IAM API リファレンスの [DeleteServerCertificate](https://docs.aws.amazon.com/IAM/latest/APIReference/API_DeleteServerCertificate.html) 
+  [AWS Certificate Manager ユーザーガイド](https://docs.aws.amazon.com/acm/latest/userguide/) 

# Kinesis を使用する
<a name="examples-kinesis"></a>

このセクションでは、AWS SDK for Java 2.x を使用して [Amazon Kinesis](https://docs.aws.amazon.com/kinesis/) をプログラムする例を示します。

Kinesis の詳細については、「[Amazon Kinesis デベロッパーガイド](https://docs.aws.amazon.com/streams/latest/dev/introduction.html)」を参照してください。

次の例には各手法を示すのに必要なコードのみが含まれます。[完全なサンプルコードは GitHub で入手できます](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/javav2)。そこから、単一のソースファイルをダウンロードするかリポジトリをローカルにクローン作成して、ビルドし実行するためのすべての例を取得できます。

**Topics**
+ [Amazon Kinesis Data Streams​ へのサブスクライブ](examples-kinesis-stream.md)

# Amazon Kinesis Data Streams​ へのサブスクライブ
<a name="examples-kinesis-stream"></a>

以下の例では、Amazon Kinesis メソッドを使用し、`subscribeToShard` Data Streams からデータを取得して処理する方法について説明します。Kinesis Data Streams では、強化されたファンアウト機能と低レイテンシーの HTTP/2 データ取得 API が導入されました。これにより、デベロッパーは複数の低レイテンシーで高パフォーマンスのアプリケーションを、同じ Kinesis Data Streams でより簡単に実行できます。

## セットアップ
<a name="set-up"></a>

まず、非同期 Kinesisクライアントと [SubscribeToShardRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/kinesis/model/SubscribeToShardRequest.html) オブジェクトを作成します。これらのオブジェクトは、Kinesis イベントにサブスクライブする次のそれぞれの例で使用されます。

 **インポート** 

```
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicInteger;
import org.reactivestreams.Subscriber;
import org.reactivestreams.Subscription;
import software.amazon.awssdk.core.async.SdkPublisher;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.kinesis.KinesisAsyncClient;
import software.amazon.awssdk.services.kinesis.model.ShardIteratorType;
import software.amazon.awssdk.services.kinesis.model.SubscribeToShardEvent;
import software.amazon.awssdk.services.kinesis.model.SubscribeToShardEventStream;
import software.amazon.awssdk.services.kinesis.model.SubscribeToShardRequest;
import software.amazon.awssdk.services.kinesis.model.SubscribeToShardResponse;
import software.amazon.awssdk.services.kinesis.model.SubscribeToShardResponseHandler;
```

 **コード** 

```
        Region region = Region.US_EAST_1;
        KinesisAsyncClient client = KinesisAsyncClient.builder()
        .region(region)
        .build();

        SubscribeToShardRequest request = SubscribeToShardRequest.builder()
                .consumerARN(CONSUMER_ARN)
                .shardId("arn:aws:kinesis:us-east-1:111122223333:stream/StockTradeStream")
                .startingPosition(s -> s.type(ShardIteratorType.LATEST)).build();
```

## ビルダーインターフェイスを使用する
<a name="use-the-builder-interface"></a>

`builder` メソッドを使用して、[SubscribeToShardResponseHandler](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/kinesis/model/SubscribeToShardResponseHandler.html) の作成をシンプルにできます。

ビルダーを使用して、完全なインターフェイスを実装する代わりにメソッド呼び出しで各ライフサイクルのコールバックを設定できます。

 **コード** 

```
    private static CompletableFuture<Void> responseHandlerBuilder(KinesisAsyncClient client, SubscribeToShardRequest request) {
        SubscribeToShardResponseHandler responseHandler = SubscribeToShardResponseHandler
                .builder()
                .onError(t -> System.err.println("Error during stream - " + t.getMessage()))
                .onComplete(() -> System.out.println("All records stream successfully"))
                // Must supply some type of subscriber
                .subscriber(e -> System.out.println("Received event - " + e))
                .build();
        return client.subscribeToShard(request, responseHandler);
    }
```

公開者をさらに制御するには、`publisherTransformer` メソッドを使用して公開者をカスタマイズできます。

 **Code** 

```
    private static CompletableFuture<Void> responseHandlerBuilderPublisherTransformer(KinesisAsyncClient client, SubscribeToShardRequest request) {
        SubscribeToShardResponseHandler responseHandler = SubscribeToShardResponseHandler
                .builder()
                .onError(t -> System.err.println("Error during stream - " + t.getMessage()))
                .publisherTransformer(p -> p.filter(e -> e instanceof SubscribeToShardEvent).limit(100))
                .subscriber(e -> System.out.println("Received event - " + e))
                .build();
        return client.subscribeToShard(request, responseHandler);
    }
```

[GitHub](https://github.com/awsdocs/aws-doc-sdk-examples/blob/ac748d8ef99cd17e297cb74fe13aa671e2679088/javav2/example_code/kinesis/src/main/java/com/example/kinesis/KinesisStreamEx.java) で完全な例をご覧ください。

## カスタムレスポンスハンドラを使用する
<a name="use-a-custom-response-handler"></a>

サブスクライバーとパブリッシャーの完全なコントロールのためには、`SubscribeToShardResponseHandler` インターフェイスを実装します。

この例では、`onEventStream` メソッドを実装します。これにより、公開者へのフルアクセスが許可されます。このデモでは、受信者による表示のために公開者をイベントレコードに変換する方法を示します。

 **Code** 

```
    private static CompletableFuture<Void> responseHandlerBuilderClassic(KinesisAsyncClient client, SubscribeToShardRequest request) {
        SubscribeToShardResponseHandler responseHandler = new SubscribeToShardResponseHandler() {

            @Override
            public void responseReceived(SubscribeToShardResponse response) {
                System.out.println("Receieved initial response");
            }

            @Override
            public void onEventStream(SdkPublisher<SubscribeToShardEventStream> publisher) {
                publisher
                        // Filter to only SubscribeToShardEvents
                        .filter(SubscribeToShardEvent.class)
                        // Flat map into a publisher of just records
                        .flatMapIterable(SubscribeToShardEvent::records)
                        // Limit to 1000 total records
                        .limit(1000)
                        // Batch records into lists of 25
                        .buffer(25)
                        // Print out each record batch
                        .subscribe(batch -> System.out.println("Record Batch - " + batch));
            }

            @Override
            public void complete() {
                System.out.println("All records stream successfully");
            }

            @Override
            public void exceptionOccurred(Throwable throwable) {
                System.err.println("Error during stream - " + throwable.getMessage());
            }
        };
        return client.subscribeToShard(request, responseHandler);
    }
```

[GitHub](https://github.com/awsdocs/aws-doc-sdk-examples/blob/ac748d8ef99cd17e297cb74fe13aa671e2679088/javav2/example_code/kinesis/src/main/java/com/example/kinesis/KinesisStreamEx.java) で完全な例をご覧ください。

## 訪問者インターフェイスを使用する
<a name="use-the-visitor-interface"></a>

[Visitor](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/kinesis/model/SubscribeToShardResponseHandler.Visitor.html) オブジェクトを使用して、監視する特定のイベントにサブスクライブできます。

 **Code** 

```
    private static CompletableFuture<Void> responseHandlerBuilderVisitorBuilder(KinesisAsyncClient client, SubscribeToShardRequest request) {
        SubscribeToShardResponseHandler.Visitor visitor = SubscribeToShardResponseHandler.Visitor
                .builder()
                .onSubscribeToShardEvent(e -> System.out.println("Received subscribe to shard event " + e))
                .build();
        SubscribeToShardResponseHandler responseHandler = SubscribeToShardResponseHandler
                .builder()
                .onError(t -> System.err.println("Error during stream - " + t.getMessage()))
                .subscriber(visitor)
                .build();
        return client.subscribeToShard(request, responseHandler);
    }
```

[GitHub](https://github.com/awsdocs/aws-doc-sdk-examples/blob/ac748d8ef99cd17e297cb74fe13aa671e2679088/javav2/example_code/kinesis/src/main/java/com/example/kinesis/KinesisStreamEx.java) で完全な例をご覧ください。

## カスタム受信者を使用する
<a name="use-a-custom-subscriber"></a>

独自のカスタム受信者を実装して、ストリームにサブスクライブすることもできます。

このコードスニペットでは、サブスクライバーの例を示しています。

 **コード** 

```
    private static class MySubscriber implements Subscriber<SubscribeToShardEventStream> {

        private Subscription subscription;
        private AtomicInteger eventCount = new AtomicInteger(0);

        @Override
        public void onSubscribe(Subscription subscription) {
            this.subscription = subscription;
            this.subscription.request(1);
        }

        @Override
        public void onNext(SubscribeToShardEventStream shardSubscriptionEventStream) {
            System.out.println("Received event " + shardSubscriptionEventStream);
            if (eventCount.incrementAndGet() >= 100) {
                // You can cancel the subscription at any time if you wish to stop receiving events.
                subscription.cancel();
            }
            subscription.request(1);
        }

        @Override
        public void onError(Throwable throwable) {
            System.err.println("Error occurred while stream - " + throwable.getMessage());
        }

        @Override
        public void onComplete() {
            System.out.println("Finished streaming all events");
        }
    }
```

次のコードスニペットに示すように、カスタムサブスクライバーを `subscribe` メソッドに渡すことができます。

 **Code** 

```
    private static CompletableFuture<Void> responseHandlerBuilderSubscriber(KinesisAsyncClient client, SubscribeToShardRequest request) {
        SubscribeToShardResponseHandler responseHandler = SubscribeToShardResponseHandler
                .builder()
                .onError(t -> System.err.println("Error during stream - " + t.getMessage()))
                .subscriber(MySubscriber::new)
                .build();
        return client.subscribeToShard(request, responseHandler);
    }
```

[GitHub](https://github.com/awsdocs/aws-doc-sdk-examples/blob/ac748d8ef99cd17e297cb74fe13aa671e2679088/javav2/example_code/kinesis/src/main/java/com/example/kinesis/KinesisStreamEx.java) で完全な例をご覧ください。

## Kinesis データストリームにデータレコードを書き込む
<a name="write-data-records-into-a-kinesis-data-stream"></a>

[KinesisClient](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/kinesis/KinesisClient.html) オブジェクトで `putRecords` メソッドを使用して、データレコードを Kinesis データストリームに書き込むことができます。このメソッドを正常に呼び出すには、[PutRecordsRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/kinesis/model/PutRecordsRequest.html) オブジェクトを作成します。データストリームの名前を `streamName` メソッドに渡します。また、`putRecords` メソッドを使用してデータを渡す必要があります (次のコード例に示します)。

 **インポート**。

```
import software.amazon.awssdk.core.SdkBytes;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.kinesis.KinesisClient;
import software.amazon.awssdk.services.kinesis.model.PutRecordRequest;
import software.amazon.awssdk.services.kinesis.model.KinesisException;
import software.amazon.awssdk.services.kinesis.model.DescribeStreamRequest;
import software.amazon.awssdk.services.kinesis.model.DescribeStreamResponse;
```

次の Java コード例では、**StockTrade** オブジェクトが Kinesis データストリームに書き込むデータとして使用されています。この例を実行する前に、データストリームを作成したことを確認します。

 **Code** 

```
import software.amazon.awssdk.core.SdkBytes;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.kinesis.KinesisClient;
import software.amazon.awssdk.services.kinesis.model.PutRecordRequest;
import software.amazon.awssdk.services.kinesis.model.KinesisException;
import software.amazon.awssdk.services.kinesis.model.DescribeStreamRequest;
import software.amazon.awssdk.services.kinesis.model.DescribeStreamResponse;

/**
 * Before running this Java V2 code example, set up your development
 * environment, including your credentials.
 *
 * For more information, see the following documentation topic:
 *
 * https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/get-started.html
 */
public class StockTradesWriter {
    public static void main(String[] args) {
        final String usage = """

                Usage:
                    <streamName>

                Where:
                    streamName - The Amazon Kinesis data stream to which records are written (for example, StockTradeStream)
                """;

        if (args.length != 1) {
            System.out.println(usage);
            System.exit(1);
        }

        String streamName = args[0];
        Region region = Region.US_EAST_1;
        KinesisClient kinesisClient = KinesisClient.builder()
                .region(region)
                .build();

        // Ensure that the Kinesis Stream is valid.
        validateStream(kinesisClient, streamName);
        setStockData(kinesisClient, streamName);
        kinesisClient.close();
    }

    public static void setStockData(KinesisClient kinesisClient, String streamName) {
        try {
            // Repeatedly send stock trades with a 100 milliseconds wait in between.
            StockTradeGenerator stockTradeGenerator = new StockTradeGenerator();

            // Put in 50 Records for this example.
            int index = 50;
            for (int x = 0; x < index; x++) {
                StockTrade trade = stockTradeGenerator.getRandomTrade();
                sendStockTrade(trade, kinesisClient, streamName);
                Thread.sleep(100);
            }

        } catch (KinesisException | InterruptedException e) {
            System.err.println(e.getMessage());
            System.exit(1);
        }
        System.out.println("Done");
    }

    private static void sendStockTrade(StockTrade trade, KinesisClient kinesisClient,
            String streamName) {
        byte[] bytes = trade.toJsonAsBytes();

        // The bytes could be null if there is an issue with the JSON serialization by
        // the Jackson JSON library.
        if (bytes == null) {
            System.out.println("Could not get JSON bytes for stock trade");
            return;
        }

        System.out.println("Putting trade: " + trade);
        PutRecordRequest request = PutRecordRequest.builder()
                .partitionKey(trade.getTickerSymbol()) // We use the ticker symbol as the partition key, explained in
                                                       // the Supplemental Information section below.
                .streamName(streamName)
                .data(SdkBytes.fromByteArray(bytes))
                .build();

        try {
            kinesisClient.putRecord(request);
        } catch (KinesisException e) {
            System.err.println(e.getMessage());
        }
    }

    private static void validateStream(KinesisClient kinesisClient, String streamName) {
        try {
            DescribeStreamRequest describeStreamRequest = DescribeStreamRequest.builder()
                    .streamName(streamName)
                    .build();

            DescribeStreamResponse describeStreamResponse = kinesisClient.describeStream(describeStreamRequest);

            if (!describeStreamResponse.streamDescription().streamStatus().toString().equals("ACTIVE")) {
                System.err.println("Stream " + streamName + " is not active. Please wait a few moments and try again.");
                System.exit(1);
            }

        } catch (KinesisException e) {
            System.err.println("Error found while describing the stream " + streamName);
            System.err.println(e);
            System.exit(1);
        }
    }
}
```

[GitHub](https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/javav2/example_code/kinesis/src/main/java/com/example/kinesis/StockTradesWriter.java) で完全な例をご覧ください。

## サードパーティーライブラリを使用する
<a name="use-a-third-party-library"></a>

カスタムの受信者を実装せずに、その他のサードパーティーのライブラリを使用することができます。この例では、RxJava の実装を例に挙げていますが、リアクティブなストリームのインターフェイスを実装するライブラリを使用することもできます。上記ライブラリの詳細については、「[Github の RxJava wiki ページ](https://github.com/ReactiveX/RxJava/wiki)」を参照してください。

このライブラリを使用するには、依存関係として追加します。使用する POM スニペットの例を示します (Maven を使用している場合)。

 **POM エントリ** 

```
<dependency>
 <groupId>io.reactivex.rxjava2</groupId>
 <artifactId>rxjava</artifactId>
 <version>2.2.21</version>
</dependency>
```

 **インポート**。

```
import java.net.URI;
import java.util.concurrent.CompletableFuture;

import io.reactivex.Flowable;
import software.amazon.awssdk.auth.credentials.ProfileCredentialsProvider;
import software.amazon.awssdk.core.async.SdkPublisher;
import software.amazon.awssdk.http.Protocol;
import software.amazon.awssdk.http.SdkHttpConfigurationOption;
import software.amazon.awssdk.http.nio.netty.NettyNioAsyncHttpClient;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.kinesis.KinesisAsyncClient;
import software.amazon.awssdk.services.kinesis.model.ShardIteratorType;
import software.amazon.awssdk.services.kinesis.model.StartingPosition;
import software.amazon.awssdk.services.kinesis.model.SubscribeToShardEvent;
import software.amazon.awssdk.services.kinesis.model.SubscribeToShardRequest;
import software.amazon.awssdk.services.kinesis.model.SubscribeToShardResponseHandler;
import software.amazon.awssdk.utils.AttributeMap;
```

この例では、`onEventStream` ライフサイクルメソッドの RxJava を使用します。これにより、発行者へのフルアクセスが付与され、これを使用して Rx Flowable を作成できます。

 **コード** 

```
        SubscribeToShardResponseHandler responseHandler = SubscribeToShardResponseHandler
            .builder()
            .onError(t -> System.err.println("Error during stream - " + t.getMessage()))
            .onEventStream(p -> Flowable.fromPublisher(p)
                                        .ofType(SubscribeToShardEvent.class)
                                        .flatMapIterable(SubscribeToShardEvent::records)
                                        .limit(1000)
                                        .buffer(25)
                                        .subscribe(e -> System.out.println("Record batch = " + e)))
            .build();
```

`publisherTransformer` 発行者を指定して、`Flowable` メソッドを使用することもできます。次の例に示すように、`Flowable` 発行者を *SdkPublisher* に適用する必要があります。

 **Code** 

```
        SubscribeToShardResponseHandler responseHandler = SubscribeToShardResponseHandler
            .builder()
            .onError(t -> System.err.println("Error during stream - " + t.getMessage()))
            .publisherTransformer(p -> SdkPublisher.adapt(Flowable.fromPublisher(p).limit(100)))
            .build();
```

[GitHub](https://github.com/awsdocs/aws-doc-sdk-examples/blob/main/javav2/example_code/kinesis/src/main/java/com/example/kinesis/KinesisStreamRxJavaEx.java) で完全な例をご覧ください。

## 詳細情報
<a name="more-information"></a>
+  Amazon Kinesis API リファレンスの [SubscribeToShardEvent](https://docs.aws.amazon.com/kinesis/latest/APIReference/API_SubscribeToShardEvent.html)
+  Amazon Kinesis API リファレンスの [SubscribeToShard](https://docs.aws.amazon.com/kinesis/latest/APIReference/API_SubscribeToShard.html)

# AWS Lambda 関数の呼び出し、一覧表示、削除
<a name="examples-lambda"></a>

このセクションでは、 AWS SDK for Java 2.x を使用した Lambda サービスクライアントでのプログラミングの例を示します。

**Topics**
+ [Lambda 関数を呼び出します。](#invoke-function)
+ [Lambda 関数を一覧表示する](#list-function)
+ [Lambda 関数を削除する](#delete-function)

## Lambda 関数を呼び出します。
<a name="invoke-function"></a>

[https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/lambda/LambdaClient.html](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/lambda/LambdaClient.html) オブジェクトを作成し、その `invoke`メソッドを呼び出すことで、 Lambda 関数を呼び出すことができます。[https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/lambda/model/InvokeRequest.html](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/lambda/model/InvokeRequest.html) オブジェクトを作成して、関数名や Lambda 関数に渡すペイロードなどの追加情報を指定します。関数名は、*arn:aws:lambda:us-east-1:123456789012:function:HelloFunction* と表示されます。 AWS マネジメントコンソールで関数を確認することで、値を取得できます。

ペイロードデータを関数に渡すには、情報を含む [https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/core/SdkBytes.html](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/core/SdkBytes.html) オブジェクトを作成します。たとえば、次のコード例では、 Lambda 関数に渡される JSON データに注意してください。

 **インポート** 

```
import software.amazon.awssdk.services.lambda.LambdaClient;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.lambda.model.InvokeRequest;
import software.amazon.awssdk.core.SdkBytes;
import software.amazon.awssdk.services.lambda.model.InvokeResponse;
import software.amazon.awssdk.services.lambda.model.LambdaException;
```

 **コード** 

次のコード例は、 Lambda 関数を呼び出す方法を示しています。

```
    public static void invokeFunction(LambdaClient awsLambda, String functionName) {

         InvokeResponse res = null ;
        try {
            //Need a SdkBytes instance for the payload
            String json = "{\"Hello \":\"Paris\"}";
            SdkBytes payload = SdkBytes.fromUtf8String(json) ;

            //Setup an InvokeRequest
            InvokeRequest request = InvokeRequest.builder()
                    .functionName(functionName)
                    .payload(payload)
                    .build();

            res = awsLambda.invoke(request);
            String value = res.payload().asUtf8String() ;
            System.out.println(value);

        } catch(LambdaException e) {
            System.err.println(e.getMessage());
            System.exit(1);
        }
    }
```

[GitHub](https://github.com/awsdocs/aws-doc-sdk-examples/blob/f807d60010caf3d14fe4cd0801b842fb8e9511ca/javav2/example_code/lambda/src/main/java/com/example/lambda/LambdaInvoke.java) で完全な例をご覧ください。

## Lambda 関数を一覧表示する
<a name="list-function"></a>

`[Lambda Client](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/lambda/LambdaClient.html)` オブジェクトを構築し、その `listFunctions` メソッドを呼び出します。このメソッドは [https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/lambda/model/ListFunctionsResponse.html](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/lambda/model/ListFunctionsResponse.html) オブジェクトを返します。このオブジェクトの `functions` メソッドを呼び出して、[https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/lambda/model/FunctionConfiguration.html](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/lambda/model/FunctionConfiguration.html) オブジェクトのリストを取得できます。リストを反復処理して、関数に関する情報を取得できます。たとえば、次の Java コード例は、各関数名を取得する方法を示しています。

 **インポート** 

```
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.lambda.LambdaClient;
import software.amazon.awssdk.services.lambda.model.LambdaException;
import software.amazon.awssdk.services.lambda.model.ListFunctionsResponse;
import software.amazon.awssdk.services.lambda.model.FunctionConfiguration;
import java.util.List;
```

 **コード** 

次の Java コード例は、 関数名のリストを取得する方法を示しています。

```
    public static void listFunctions(LambdaClient awsLambda) {

        try {
            ListFunctionsResponse functionResult = awsLambda.listFunctions();
            List<FunctionConfiguration> list = functionResult.functions();

            for (FunctionConfiguration config: list) {
                System.out.println("The function name is "+config.functionName());
            }

        } catch(LambdaException e) {
            System.err.println(e.getMessage());
            System.exit(1);
        }
    }
```

[GitHub](https://github.com/awsdocs/aws-doc-sdk-examples/blob/f807d60010caf3d14fe4cd0801b842fb8e9511ca/javav2/example_code/lambda/src/main/java/com/example/lambda/ListLambdaFunctions.java) で完全な例をご覧ください。

## Lambda 関数を削除する
<a name="delete-function"></a>

[https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/lambda/LambdaClient.html](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/lambda/LambdaClient.html) オブジェクトを構築し、その `deleteFunction` メソッドを呼び出します。[https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/lambda/model/DeleteFunctionRequest.html](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/lambda/model/DeleteFunctionRequest.html) オブジェクトを作成し、 `deleteFunction` メソッドに渡します。このオブジェクトには、削除する関数の名前などの情報が含まれています。関数名は、*arn:aws:lambda:us-east-1:123456789012:function:HelloFunction* と表示されます。 AWS マネジメントコンソールで関数を確認することで、値を取得できます。

 **インポート** 

```
import software.amazon.awssdk.services.lambda.LambdaClient;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.lambda.model.DeleteFunctionRequest;
import software.amazon.awssdk.services.lambda.model.LambdaException;
```

 **コード** 

次の Java コードは、 Lambda 関数を削除する方法を示しています。

```
    public static void deleteLambdaFunction(LambdaClient awsLambda, String functionName ) {
        try {
            DeleteFunctionRequest request = DeleteFunctionRequest.builder()
                    .functionName(functionName)
                    .build();

            awsLambda.deleteFunction(request);
            System.out.println("The "+functionName +" function was deleted");

        } catch(LambdaException e) {
            System.err.println(e.getMessage());
            System.exit(1);
        }
    }
```

[GitHub](https://github.com/awsdocs/aws-doc-sdk-examples/blob/f807d60010caf3d14fe4cd0801b842fb8e9511ca/javav2/example_code/lambda/src/main/java/com/example/lambda/DeleteFunction.java) で完全な例をご覧ください。

# Amazon S3 で使用する
<a name="examples-s3"></a>

このセクションでは、 AWS SDK for Java 2.xを使用して Amazon S3 を操作するための背景情報を提供します。このセクションは、このガイドの「*コード例*」セクションで説明されている [Amazon S3 Java v2 の例](java_s3_code_examples.md)の情報を補完します

## の S3 クライアント AWS SDK for Java 2.x
<a name="s3-clients"></a>

 AWS SDK for Java 2.x には、さまざまなタイプの S3 クライアントが用意されています。次の表では違いを比較しており、ユースケースに最適なクライアントを決定するのに役立ちます。


**Amazon S3 クライアントのさまざまなタイプ**  

| S3 クライアント | 簡単な説明 | どのようなときに使うか | 制限/欠点 | 
| --- | --- | --- | --- | 
|  **AWS CRT ベースの S3 クライアント** インターフェイス: [S3AsyncClient](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/s3/S3AsyncClient.html) ビルダー: [S3CrtAsyncClientBuilder](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/s3/S3AsyncClient.html)  |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ja_jp/sdk-for-java/latest/developer-guide/examples-s3.html) 「[パフォーマンスの高い S3 クライアントを使用する: AWS CRT ベースの S3 クライアント](crt-based-s3-client.md)」を参照してください。  |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ja_jp/sdk-for-java/latest/developer-guide/examples-s3.html)  |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ja_jp/sdk-for-java/latest/developer-guide/examples-s3.html)  | 
|  **マルチパートが*有効になっている* Java ベースの S3 非同期クライアント** インターフェイス: [S3AsyncClient](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/s3/S3AsyncClient.html) ビルダー: [S3AsyncClientBuilder](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/s3/S3AsyncClientBuilder.html)  |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ja_jp/sdk-for-java/latest/developer-guide/examples-s3.html) 「[並列転送を使用するように Java ベースの S3 非同期クライアントを設定する](s3-async-client-multipart.md)」を参照してください。  |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ja_jp/sdk-for-java/latest/developer-guide/examples-s3.html)  | CRT AWS ベースの S3 クライアントよりもパフォーマンスが低くなります。 | 
|  **マルチパートが*有効になっていない* Java ベースの S3 非同期クライアント** インターフェイス: [S3AsyncClient](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/s3/S3AsyncClient.html) ビルダー: [S3AsyncClientBuilder](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/s3/S3AsyncClientBuilder.html) |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ja_jp/sdk-for-java/latest/developer-guide/examples-s3.html)  |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ja_jp/sdk-for-java/latest/developer-guide/examples-s3.html)  |  パフォーマンスの最適化なし。  | 
|  **Java ベースの S3 同期クライアント** インターフェイス: [S3Client](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/s3/S3Client.html) ビルダー: [S3ClientBuilder](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/s3/S3ClientBuilder.html) |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ja_jp/sdk-for-java/latest/developer-guide/examples-s3.html)  |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ja_jp/sdk-for-java/latest/developer-guide/examples-s3.html)  |  パフォーマンスの最適化なし。  | 

**注記**  
バージョン 2.18.x 以降では、 はエンドポイントオーバーライドを含めるときに[仮想ホスト形式のアドレス指定](https://docs.aws.amazon.com/AmazonS3/latest/userguide/VirtualHosting.html#virtual-hosted-style-access) AWS SDK for Java 2.x を使用します。これは、バケット名が有効な DNS ラベルである限り適用されます。  
クライアントビルダーの `true` で [https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/s3/S3BaseClientBuilder.html#forcePathStyle(java.lang.Boolean](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/s3/S3BaseClientBuilder.html#forcePathStyle(java.lang.Boolean) メソッドを呼び出して、クライアントにバケットにパス形式のアドレス指定を使用するように強制します。  
以下の例は、エンドポイントオーバーライドを設定し、パス形式のアドレス指定を使用するサービスクライアントを示しています。  

```
S3Client client = S3Client.builder()
                          .region(Region.US_WEST_2)
                          .endpointOverride(URI.create("https://s3.us-west-2.amazonaws.com"))
                          .forcePathStyle(true)
                          .build();
```

**Topics**
+ [SDK の S3 クライアント](#s3-clients)
+ [S3 にストリームをアップロードする](best-practices-s3-uploads.md)
+ [署名付き URL](examples-s3-presign.md)
+ [クロスリージョンアクセス](s3-cross-region.md)
+ [チェックサムによるデータ整合性保護](s3-checksums.md)
+ [パフォーマンスの高い S3 クライアントを使用する](crt-based-s3-client.md)
+ [並列転送のサポートを設定する](s3-async-client-multipart.md)
+ [ファイルとディレクトリを転送する](transfer-manager.md)
+ [S3 イベント通知](examples-s3-event-notifications.md)

# を使用した Amazon S3 へのストリームのアップロード AWS SDK for Java 2.x
<a name="best-practices-s3-uploads"></a>

ストリームを使用して、[https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/s3/S3Client.html#putObject(software.amazon.awssdk.services.s3.model.PutObjectRequest,software.amazon.awssdk.core.sync.RequestBody)](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/s3/S3Client.html#putObject(software.amazon.awssdk.services.s3.model.PutObjectRequest,software.amazon.awssdk.core.sync.RequestBody)) または [https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/s3/S3Client.html#uploadPart(software.amazon.awssdk.services.s3.model.UploadPartRequest,software.amazon.awssdk.core.sync.RequestBody)](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/s3/S3Client.html#uploadPart(software.amazon.awssdk.services.s3.model.UploadPartRequest,software.amazon.awssdk.core.sync.RequestBody)) で S3 にコンテンツをアップロードする場合、同期 API の`RequestBody` ファクトリクラスを使用してストリームを提供します。非同期 API の場合、`AsyncRequestBody` は同等のファクトリクラスです。

## ストリームをアップロードするメソッド
<a name="s3-stream-upload-methods"></a>

同期 API では、次の `RequestBody` のファクトリメソッドを使用してストリームを指定できます。
+ `[fromInputStream](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/core/sync/RequestBody.html#fromInputStream(java.io.InputStream,long))(InputStream inputStream, long contentLength)`

  `[fromContentProvider](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/core/sync/RequestBody.html#fromContentProvider(software.amazon.awssdk.http.ContentStreamProvider,long,java.lang.String))(ContentStreamProvider provider, long contentLength, String mimeType)`
  + `ContentStreamProvider` には `fromInputStream(InputStream inputStream)` ファクトリメソッドがあります
+ `[fromContentProvider](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/core/sync/RequestBody.html#fromContentProvider(software.amazon.awssdk.http.ContentStreamProvider,java.lang.String))(ContentStreamProvider provider, String mimeType)`

非同期 API では、次のファクトリメソッド `AsyncRequestBody` を使用できます。
+ `[fromInputStream](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/core/async/AsyncRequestBody.html#fromInputStream(java.io.InputStream,java.lang.Long,java.util.concurrent.ExecutorService))(InputStream inputStream, Long contentLength, ExecutorService executor)` 
+ `[fromInputStream](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/core/async/AsyncRequestBody.html#fromInputStream(software.amazon.awssdk.core.async.AsyncRequestBodyFromInputStreamConfiguration))(AsyncRequestBodyFromInputStreamConfiguration configuration)`
  + AsyncRequestBodyFromInputStreamConfiguration.Builder を使用してストリームを提供します。
+ `[fromInputStream](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/core/async/AsyncRequestBody.html#fromInputStream(java.util.function.Consumer))(Consumer<AsyncRequestBodyFromInputStreamConfiguration.Builder> configuration)`
+ `[forBlockingInputStream](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/core/async/AsyncRequestBody.html#forBlockingInputStream(java.lang.Long))(Long contentLength)`
  + 結果の `[BlockingInputStreamAsyncRequestBody](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/core/async/BlockingInputStreamAsyncRequestBody.html)` には、ストリームの提供に使用できるメソッド `writeInputStream(InputStream inputStream)` が含まれています。

## アップロードの実行
<a name="s3-upload-stream-perform"></a>

### ストリームの長さがわかっている場合
<a name="s3-stream-upload-supply-content-length"></a>

前に示したメソッドの署名からわかるように、ほとんどのメソッドはコンテンツの長さのパラメータを受け入れます。

コンテンツの長さがバイト単位でわかっている場合は、正確な値を指定します。

```
// Always provide the exact content length when it's available.
long contentLength = 1024; // Exact size in bytes.
s3Client.putObject(req -> req
    .bucket("amzn-s3-demo-bucket")
    .key("my-key"),
RequestBody.fromInputStream(inputStream, contentLength));
```

**警告**  
 入力ストリームからアップロードするときに、指定したコンテンツの長さが実際のバイト数と一致しない場合、次のようなことが起こる可能性があります。  
指定した長さが小さすぎる場合にオブジェクトが切り捨てられる
指定した長さが大きすぎる場合、アップロードが失敗するか接続がハングアップする

### ストリームの長さがわからない場合
<a name="s3-stream-upload-unknown-length"></a>

#### 同期 API を使用する
<a name="s3-upload-unknown-sync-client"></a>

`fromContentProvider(ContentStreamProvider provider, String mimeType)` を使用します。

```
public PutObjectResponse syncClient_stream_unknown_size(String bucketName, String key, InputStream inputStream) {

    S3Client s3Client = S3Client.create();

    RequestBody body = RequestBody.fromContentProvider(ContentStreamProvider.fromInputStream(inputStream), "text/plain");
    PutObjectResponse putObjectResponse = s3Client.putObject(b -> b.bucket(BUCKET_NAME).key(KEY_NAME), body);
    return putObjectResponse;
}
```

SDK はストリーム全体をメモリにバッファリングしてコンテンツの長さを計算するため、大きなストリームでメモリの問題が発生する可能性があります。同期クライアントで大きなストリームをアップロードする必要がある場合は、マルチパート API の使用を検討してください。

##### 同期クライアント API とマルチパート API を使用してストリームをアップロードする
<a name="sync-multipart-upload-stream"></a>

```
public static void uploadStreamToS3(String bucketName, String key, InputStream inputStream) {
    // Create S3 client
    S3Client s3Client = S3Client.create();
    try {
        // Step 1: Initiate the multipart upload
        CreateMultipartUploadRequest createMultipartUploadRequest = CreateMultipartUploadRequest.builder()
                .bucket(bucketName)
                .key(key)
                .build();

        CreateMultipartUploadResponse createResponse = s3Client.createMultipartUpload(createMultipartUploadRequest);
        String uploadId = createResponse.uploadId();
        System.out.println("Started multipart upload with ID: " + uploadId);

        // Step 2: Upload parts
        List<CompletedPart> completedParts = new ArrayList<>();
        int partNumber = 1;
        byte[] buffer = new byte[PART_SIZE];
        int bytesRead;

        try {
            while ((bytesRead = readFullyOrToEnd(inputStream, buffer)) > 0) {
                // Create request to upload a part
                UploadPartRequest uploadPartRequest = UploadPartRequest.builder()
                        .bucket(bucketName)
                        .key(key)
                        .uploadId(uploadId)
                        .partNumber(partNumber)
                        .build();

                // If we didn't read a full buffer, create a properly sized byte array
                RequestBody requestBody;
                if (bytesRead < PART_SIZE) {
                    byte[] lastPartBuffer = new byte[bytesRead];
                    System.arraycopy(buffer, 0, lastPartBuffer, 0, bytesRead);
                    requestBody = RequestBody.fromBytes(lastPartBuffer);
                } else {
                    requestBody = RequestBody.fromBytes(buffer);
                }

                // Upload the part and save the response's ETag
                UploadPartResponse uploadPartResponse = s3Client.uploadPart(uploadPartRequest, requestBody);
                CompletedPart part = CompletedPart.builder()
                        .partNumber(partNumber)
                        .eTag(uploadPartResponse.eTag())
                        .build();
                completedParts.add(part);

                System.out.println("Uploaded part " + partNumber + " with size " + bytesRead + " bytes");
                partNumber++;
            }

            // Step 3: Complete the multipart upload
            CompletedMultipartUpload completedMultipartUpload = CompletedMultipartUpload.builder()
                    .parts(completedParts)
                    .build();

            CompleteMultipartUploadRequest completeRequest = CompleteMultipartUploadRequest.builder()
                    .bucket(bucketName)
                    .key(key)
                    .uploadId(uploadId)
                    .multipartUpload(completedMultipartUpload)
                    .build();

            CompleteMultipartUploadResponse completeResponse = s3Client.completeMultipartUpload(completeRequest);
            System.out.println("Multipart upload completed. Object URL: " + completeResponse.location());

        } catch (Exception e) {
            // If an error occurs, abort the multipart upload
            System.err.println("Error during multipart upload: " + e.getMessage());
            AbortMultipartUploadRequest abortRequest = AbortMultipartUploadRequest.builder()
                    .bucket(bucketName)
                    .key(key)
                    .uploadId(uploadId)
                    .build();
            s3Client.abortMultipartUpload(abortRequest);
            System.err.println("Multipart upload aborted");
        } finally {
            try {
                inputStream.close();
            } catch (IOException e) {
                System.err.println("Error closing input stream: " + e.getMessage());
            }
        }
    } finally {
        s3Client.close();
    }
}

/**
 * Reads from the input stream into the buffer, attempting to fill the buffer completely
 * or until the end of the stream is reached.
 *
 * @param inputStream the input stream to read from
 * @param buffer      the buffer to fill
 * @return the number of bytes read, or -1 if the end of the stream is reached before any bytes are read
 * @throws IOException if an I/O error occurs
 */
private static int readFullyOrToEnd(InputStream inputStream, byte[] buffer) throws IOException {
    int totalBytesRead = 0;
    int bytesRead;

    while (totalBytesRead < buffer.length) {
        bytesRead = inputStream.read(buffer, totalBytesRead, buffer.length - totalBytesRead);
        if (bytesRead == -1) {
            break; // End of stream
        }
        totalBytesRead += bytesRead;
    }

    return totalBytesRead > 0 ? totalBytesRead : -1;
}
```

**注記**  
ほとんどのユースケースでは、サイズが不明なストリームに非同期クライアント API を使用することをお勧めします。このアプローチにより並列転送が可能になり、プログラミングインターフェイスがよりシンプルになります。これは、ストリームが大きい場合、SDK はストリームセグメンテーションをマルチパートチャンクに処理するためです。  
マルチパートが有効になっている標準の S3 非同期クライアントと AWS CRT ベースの S3 クライアントの両方がこのアプローチを実装しています。このアプローチの例を次のセクションに示します。

#### 非同期 API を使用する
<a name="s3-stream-upload-unknown-async-client"></a>

`fromInputStream(InputStream inputStream, Long contentLength, ExecutorService executor)` への `contentLength` 引数に `null` を指定できます。

**Example CRT AWS ベースの非同期クライアントの使用:**  

```
public PutObjectResponse crtClient_stream_unknown_size(String bucketName, String key, InputStream inputStream) {

    S3AsyncClient s3AsyncClient = S3AsyncClient.crtCreate();
    ExecutorService executor = Executors.newSingleThreadExecutor();
    AsyncRequestBody body = AsyncRequestBody.fromInputStream(inputStream, null, executor);  // 'null' indicates that the
                                                                                            // content length is unknown.
    CompletableFuture<PutObjectResponse> responseFuture =
            s3AsyncClient.putObject(r -> r.bucket(bucketName).key(key), body)
                    .exceptionally(e -> {
                        if (e != null){
                            logger.error(e.getMessage(), e);
                        }
                        return null;
                    });

    PutObjectResponse response = responseFuture.join(); // Wait for the response.
    executor.shutdown();
    return response;
}
```

**Example マルチパートが有効になっている標準の非同期クライアントを使用します。**  

```
public PutObjectResponse asyncClient_multipart_stream_unknown_size(String bucketName, String key, InputStream inputStream) {

    S3AsyncClient s3AsyncClient = S3AsyncClient.builder().multipartEnabled(true).build();
    ExecutorService executor = Executors.newSingleThreadExecutor();
    AsyncRequestBody body = AsyncRequestBody.fromInputStream(inputStream, null, executor); // 'null' indicates that the
                                                                                           // content length is unknown.
    CompletableFuture<PutObjectResponse> responseFuture =
            s3AsyncClient.putObject(r -> r.bucket(bucketName).key(key), body)
                    .exceptionally(e -> {
                        if (e != null) {
                            logger.error(e.getMessage(), e);
                        }
                        return null;
                    });

    PutObjectResponse response = responseFuture.join(); // Wait for the response.
    executor.shutdown();
    return response;
}
```

# 署名 Amazon S3 付き URLsの使用
<a name="examples-s3-presign"></a>

署名付き URLs は、ユーザーが AWS 認証情報やアクセス許可を持つことなく、プライベート S3 オブジェクトへの一時的なアクセスを提供します。

たとえば、Alice に S3 オブジェクトへのアクセス権限があり、そのオブジェクトへのアクセス権限を一時的に Bob と共有するとします。Alice は、署名付き Get リクエストを生成して Bob との共有し、Bob が Alice の認証情報にアクセスすることなくそのオブジェクトをダウンロードできるようにすることができます。HTTP GET リクエストと HTTP PUT リクエスト用の署名付き URL を生成できます。

## オブジェクトの署名付き URL を生成して、オブジェクトをダウンロードします (GET リクエスト)。
<a name="get-presignedobject"></a>

以下の例は次の 2 つの部分で構成されます。
+ パート 1: Alice はオブジェクトの署名付き URL を生成します。
+ パート 2: Bob は署名済み URL を使用してオブジェクトをダウンロードします。

### パート 1: URL を生成する
<a name="get-presigned-object-part1"></a>

Alice はすでに S3 バケットにオブジェクトを持っています。彼女は次のコードを使用して、Bob が後続の GET リクエストで使用できる URL 文字列を生成します。

#### インポート
<a name="get-presigned-example-imports"></a>

```
import com.example.s3.util.PresignUrlUtils;
import org.slf4j.Logger;
import software.amazon.awssdk.http.HttpExecuteRequest;
import software.amazon.awssdk.http.HttpExecuteResponse;
import software.amazon.awssdk.http.SdkHttpClient;
import software.amazon.awssdk.http.SdkHttpMethod;
import software.amazon.awssdk.http.SdkHttpRequest;
import software.amazon.awssdk.http.apache.ApacheHttpClient;
import software.amazon.awssdk.services.s3.S3Client;
import software.amazon.awssdk.services.s3.model.GetObjectRequest;
import software.amazon.awssdk.services.s3.model.S3Exception;
import software.amazon.awssdk.services.s3.presigner.S3Presigner;
import software.amazon.awssdk.services.s3.presigner.model.GetObjectPresignRequest;
import software.amazon.awssdk.services.s3.presigner.model.PresignedGetObjectRequest;
import software.amazon.awssdk.utils.IoUtils;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.file.Paths;
import java.time.Duration;
import java.util.UUID;
```

```
    /* Create a pre-signed URL to download an object in a subsequent GET request. */
    public String createPresignedGetUrl(String bucketName, String keyName) {
        try (S3Presigner presigner = S3Presigner.create()) {

            GetObjectRequest objectRequest = GetObjectRequest.builder()
                    .bucket(bucketName)
                    .key(keyName)
                    .build();

            GetObjectPresignRequest presignRequest = GetObjectPresignRequest.builder()
                    .signatureDuration(Duration.ofMinutes(10))  // The URL will expire in 10 minutes.
                    .getObjectRequest(objectRequest)
                    .build();

            PresignedGetObjectRequest presignedRequest = presigner.presignGetObject(presignRequest);
            logger.info("Presigned URL: [{}]", presignedRequest.url().toString());
            logger.info("HTTP method: [{}]", presignedRequest.httpRequest().method());

            return presignedRequest.url().toExternalForm();
        }
    }
```

### パート 2: オブジェクトをダウンロードする
<a name="get-presigned-object-part2"></a>

ボブは次の 3 つのコードオプションのいずれかを使用してオブジェクトをダウンロードします。または、ブラウザを使用して GET リクエストを実行することもできます。

#### JDK `HttpURLConnection` を使用する (v1.1 以降)
<a name="get-presigned-example-useHttpUrlConnection"></a>

```
    /* Use the JDK HttpURLConnection (since v1.1) class to do the download. */
    public byte[] useHttpUrlConnectionToGet(String presignedUrlString) {
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); // Capture the response body to a byte array.

        try {
            URL presignedUrl = new URL(presignedUrlString);
            HttpURLConnection connection = (HttpURLConnection) presignedUrl.openConnection();
            connection.setRequestMethod("GET");
            // Download the result of executing the request.
            try (InputStream content = connection.getInputStream()) {
                IoUtils.copy(content, byteArrayOutputStream);
            }
            logger.info("HTTP response code is " + connection.getResponseCode());

        } catch (S3Exception | IOException e) {
            logger.error(e.getMessage(), e);
        }
        return byteArrayOutputStream.toByteArray();
    }
```

#### JDK `HttpClient` を使用する (v11 以降)
<a name="get-presigned-example-useHttpClient"></a>

```
    /* Use the JDK HttpClient (since v11) class to do the download. */
    public byte[] useHttpClientToGet(String presignedUrlString) {
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); // Capture the response body to a byte array.

        HttpRequest.Builder requestBuilder = HttpRequest.newBuilder();
        HttpClient httpClient = HttpClient.newHttpClient();
        try {
            URL presignedUrl = new URL(presignedUrlString);
            HttpResponse<InputStream> response = httpClient.send(requestBuilder
                            .uri(presignedUrl.toURI())
                            .GET()
                            .build(),
                    HttpResponse.BodyHandlers.ofInputStream());

            IoUtils.copy(response.body(), byteArrayOutputStream);

            logger.info("HTTP response code is " + response.statusCode());

        } catch (URISyntaxException | InterruptedException | IOException e) {
            logger.error(e.getMessage(), e);
        }
        return byteArrayOutputStream.toByteArray();
    }
```

#### SDK for Java から `SdkHttpClient` を使用する
<a name="get-presigned-example-useSdkHttpClient"></a>

```
    /* Use the AWS SDK for Java SdkHttpClient class to do the download. */
    public byte[] useSdkHttpClientToGet(String presignedUrlString) {

        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); // Capture the response body to a byte array.
        try {
            URL presignedUrl = new URL(presignedUrlString);
            SdkHttpRequest request = SdkHttpRequest.builder()
                    .method(SdkHttpMethod.GET)
                    .uri(presignedUrl.toURI())
                    .build();

            HttpExecuteRequest executeRequest = HttpExecuteRequest.builder()
                    .request(request)
                    .build();

            try (SdkHttpClient sdkHttpClient = ApacheHttpClient.create()) {
                HttpExecuteResponse response = sdkHttpClient.prepareRequest(executeRequest).call();
                response.responseBody().ifPresentOrElse(
                        abortableInputStream -> {
                            try {
                                IoUtils.copy(abortableInputStream, byteArrayOutputStream);
                            } catch (IOException e) {
                                throw new RuntimeException(e);
                            }
                        },
                        () -> logger.error("No response body."));

                logger.info("HTTP Response code is {}", response.httpResponse().statusCode());
            }
        } catch (URISyntaxException | IOException e) {
            logger.error(e.getMessage(), e);
        }
        return byteArrayOutputStream.toByteArray();
    }
```

GitHub で[完全な例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/d73001daea05266eaa9e074ccb71b9383832369a/javav2/example_code/s3/src/main/java/com/example/s3/GeneratePresignedGetUrlAndRetrieve.java)と[テスト](https://github.com/awsdocs/aws-doc-sdk-examples/blob/d73001daea05266eaa9e074ccb71b9383832369a/javav2/example_code/s3/src/test/java/com/example/s3/presignurl/GeneratePresignedGetUrlTests.java)をご覧ください。

## アップロード用の署名付き URL を生成して、ファイルをアップロードします (PUT リクエスト)。
<a name="put-presignedobject"></a>

以下の例は次の 2 つの部分で構成されます。
+ パート 1: Alice はオブジェクトをアップロードするために署名付き URL を生成します。
+ パート 2: Bob は署名済み URL を使用してファイルをアップロードします。

### パート 1: URL を生成する
<a name="put-presigned-object-part1"></a>

Alice はすでに S3 バケットを持っています。彼女は次のコードを使用して、Bob が後続の PUT リクエストで使用できる URL 文字列を生成します。

#### インポート
<a name="put-presigned-example-imports"></a>

```
import com.example.s3.util.PresignUrlUtils;
import org.slf4j.Logger;
import software.amazon.awssdk.core.internal.sync.FileContentStreamProvider;
import software.amazon.awssdk.http.HttpExecuteRequest;
import software.amazon.awssdk.http.HttpExecuteResponse;
import software.amazon.awssdk.http.SdkHttpClient;
import software.amazon.awssdk.http.SdkHttpMethod;
import software.amazon.awssdk.http.SdkHttpRequest;
import software.amazon.awssdk.http.apache.ApacheHttpClient;
import software.amazon.awssdk.services.s3.S3Client;
import software.amazon.awssdk.services.s3.model.PutObjectRequest;
import software.amazon.awssdk.services.s3.model.S3Exception;
import software.amazon.awssdk.services.s3.presigner.S3Presigner;
import software.amazon.awssdk.services.s3.presigner.model.PresignedPutObjectRequest;
import software.amazon.awssdk.services.s3.presigner.model.PutObjectPresignRequest;

import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.Duration;
import java.util.Map;
import java.util.UUID;
```

```
    /* Create a presigned URL to use in a subsequent PUT request */
    public String createPresignedUrl(String bucketName, String keyName, Map<String, String> metadata) {
        try (S3Presigner presigner = S3Presigner.create()) {

            PutObjectRequest objectRequest = PutObjectRequest.builder()
                    .bucket(bucketName)
                    .key(keyName)
                    .metadata(metadata)
                    .build();

            PutObjectPresignRequest presignRequest = PutObjectPresignRequest.builder()
                    .signatureDuration(Duration.ofMinutes(10))  // The URL expires in 10 minutes.
                    .putObjectRequest(objectRequest)
                    .build();


            PresignedPutObjectRequest presignedRequest = presigner.presignPutObject(presignRequest);
            String myURL = presignedRequest.url().toString();
            logger.info("Presigned URL to upload a file to: [{}]", myURL);
            logger.info("HTTP method: [{}]", presignedRequest.httpRequest().method());

            return presignedRequest.url().toExternalForm();
        }
    }
```

### パート 2: ファイルオブジェクトをアップロードする
<a name="put-presigned-object-part2"></a>

ボブは次の 3 つのコードオプションのいずれかを使用してファイルをアップロードします。

#### JDK `HttpURLConnection` を使用する (v1.1 以降)
<a name="put-presigned-example-useHttpUrlConnection"></a>

```
    /* Use the JDK HttpURLConnection (since v1.1) class to do the upload. */
    public void useHttpUrlConnectionToPut(String presignedUrlString, File fileToPut, Map<String, String> metadata) {
        logger.info("Begin [{}] upload", fileToPut.toString());
        try {
            URL presignedUrl = new URL(presignedUrlString);
            HttpURLConnection connection = (HttpURLConnection) presignedUrl.openConnection();
            connection.setDoOutput(true);
            metadata.forEach((k, v) -> connection.setRequestProperty("x-amz-meta-" + k, v));
            connection.setRequestMethod("PUT");
            OutputStream out = connection.getOutputStream();

            try (RandomAccessFile file = new RandomAccessFile(fileToPut, "r");
                 FileChannel inChannel = file.getChannel()) {
                ByteBuffer buffer = ByteBuffer.allocate(8192); //Buffer size is 8k

                while (inChannel.read(buffer) > 0) {
                    buffer.flip();
                    for (int i = 0; i < buffer.limit(); i++) {
                        out.write(buffer.get());
                    }
                    buffer.clear();
                }
            } catch (IOException e) {
                logger.error(e.getMessage(), e);
            }

            out.close();
            connection.getResponseCode();
            logger.info("HTTP response code is " + connection.getResponseCode());

        } catch (S3Exception | IOException e) {
            logger.error(e.getMessage(), e);
        }
    }
```

#### JDK `HttpClient` を使用する (v11 以降)
<a name="put-presigned-example-useHttpClient"></a>

```
    /* Use the JDK HttpClient (since v11) class to do the upload. */
    public void useHttpClientToPut(String presignedUrlString, File fileToPut, Map<String, String> metadata) {
        logger.info("Begin [{}] upload", fileToPut.toString());

        HttpRequest.Builder requestBuilder = HttpRequest.newBuilder();
        metadata.forEach((k, v) -> requestBuilder.header("x-amz-meta-" + k, v));

        HttpClient httpClient = HttpClient.newHttpClient();
        try {
            final HttpResponse<Void> response = httpClient.send(requestBuilder
                            .uri(new URL(presignedUrlString).toURI())
                            .PUT(HttpRequest.BodyPublishers.ofFile(Path.of(fileToPut.toURI())))
                            .build(),
                    HttpResponse.BodyHandlers.discarding());

            logger.info("HTTP response code is " + response.statusCode());

        } catch (URISyntaxException | InterruptedException | IOException e) {
            logger.error(e.getMessage(), e);
        }
    }
```

#### SDK for Java から `SdkHttpClient` を使用する
<a name="put-presigned-example-useSdkHttpClient"></a>

```
    /* Use the AWS SDK for Java V2 SdkHttpClient class to do the upload. */
    public void useSdkHttpClientToPut(String presignedUrlString, File fileToPut, Map<String, String> metadata) {
        logger.info("Begin [{}] upload", fileToPut.toString());

        try {
            URL presignedUrl = new URL(presignedUrlString);

            SdkHttpRequest.Builder requestBuilder = SdkHttpRequest.builder()
                    .method(SdkHttpMethod.PUT)
                    .uri(presignedUrl.toURI());
            // Add headers
            metadata.forEach((k, v) -> requestBuilder.putHeader("x-amz-meta-" + k, v));
            // Finish building the request.
            SdkHttpRequest request = requestBuilder.build();

            HttpExecuteRequest executeRequest = HttpExecuteRequest.builder()
                    .request(request)
                    .contentStreamProvider(new FileContentStreamProvider(fileToPut.toPath()))
                    .build();

            try (SdkHttpClient sdkHttpClient = ApacheHttpClient.create()) {
                HttpExecuteResponse response = sdkHttpClient.prepareRequest(executeRequest).call();
                logger.info("Response code: {}", response.httpResponse().statusCode());
            }
        } catch (URISyntaxException | IOException e) {
            logger.error(e.getMessage(), e);
        }
    }
```

GitHub で[完全な例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/d73001daea05266eaa9e074ccb71b9383832369a/javav2/example_code/s3/src/main/java/com/example/s3/GeneratePresignedUrlAndPutFileWithMetadata.java)と[テスト](https://github.com/awsdocs/aws-doc-sdk-examples/blob/d73001daea05266eaa9e074ccb71b9383832369a/javav2/example_code/s3/src/test/java/com/example/s3/presignurl/GeneratePresignedPutUrlTests.java)をご覧ください。

# Amazon S3 のクロスリージョンアクセス
<a name="s3-cross-region"></a>

Amazon Simple Storage Service (Amazon S3) バケットで作業をする場合、通常そのバケットの AWS リージョン を知っています。使用するリージョンは、S3 クライアントの作成時に決定されます。

ただし、特定のバケットを操作する必要があったとしても、そのバケットが S3 クライアントに設定されているのと同じリージョンにあるかどうかわからない場合があります。

バケットのリージョンを特定するためにさらに呼び出しを行う代わりに、SDK を使用してさまざまなリージョンの S3 バケットにアクセスできるようにすることができます。

## セットアップ
<a name="s3-cross-region-setup"></a>

クロスリージョンアクセスに関するサポートは、SDK のバージョン `2.20.111` で利用可能になりました。次のスニペットに示すように、Maven ビルドファイルの `s3` 依存関係には、このバージョンまたはそれ以降のバージョンを使用します。

```
<dependency>
  <groupId>software.amazon.awssdk</groupId>
  <artifactId>s3</artifactId>
  <version>2.27.21</version>
</dependency>
```

次に、S3 クライアントを作成するときに、スニペットに示すようにクロスリージョンアクセスを有効にします。デフォルトでは、アクセスは有効になっていません。

```
S3AsyncClient client = S3AsyncClient.builder()
                                    .crossRegionAccessEnabled(true)
                                    .build();
```

## SDK がクロスリージョンアクセスを提供する方法
<a name="s3-cross-region-routing"></a>

`putObject` メソッドを使用する場合など、リクエストで既存のバケットを参照すると、SDK はクライアント用に設定されたリージョンへのリクエストを開始します。

その特定のリージョンにバケットが存在しない場合、エラーレスポンスにはバケットが存在する実際のリージョンが含まれます。その後、SDK は 2 回目のリクエストで正しいリージョンを使用します。

同じバケットへの今後のリクエストを最適化するために、SDK はこのリージョンマッピングをクライアントにキャッシュします。

## 考慮事項
<a name="s3-cross-region-considerations"></a>

クロスリージョンバケットアクセスを有効にする場合、バケットがクライアントの設定済みリージョンにない場合、最初の API コールでレイテンシーが増加する可能性があることに注意してください。ただし、それ以降のコールではキャッシュされたリージョン情報が有効になるため、パフォーマンスが向上します。

クロスリージョンアクセスを有効にする場合、バケットへのアクセスには影響しません。ユーザーは、そのバケットが存在するリージョンに関係なく、バケットにアクセスする権限を持っている必要があります。

# チェックサムによるデータ整合性保護
<a name="s3-checksums"></a>

Amazon Simple Storage Service (Amazon S3) では、オブジェクトをアップロードするときにチェックサムを指定できます。チェックサムを指定すると、そのチェックサムはオブジェクトとともに保存され、オブジェクトのダウンロード時に検証できます。

チェックサムは、ファイルを転送する際のデータの整合性をさらに強化します。チェックサムを使用すると、受信したファイルが元のファイルと一致することを確認することで、データ整合性を検証できます。Amazon S3 でのチェックサムの詳細については、[サポート対象アルゴリズム](https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html#using-additional-checksums)など、「[Amazon Simple Storage Service ユーザーガイド](https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html)」を参照してください。

ニーズに最適なアルゴリズムを柔軟に選択して、SDK にチェックサムを計算させることができます。または、サポートされているアルゴリズムのいずれかを使用して、事前に計算された独自のチェックサム値を指定することもできます。

**注記**  
 AWS SDK for Java 2.xのバージョン 2.30.0 以降、SDK はアップロードの `CRC32` チェックサムを自動的に計算することで、デフォルトの整合性保護を提供します。事前計算されたチェックサム値を指定しない場合、または SDK がチェックサムの計算に使用するアルゴリズムを指定しない場合、SDK はこのチェックサムを計算します。   
SDK には、外部で設定できるデータ整合性保護のグローバル設定も用意されています。詳細については、「[AWS SDK とツールのリファレンスガイド](https://docs.aws.amazon.com/sdkref/latest/guide/feature-dataintegrity.html)」を参照してください。

チェックサムについては、オブジェクトのアップロードとオブジェクトのダウンロードという 2 つのリクエストフェーズで説明します。

## オブジェクトのアップロード
<a name="use-service-S3-checksum-upload"></a>

`putObject` メソッドでオブジェクトをアップロードし、チェックサムアルゴリズムを指定した場合、SDK は指定したアルゴリズムでチェックサムを計算します。 

次のコードスニペットは、`SHA256` チェックサムを含むオブジェクトをアップロードするリクエストを示しています。SDK はリクエストを送信すると、`SHA256` チェックサムを計算してオブジェクトをアップロードします。Amazon S3 は、チェックサムを計算し、SDK によって提供されるチェックサムと比較することで、コンテンツの整合性を検証します。次に、Amazon S3 はオブジェクトと共にチェックサムを保存します。

```
public void putObjectWithChecksum() {
        s3Client.putObject(b -> b
                .bucket(bucketName)
                .key(key)
                .checksumAlgorithm(ChecksumAlgorithm.SHA256),
            RequestBody.fromString("This is a test"));
}
```

リクエストでチェックサムアルゴリズムを指定しない場合、チェックサムの動作は、次の表に示すように、使用する SDK のバージョンによって異なります。

**チェックサムアルゴリズムが指定されていない場合のチェックサムの動作**


| Java SDK バージョン | チェックサムの動作 | 
| --- | --- | 
| 2.30.0 より前 | SDK は、CRC ベースのチェックサムを自動的に計算してリクエストに含めることはありません。 | 
| 2.30.0 以降 | SDK は、`CRC32` アルゴリズムを使用してチェックサムを計算し、リクエストに含めます。Amazon S3 は、独自の `CRC32` チェックサムを計算して転送の整合性を検証し、SDK が提供するチェックサムと比較します。チェックサムが一致した場合、チェックサムはオブジェクトとともに保存されます。 | 

### 事前に計算されたチェックサム値を使用してください。
<a name="use-service-S3-checksum-upload-pre"></a>

リクエストで事前に計算されたチェックサム値を指定すると、SDK による自動計算が無効になり、代わりに提供された値が使用されます。

次の例は、SHA256 チェックサムが事前に計算されたリクエストを示しています。

```
    public void putObjectWithPrecalculatedChecksum(String filePath) {
        String checksum = calculateChecksum(filePath, "SHA-256");

        s3Client.putObject((b -> b
                .bucket(bucketName)
                .key(key)
                .checksumSHA256(checksum)),
            RequestBody.fromFile(Paths.get(filePath)));
    }
```

Amazon S3 が、指定されたアルゴリズムのチェックサム値が正しくないと判断した場合、サービスはエラーレスポンスを返します。

### マルチパートアップロード
<a name="use-service-S3-checksum-upload-multi"></a>

チェックサムはマルチパートアップロードでも使用できます。

 SDK for Java 2.x には、マルチパートアップロードでチェックサムを使用する 2 つのオプションがあります。最初のオプションでは `S3TransferManager` を使用します。

次の転送マネージャーの例では、アップロードに SHA1 アルゴリズムを指定しています。

```
    public void multipartUploadWithChecksumTm(String filePath) {
        S3TransferManager transferManager = S3TransferManager.create();
        UploadFileRequest uploadFileRequest = UploadFileRequest.builder()
            .putObjectRequest(b -> b
                .bucket(bucketName)
                .key(key)
                .checksumAlgorithm(ChecksumAlgorithm.SHA1))
            .source(Paths.get(filePath))
            .build();
        FileUpload fileUpload = transferManager.uploadFile(uploadFileRequest);
        fileUpload.completionFuture().join();
        transferManager.close();
    }
```

アップロードで Transfer Manager を使用する際にチェックサムアルゴリズムを指定しない場合、SDK は `CRC32` アルゴリズムに基づいてチェックサムを自動的に計算します。SDK は、SDK のすべてのバージョンに対してこの計算を実行します。

2 つ目のオプションは [`S3Client`API](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/s3/S3Client.html) (または [`S3AsyncClient`API](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/s3/S3AsyncClient.html)) を使用してマルチパートアップロードを実行します。このアプローチでチェックサムを指定する場合は、アップロードの開始時に使用するアルゴリズムを指定する必要があります。また、パートリクエストごとにアルゴリズムを指定し、アップロード後にパートごとに計算されたチェックサムを指定する必要があります。

```
    public void multipartUploadWithChecksumS3Client(String filePath) {
        ChecksumAlgorithm algorithm = ChecksumAlgorithm.CRC32;

        // Initiate the multipart upload.
        CreateMultipartUploadResponse createMultipartUploadResponse = s3Client.createMultipartUpload(b -> b
            .bucket(bucketName)
            .key(key)
            .checksumAlgorithm(algorithm)); // Checksum specified on initiation.
        String uploadId = createMultipartUploadResponse.uploadId();

        // Upload the parts of the file.
        int partNumber = 1;
        List<CompletedPart> completedParts = new ArrayList<>();
        ByteBuffer bb = ByteBuffer.allocate(1024 * 1024 * 5); // 5 MB byte buffer

        try (RandomAccessFile file = new RandomAccessFile(filePath, "r")) {
            long fileSize = file.length();
            long position = 0;
            while (position < fileSize) {
                file.seek(position);
                long read = file.getChannel().read(bb);

                bb.flip(); // Swap position and limit before reading from the buffer.
                UploadPartRequest uploadPartRequest = UploadPartRequest.builder()
                    .bucket(bucketName)
                    .key(key)
                    .uploadId(uploadId)
                    .checksumAlgorithm(algorithm) // Checksum specified on each part.
                    .partNumber(partNumber)
                    .build();

                UploadPartResponse partResponse = s3Client.uploadPart(
                    uploadPartRequest,
                    RequestBody.fromByteBuffer(bb));

                CompletedPart part = CompletedPart.builder()
                    .partNumber(partNumber)
                    .checksumCRC32(partResponse.checksumCRC32()) // Provide the calculated checksum.
                    .eTag(partResponse.eTag())
                    .build();
                completedParts.add(part);

                bb.clear();
                position += read;
                partNumber++;
            }
        } catch (IOException e) {
            System.err.println(e.getMessage());
        }

        // Complete the multipart upload.
        s3Client.completeMultipartUpload(b -> b
            .bucket(bucketName)
            .key(key)
            .uploadId(uploadId)
            .multipartUpload(CompletedMultipartUpload.builder().parts(completedParts).build()));
    }
```

[完全な例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/main/javav2/example_code/s3/src/main/java/com/example/s3/PerformMultiPartUpload.java)と[テスト](https://github.com/awsdocs/aws-doc-sdk-examples/blob/main/javav2/example_code/s3/src/test/java/com/example/s3/PerformMultiPartUploadTests.java)のコードは、GitHub のコードサンプルリポジトリにあります。

## オブジェクトのダウンロード
<a name="use-service-S3-checksum-download"></a>

[getObject](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/s3/S3Client.html#getObject(software.amazon.awssdk.services.s3.model.GetObjectRequest)) メソッドを使用してオブジェクトをダウンロードすると、SDK は `GetObjectRequest` のビルダーの `checksumMode` のメソッドが `ChecksumMode.ENABLED` に設定されている場合にチェックサムを自動的に検証します。

次のスニペット内のリクエストは、チェックサムを計算して値を比較することでレスポンス内のチェックサムを検証するよう SDK に指示します。

```
    public GetObjectResponse getObjectWithChecksum() {
        return s3Client.getObject(b -> b
                        .bucket(bucketName)
                        .key(key)
                        .checksumMode(ChecksumMode.ENABLED))
                .response();
    }
```

**注記**  
オブジェクトがチェックサム付きでアップロードされなかった場合、検証は行われません。

## その他のチェックサム計算オプション
<a name="S3-checsum-calculation-options"></a>

**注記**  
送信データの整合性を検証し、送信エラーを検出するために、チェックサム計算オプションについては SDK のデフォルト設定を維持することをお勧めします。デフォルトでは、SDK は `PutObject` や `GetObject` を含む多くの S3 オペレーションに対して、この重要なチェックを追加します。

ただし、Amazon S3 の使用で最小限のチェックサム検証しか必要としない場合は、デフォルトの設定を変更することで、多くのチェックを無効にできます。

### 必須でない場合に自動チェックサム計算を無効にする
<a name="S3-minimize-checksum-calc-global"></a>

SDK がサポートするオペレーション（例：`PutObject` や `GetObject`）に対して、自動チェックサム計算を無効にできます。ただし、一部の S3 オペレーションではチェックサムの計算が必須であり、これらのオペレーションではチェックサム計算を無効にすることはできません。

SDK は、リクエストのペイロード用チェックサムの計算と、レスポンスのペイロード用チェックサムの計算をそれぞれ個別の設定として提供します。

次のリストでは、さまざまな範囲でのチェックサム計算を最小限に抑えるために使用できる設定について説明します。
+ **すべてのアプリケーションスコープ** — 環境変数または共有 AWS `config` および `credentials` ファイル内のプロファイルの設定を変更することで、すべてのアプリケーションがこれらの設定を使用できます。これらの設定は、アプリケーションまたはサービスクライアントスコープで上書きされない限り、すべての AWS SDK アプリケーションのすべてのサービスクライアントに影響します。
  + プロファイルで設定を追加します。

    ```
    [default]
    request_checksum_calculation = WHEN_REQUIRED
    response_checksum_validation = WHEN_REQUIRED
    ```
  + 環境変数を追加します。

    ```
    AWS_REQUEST_CHECKSUM_CALCULATION=WHEN_REQUIRED
    AWS_RESPONSE_CHECKSUM_VALIDATION=WHEN_REQUIRED
    ```
+ **現在のアプリケーション範囲** — Java システムプロパティ `aws.requestChecksumCalculation` を `WHEN_REQUIRED` に設定して、チェックサムの計算を制限できます。レスポンスの対応するシステムプロパティは `aws.responseChecksumValidation` です。

  これらの設定は、サービスクライアントの作成中に上書きされない限り、アプリケーション内のすべての SDK サービスクライアントに影響します。

  アプリケーションの開始時にシステムプロパティを設定します。

  ```
  import software.amazon.awssdk.core.SdkSystemSetting;
  import software.amazon.awssdk.core.checksums.RequestChecksumCalculation;
  import software.amazon.awssdk.core.checksums.ResponseChecksumValidation;
  import software.amazon.awssdk.services.s3.S3Client;
  
  class DemoClass {
      public static void main(String[] args) {
  
          System.setProperty(SdkSystemSetting.AWS_REQUEST_CHECKSUM_CALCULATION.property(), // Resolves to "aws.requestChecksumCalculation".
                  "WHEN_REQUIRED");
          System.setProperty(SdkSystemSetting.AWS_RESPONSE_CHECKSUM_VALIDATION.property(), // Resolves to "aws.responseChecksumValidation".
                  "WHEN_REQUIRED");
  
          S3Client s3Client = S3Client.builder().build();
  
          // Use s3Client.
      }
  }
  ```
+ **単一の S3 サービスクライアント範囲** — ビルダーメソッドを使用して、最小量のチェックサムを計算するように単一の S3 サービスクライアントを設定できます。

  ```
  import software.amazon.awssdk.core.checksums.RequestChecksumCalculation;
  import software.amazon.awssdk.services.s3.S3Client;
  
  public class RequiredChecksums {
      public static void main(String[] args) {
          S3Client s3 = S3Client.builder()
                  .requestChecksumCalculation(RequestChecksumCalculation.WHEN_REQUIRED)
                  .responseChecksumValidation(ResponseChecksumValidation.WHEN_REQUIRED)
                  .build();
  
          // Use s3Client. 
      }
  // ...
  }
  ```

### `LegacyMd5Plugin` を使用した MD5 との互換性の簡素化
<a name="S3-checksum-legacy-md5"></a>

バージョン 2.30.0 での CRC32 チェックサム動作のリリースに加えて、SDK は必要なオペレーションの MD5 チェックサムの計算を停止しました。

S3 オペレーションにレガシーの MD5 チェックサム動作が必要な場合は、 SDK のバージョン 2.31.32 でリリースされた `LegacyMd5Plugin` を使用できます。

`LegacyMd5Plugin` は、レガシー MD5 チェックサムの動作に依存するアプリケーションとの互換性を維持する必要がある場合、特に S3A ファイルシステムコネクタで使用されるようなサードパーティの S3 互換ストレージプロバイダーを使用する場合に特に便利です (Apache Spark、Iceberg) 。

`LegacyMd5Plugin` を使用するには、S3 クライアントビルダーに追加します。

```
// For synchronous S3 client.
S3Client s3Client = S3Client.builder()
                           .addPlugin(LegacyMd5Plugin.create())
                           .build();

// For asynchronous S3 client.
S3AsyncClient asyncClient = S3AsyncClient.builder()
                                       .addPlugin(LegacyMd5Plugin.create())
                                       .build();
```

チェックサムが必要なオペレーションに MD5 チェックサムを追加し、チェックサムをサポートしているが必須ではないオペレーションに対しては SDK デフォルトチェックサムの追加をスキップする場合は、`ClientBuilder` オプション `requestChecksumCalculation` および `responseChecksumValidation` を `WHEN_REQUIRED` として有効にできます。これにより、SDK のデフォルトのチェックサムのみが、チェックサムを必要とするオペレーションに追加されます。

```
// Use the `LegacyMd5Plugin` with `requestChecksumCalculation` and `responseChecksumValidation` set to WHEN_REQUIRED.
S3AsyncClient asyncClient = S3AsyncClient.builder()
                                       .addPlugin(LegacyMd5Plugin.create())
                                       .requestChecksumCalculation(RequestChecksumCalculation.WHEN_REQUIRED)
                                       .responseChecksumValidation(ResponseChecksumValidation.WHEN_REQUIRED)
                                       .build();
```

この設定は、新しいチェックサムアルゴリズムを完全にはサポートしていないものの、特定のオペレーションに MD5 チェックサムが必要なサードパーティーの S3 互換ストレージシステムを使用する場合に特に便利です。

# パフォーマンスの高い S3 クライアントを使用する: AWS CRT ベースの S3 クライアント
<a name="crt-based-s3-client"></a>

Common Runtime ( AWS CRT) 上に構築された CRT ベースの S3 クライアントは、代替の S3 非同期クライアントです。 [AWS](https://docs.aws.amazon.com/sdkref/latest/guide/common-runtime.html)Amazon S3 の[マルチパートアップロード API](https://docs.aws.amazon.com/AmazonS3/latest/userguide/mpuoverview.html) と[バイト範囲フェッチ](https://docs.aws.amazon.com/AmazonS3/latest/userguide/optimizing-performance-guidelines.html#optimizing-performance-guidelines-get-range)を自動的に使用することで、Amazon Simple Storage Service (Amazon S3) との間でオブジェクトを転送し、パフォーマンスと信頼性を向上させます。

 AWS CRT ベースの S3 クライアントは、ネットワーク障害が発生した場合の転送の信頼性を向上させます。ファイル転送を最初からやり直すことなく、失敗した個別の部分を再試行することで、信頼性を改善しています。

さらに、CRT AWS ベースの S3 クライアントは、強化された接続プーリングとドメインネームシステム (DNS) ロードバランシングを提供し、スループットも向上します。

SDK の標準 S3 非同期クライアントの代わりに AWS CRT ベースの S3 クライアントを使用し、その改善されたスループットをすぐに活用できます。

**重要**  
 AWS CRT ベースの S3 クライアントは現在、クライアントレベルまたはリクエストレベルで [SDK メトリクス収集](metrics.md)をサポートしていません。

**AWS SDK の CRT ベースのコンポーネント**

このトピックで説明されている AWS CRT ベースの* S3* クライアントと CRT AWS ベースの *HTTP* クライアントは SDK の異なるコンポーネントです。

**AWS CRT ベースの S3 クライアント**は [S3AsyncClient](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/s3/S3AsyncClient.html) インターフェイスの実装であり、Amazon S3 サービスを利用するために使用されます。これは `S3AsyncClient` インターフェイスの Java ベースの実装に代わるもので、いくつかの利点があります。

[AWS CRT ベースの HTTP クライアント](http-configuration-crt.md)は、[SDKASyncHttpClient](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/http/async/SdkAsyncHttpClient.html) インターフェースを実装したもので、一般的な HTTP 通信に使用されます。これは `SdkAsyncHttpClient` インターフェースの Netty 実装に代わるもので、いくつかの利点があります。

どちらのコンポーネントも [AWS Common Runtime](https://docs.aws.amazon.com/sdkref/latest/guide/common-runtime.html) のライブラリを使用しますが、 AWS CRT ベースの S3 クライアントは [aws-c-s3 ライブラリ](https://github.com/awslabs/aws-c-s3)を使用し、[S3 マルチパートアップロード API ](https://docs.aws.amazon.com/AmazonS3/latest/userguide/mpuoverview.html)機能をサポートしています。 AWS CRT ベースの HTTP クライアントは汎用であるため、S3 マルチパートアップロード API 機能はサポートされていません。

## CRT AWS ベースの S3 クライアントを使用するための依存関係を追加する
<a name="crt-based-s3-client-depend"></a>

 AWS CRT ベースの S3 クライアントを使用するには、Maven プロジェクトファイルに次の 2 つの依存関係を追加します。この例は、使用する最小バージョンを示しています。Maven central リポジトリで [s3](https://central.sonatype.com/artifact/software.amazon.awssdk/s3) と [aws-crt](https://central.sonatype.com/artifact/software.amazon.awssdk.crt/aws-crt) のアーティファクトの最新バージョンを検索します。

```
<dependency>
  <groupId>software.amazon.awssdk</groupId>
  <artifactId>s3</artifactId>
  <version>2.27.21</version>
</dependency>
<dependency>
  <groupId>software.amazon.awssdk.crt</groupId>
  <artifactId>aws-crt</artifactId>
  <version>0.30.11</version>
</dependency>
```

## CRT AWS ベースの S3 クライアントのインスタンスを作成する
<a name="crt-based-s3-client-create"></a>

 次のコードスニペットに示すように、デフォルト設定で AWS CRT ベースの S3 クライアントのインスタンスを作成します。

```
S3AsyncClient s3AsyncClient = S3AsyncClient.crtCreate();
```

クライアントを設定するには、CRT AWS クライアントビルダーを使用します。ビルダーメソッドを変更することで、標準の S3 非同期クライアントから AWS CRT ベースのクライアントに切り替えることができます。

```
import software.amazon.awssdk.auth.credentials.DefaultCredentialsProvider;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.s3.S3AsyncClient;


S3AsyncClient s3AsyncClient = 
        S3AsyncClient.crtBuilder()
                     .credentialsProvider(DefaultCredentialsProvider.create())
                     .region(Region.US_WEST_2)
                     .targetThroughputInGbps(20.0)
                     .minimumPartSizeInBytes(8 * 1025 * 1024L)
                     .build();
```

**注記**  
スタンダードビルダーの設定の一部は、現在 AWS CRT クライアントビルダーではサポートされていない場合があります。スタンダードビルダーを取得するには、`S3AsyncClient#builder()` を呼び出します。

## CRT AWS ベースの S3 クライアントを使用する
<a name="crt-based-s3-client-use"></a>

 AWS CRT ベースの S3 クライアントを使用して Amazon S3 API オペレーションを呼び出します。次の例は、 AWS SDK for Javaを介して実行できる [PutObject](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/s3/S3AsyncClient.html#putObject(java.util.function.Consumer,software.amazon.awssdk.core.async.AsyncRequestBody)) オペレーションと [GetObject](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/s3/S3AsyncClient.html#getObject(java.util.function.Consumer,software.amazon.awssdk.core.async.AsyncResponseTransformer)) オペレーションを示しています。

```
import software.amazon.awssdk.core.async.AsyncRequestBody;
import software.amazon.awssdk.core.async.AsyncResponseTransformer;
import software.amazon.awssdk.services.s3.S3AsyncClient;
import software.amazon.awssdk.services.s3.model.GetObjectResponse;
import software.amazon.awssdk.services.s3.model.PutObjectResponse;


S3AsyncClient s3Client = S3AsyncClient.crtCreate();

// Upload a local file to Amazon S3.
PutObjectResponse putObjectResponse = 
      s3Client.putObject(req -> req.bucket(<BUCKET_NAME>)
                                   .key(<KEY_NAME>),
                        AsyncRequestBody.fromFile(Paths.get(<FILE_NAME>)))
              .join();

// Download an object from Amazon S3 to a local file.
GetObjectResponse getObjectResponse = 
      s3Client.getObject(req -> req.bucket(<BUCKET_NAME>)
                                   .key(<KEY_NAME>),
                        AsyncResponseTransformer.toFile(Paths.get(<FILE_NAME>)))
              .join();
```

## サイズが不明なストリームのアップロード
<a name="crt-stream-unknown-size"></a>

 AWS AWS CRT ベースの S3 クライアントの主な利点の 1 つは、サイズが不明な入力ストリームを効率的に処理できることです。これは、合計サイズを事前に判断できないソースからデータをアップロードする必要がある場合に特に便利です。

```
public PutObjectResponse crtClient_stream_unknown_size(String bucketName, String key, InputStream inputStream) {

    S3AsyncClient s3AsyncClient = S3AsyncClient.crtCreate();
    ExecutorService executor = Executors.newSingleThreadExecutor();
    AsyncRequestBody body = AsyncRequestBody.fromInputStream(inputStream, null, executor);  // 'null' indicates that the
                                                                                            // content length is unknown.
    CompletableFuture<PutObjectResponse> responseFuture =
            s3AsyncClient.putObject(r -> r.bucket(bucketName).key(key), body)
                    .exceptionally(e -> {
                        if (e != null){
                            logger.error(e.getMessage(), e);
                        }
                        return null;
                    });

    PutObjectResponse response = responseFuture.join(); // Wait for the response.
    executor.shutdown();
    return response;
}
```

この機能は、コンテンツの長さの指定が正しくないとオブジェクトの切り捨てやアップロードの失敗につながる可能性がある、従来のアップロードの一般的な問題を回避するのに役立ちます。

## 設定の制限
<a name="crt-based-s3-client-limitations"></a>

 AWS CRT ベースの S3 クライアントと Java ベースの S3 非同期クライアントは[同等の機能を提供し](examples-s3.md#s3-clients)、CRT AWS ベースの S3 クライアントはパフォーマンスエッジを提供します。ただし、 AWS CRT ベースの S3 クライアントには、Java ベースの S3 非同期クライアントの設定がありません。設定は次のとおりです。
+ *クライアントレベルの設定:* API コール試行のタイムアウト、圧縮実行インターセプター、メトリクスパブリッシャー、カスタム実行属性、カスタム詳細オプション、カスタムスケジュールのエグゼキュータサービス、カスタムヘッダー
+ *リクエストレベルの設定:* カスタム署名者、API コール試行タイムアウト

設定の違いの完全なリストについては、 API リファレンスを参照してください。


| Java ベースの S3 非同期クライアント | AWS CRT ベースの S3 クライアント | 
| --- | --- | 
| クライアントレベルの設定[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ja_jp/sdk-for-java/latest/developer-guide/crt-based-s3-client.html)リクエストレベルの設定[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ja_jp/sdk-for-java/latest/developer-guide/crt-based-s3-client.html) | クライアントレベルの設定[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ja_jp/sdk-for-java/latest/developer-guide/crt-based-s3-client.html)リクエストレベルの設定[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ja_jp/sdk-for-java/latest/developer-guide/crt-based-s3-client.html) | 

# 並列転送を使用するように Java ベースの S3 非同期クライアントを設定する
<a name="s3-async-client-multipart"></a>

バージョン 2.27.5 以降、標準の Java ベースの S3 非同期クライアントは、自動並列転送 (マルチパートアップロードおよびダウンロード) をサポートしています。Java ベースの S3 非同期クライアントを作成するときに、並列転送のサポートを設定します。

このセクションでは、並列転送を有効にする方法と設定をカスタマイズする方法について説明します。

## `S3AsyncClient` のインスタンスの作成
<a name="s3-async-client-multipart-create"></a>

[ビルダー](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/s3/S3AsyncClientBuilder.html)で `multipart*` メソッドを呼び出さずに `S3AsyncClient` インスタンスを作成する場合、並列転送は有効になりません。次の各ステートメントは、マルチパートアップロードとダウンロードのサポートなしで Java ベースの S3 非同期クライアントを作成します。

### マルチパートサポート*なしで*作成する
<a name="s3-async-client-mp-off"></a>

**Example**  

```
import software.amazon.awssdk.auth.credentials.ProcessCredentialsProvider;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.s3.S3AsyncClient;


S3AsyncClient s3Client = S3AsyncClient.create();

S3AsyncClient s3Client2 = S3AsyncClient.builder().build();

S3AsyncClient s3Client3 = S3AsyncClient.builder()
        .credentialsProvider(ProcessCredentialsProvider.builder().build())
        .region(Region.EU_NORTH_1)
        .build();
```

### マルチパートサポート*付きで*作成する
<a name="s3-async-client-mp-on"></a>

デフォルト設定で並列転送を有効にするには、ビルダーで `multipartEnabled` を呼び出し、次の例に示すように `true` を渡します。

**Example**  

```
S3AsyncClient s3AsyncClient2 = S3AsyncClient.builder()
        .multipartEnabled(true)
        .build();
```

デフォルト値は、 `thresholdInBytes` および `minimumPartSizeInBytes` 設定では 8 MiB です。

マルチパート設定をカスタマイズすると、次に示すように並列転送が自動的に有効になります。

**Example**  

```
import software.amazon.awssdk.services.s3.S3AsyncClient;
import static software.amazon.awssdk.transfer.s3.SizeConstant.MB;


S3AsyncClient s3AsyncClient2 = S3AsyncClient.builder()
        .multipartConfiguration(b -> b
                .thresholdInBytes(16 * MB)
                .minimumPartSizeInBytes(10 * MB))
        .build();
```

## サイズが不明なストリームのアップロード
<a name="java-async-client-stream-unknown-size"></a>

マルチパートが有効になっている Java ベースの S3 非同期クライアントは、合計サイズが事前にわからない入力ストリームを効率的に処理できます。

```
public PutObjectResponse asyncClient_multipart_stream_unknown_size(String bucketName, String key, InputStream inputStream) {

    S3AsyncClient s3AsyncClient = S3AsyncClient.builder().multipartEnabled(true).build();
    ExecutorService executor = Executors.newSingleThreadExecutor();
    AsyncRequestBody body = AsyncRequestBody.fromInputStream(inputStream, null, executor); // 'null' indicates that the
                                                                                           // content length is unknown.
    CompletableFuture<PutObjectResponse> responseFuture =
            s3AsyncClient.putObject(r -> r.bucket(bucketName).key(key), body)
                    .exceptionally(e -> {
                        if (e != null) {
                            logger.error(e.getMessage(), e);
                        }
                        return null;
                    });

    PutObjectResponse response = responseFuture.join(); // Wait for the response.
    executor.shutdown();
    return response;
}
```

このアプローチにより、切り捨てられたオブジェクトやアップロードの失敗など、コンテンツの長さを手動で指定した場合に発生する可能性のある問題を回避できます。

# Amazon S3 Transfer Manager を使用してファイルとディレクトリを転送する
<a name="transfer-manager"></a>

Amazon S3 転送マネージャは、 AWS SDK for Java 2.x用のオープンソースの高レベルファイル転送ユーティリティです。Amazon Simple Storage Service (Amazon S3) との間でファイルやディレクトリを転送するために使用します。

[AWS CRT ベースの S3 クライアント](crt-based-s3-client.md)または[マルチパートが有効になっている標準の Java ベースの S3 非同期クライアント](s3-async-client-multipart.md)上に構築すると、S3 Transfer Manager では[マルチパートアップロード API](https://docs.aws.amazon.com/AmazonS3/latest/userguide/mpuoverview.html) や[バイト範囲フェッチ](https://docs.aws.amazon.com/AmazonS3/latest/userguide/optimizing-performance-guidelines.html#optimizing-performance-guidelines-get-range)などのパフォーマンスの向上を活用できます。

S3 Transfer Manager では、転送の進行状況をリアルタイムでモニタリングし、転送を一時停止して後で実行することもできます。

## はじめに
<a name="transfer-manager-prerequisites"></a>

### ビルドファイルに依存関係を追加する
<a name="transfer-manager-add-dependency"></a>

S3 Transfer Manager で強化されたマルチパートパフォーマンスを利用するには、必要な依存関係を使用してビルドファイルを設定します。

------
#### [ Use the AWS CRT-based S3 client ]

```
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>software.amazon.awssdk</groupId>
            <artifactId>bom</artifactId>
            <version>2.27.211</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>
<dependencies>
    <dependency>
        <groupId>software.amazon.awssdk</groupId>
        <artifactId>s3-transfer-manager</artifactId>
    </dependency>
    <dependency>
        <groupId>software.amazon.awssdk.crt</groupId>
        <artifactId>aws-crt</artifactId>
        <version>0.29.1432</version>
    </dependency>
</dependencies>
```

1 [最新バージョン](https://central.sonatype.com/artifact/software.amazon.awssdk/bom)。 2 [最新バージョン](https://central.sonatype.com/artifact/software.amazon.awssdk.crt/aws-crt)。

------
#### [ Use the Java-based S3 async client ]

```
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>software.amazon.awssdk</groupId>
            <artifactId>bom</artifactId>
            <version>2.27.211</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>
<dependencies>
    <dependency>
        <groupId>software.amazon.awssdk</groupId>
        <artifactId>s3-transfer-manager</artifactId>
    </dependency>
</dependencies>
```

1 [最新バージョン](https://central.sonatype.com/artifact/software.amazon.awssdk/bom)。

------

### S3 Transfer Manager のインスタンスを作成する
<a name="transfer-manager-create"></a>

並列転送を有効にするには、CRT AWS ベースの S3 クライアントまたはマルチパートが有効になっている Java ベースの S3 非同期クライアントを渡す必要があります。次の例は、S3 Transfer Manager をカスタム設定する方法を示しています。

------
#### [ Use the AWS CRT-based S3 client ]

```
        S3AsyncClient s3AsyncClient = S3AsyncClient.crtBuilder()
                .credentialsProvider(DefaultCredentialsProvider.create())
                .region(Region.US_EAST_1)
                .targetThroughputInGbps(20.0)
                .minimumPartSizeInBytes(8 * MB)
                .build();

        S3TransferManager transferManager = S3TransferManager.builder()
                .s3Client(s3AsyncClient)
                .build();
```

------
#### [ Use the Java-based S3 async client ]

`aws-crt` 依存関係がビルドファイルに含まれていない場合、S3 Transfer Manager は SDK for Java 2.x で使用されている標準の Java ベースの S3 非同期クライアント上に構築されます。

**S3 クライアントのカスタム設定 - マルチパートを有効にする必要があります**

```
        S3AsyncClient s3AsyncClient = S3AsyncClient.builder()
                .multipartEnabled(true)
                .credentialsProvider(DefaultCredentialsProvider.create())
                .region(Region.US_EAST_1)
                .build();

        S3TransferManager transferManager = S3TransferManager.builder()
                .s3Client(s3AsyncClient)
                .build();
```

**S3 クライアントの設定なし - マルチパートサポートが自動的に有効になります**

```
S3TransferManager transferManager = S3TransferManager.create();
```

------

## S3 バケットにファイルをアップロードする
<a name="transfer-manager-upload"></a>

次の例は、ファイルのアップロード例と、アップロードの進行状況をログ記録する [LoggingTransferListener](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/transfer/s3/progress/LoggingTransferListener.html) をオプションで使用したものです。

S3 Transfer Manager を使用して Amazon S3 にファイルをアップロードするには、`S3TransferManager`の [uploadFile](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/transfer/s3/S3TransferManager.html#uploadFile(software.amazon.awssdk.transfer.s3.model.UploadFileRequest)) メソッドに[https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/transfer/s3/model/UploadFileRequest.html](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/transfer/s3/model/UploadFileRequest.html) オブジェクトを渡します。

`uploadFile` メソッドから返される [FileUpload](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/transfer/s3/model/FileUpload.html) オブジェクトはアップロードプロセスを表します。リクエストが完了すると、[CompletedFileUpload](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/transfer/s3/model/CompletedFileUpload.html) オブジェクトはアップロードに関する情報を含めます。

```
    public void trackUploadFile(S3TransferManager transferManager, String bucketName,
                             String key, URI filePathURI) {
        UploadFileRequest uploadFileRequest = UploadFileRequest.builder()
                .putObjectRequest(b -> b.bucket(bucketName).key(key))
                .addTransferListener(LoggingTransferListener.create())  // Add listener.
                .source(Paths.get(filePathURI))
                .build();

        FileUpload fileUpload = transferManager.uploadFile(uploadFileRequest);

        fileUpload.completionFuture().join();
        /*
            The SDK provides a LoggingTransferListener implementation of the TransferListener interface.
            You can also implement the interface to provide your own logic.

            Configure log4J2 with settings such as the following.
                <Configuration status="WARN">
                    <Appenders>
                        <Console name="AlignedConsoleAppender" target="SYSTEM_OUT">
                            <PatternLayout pattern="%m%n"/>
                        </Console>
                    </Appenders>

                    <Loggers>
                        <logger name="software.amazon.awssdk.transfer.s3.progress.LoggingTransferListener" level="INFO" additivity="false">
                            <AppenderRef ref="AlignedConsoleAppender"/>
                        </logger>
                    </Loggers>
                </Configuration>

            Log4J2 logs the progress. The following is example output for a 21.3 MB file upload.
                Transfer initiated...
                |                    | 0.0%
                |====                | 21.1%
                |============        | 60.5%
                |====================| 100.0%
                Transfer complete!
        */
    }
```

### インポート
<a name="transfer-manager-upload-imports"></a>

```
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import software.amazon.awssdk.transfer.s3.S3TransferManager;
import software.amazon.awssdk.transfer.s3.model.CompletedFileUpload;
import software.amazon.awssdk.transfer.s3.model.FileUpload;
import software.amazon.awssdk.transfer.s3.model.UploadFileRequest;
import software.amazon.awssdk.transfer.s3.progress.LoggingTransferListener;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.Paths;
import java.util.UUID;
```

## S3 バケットからのファイルのダウンロード
<a name="transfer-manager-download"></a>

次の例には、ダウンロードの例と、ダウンロードの進行状況をログ記録する [LoggingTransferListener](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/transfer/s3/progress/LoggingTransferListener.html) をオプションで使用する方法も示されています。

S3 Transfer Manager を使用して S3 バケットからオブジェクトをダウンロードするには、[DownloadFileRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/transfer/s3/model/DownloadFileRequest.html) オブジェクトを構築してそれを [downloadFile](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/transfer/s3/S3TransferManager.html#downloadFile(software.amazon.awssdk.transfer.s3.model.DownloadFileRequest)) メソッドに渡します。

`S3TransferManager` の `downloadFile` メソッドによって返される [FileDownload](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/transfer/s3/model/FileDownload.html) オブジェクトは、ファイル転送を表します。ダウンロードが完了すると、[CompletedFileDownload](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/transfer/s3/model/CompletedFileDownload.html) はダウンロードに関する情報へのアクセスを含めます。

```
    public void trackDownloadFile(S3TransferManager transferManager, String bucketName,
                             String key, String downloadedFileWithPath) {
        DownloadFileRequest downloadFileRequest = DownloadFileRequest.builder()
                .getObjectRequest(b -> b.bucket(bucketName).key(key))
                .addTransferListener(LoggingTransferListener.create())  // Add listener.
                .destination(Paths.get(downloadedFileWithPath))
                .build();

        FileDownload downloadFile = transferManager.downloadFile(downloadFileRequest);

        CompletedFileDownload downloadResult = downloadFile.completionFuture().join();
        /*
            The SDK provides a LoggingTransferListener implementation of the TransferListener interface.
            You can also implement the interface to provide your own logic.

            Configure log4J2 with settings such as the following.
                <Configuration status="WARN">
                    <Appenders>
                        <Console name="AlignedConsoleAppender" target="SYSTEM_OUT">
                            <PatternLayout pattern="%m%n"/>
                        </Console>
                    </Appenders>

                    <Loggers>
                        <logger name="software.amazon.awssdk.transfer.s3.progress.LoggingTransferListener" level="INFO" additivity="false">
                            <AppenderRef ref="AlignedConsoleAppender"/>
                        </logger>
                    </Loggers>
                </Configuration>

            Log4J2 logs the progress. The following is example output for a 21.3 MB file download.
                Transfer initiated...
                |=======             | 39.4%
                |===============     | 78.8%
                |====================| 100.0%
                Transfer complete!
        */
    }
```

### インポート
<a name="transfer-manager-download-import"></a>

```
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import software.amazon.awssdk.core.exception.SdkException;
import software.amazon.awssdk.core.sync.RequestBody;
import software.amazon.awssdk.transfer.s3.S3TransferManager;
import software.amazon.awssdk.transfer.s3.model.CompletedFileDownload;
import software.amazon.awssdk.transfer.s3.model.DownloadFileRequest;
import software.amazon.awssdk.transfer.s3.model.FileDownload;
import software.amazon.awssdk.transfer.s3.progress.LoggingTransferListener;

import java.io.IOException;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.NoSuchFileException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.UUID;
```

## Amazon S3 バケットを他のバケットにコピーする
<a name="transfer-manager-copy"></a>

次の例は、S3 Transfer Manager を使用してオブジェクトをコピーする方法を示しています。

S3 バケットから別のバケットへのオブジェクトのコピーを開始するには、基本 [CopyObjectRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/s3/model/CopyObjectRequest.html) インスタンスを作成します。

次に、その基本 `CopyObjectRequest` を S3 Transfer Manager が使用できる [CopyRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/transfer/s3/model/CopyRequest.html) にラップします。

`S3TransferManager` の `copy` メソッドによって返される `Copy` オブジェクトはコピープロセスを表します。コピープロセスが完了すると、[CompletedCopy](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/transfer/s3/model/CompletedCopy.html) オブジェクトはレスポンスに関する詳細を含めます。

```
    public String copyObject(S3TransferManager transferManager, String bucketName,
            String key, String destinationBucket, String destinationKey) {
        CopyObjectRequest copyObjectRequest = CopyObjectRequest.builder()
                .sourceBucket(bucketName)
                .sourceKey(key)
                .destinationBucket(destinationBucket)
                .destinationKey(destinationKey)
                .build();

        CopyRequest copyRequest = CopyRequest.builder()
                .copyObjectRequest(copyObjectRequest)
                .build();

        Copy copy = transferManager.copy(copyRequest);

        CompletedCopy completedCopy = copy.completionFuture().join();
        return completedCopy.response().copyObjectResult().eTag();
    }
```

**注記**  
S3 Transfer Manager でクロスリージョンコピーを実行するには、次のスニペットに示すように、CRT AWS ベースの S3 クライアントビルダー`crossRegionAccessEnabled`で を有効にします。  

```
S3AsyncClient s3AsyncClient = S3AsyncClient.crtBuilder()
                .crossRegionAccessEnabled(true)
                .build();

S3TransferManager transferManager = S3TransferManager.builder()
                .s3Client(s3AsyncClient)
                .build();
```

### インポート
<a name="transfer-manager-copy-import"></a>

```
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import software.amazon.awssdk.core.sync.RequestBody;
import software.amazon.awssdk.services.s3.model.CopyObjectRequest;
import software.amazon.awssdk.transfer.s3.S3TransferManager;
import software.amazon.awssdk.transfer.s3.model.CompletedCopy;
import software.amazon.awssdk.transfer.s3.model.Copy;
import software.amazon.awssdk.transfer.s3.model.CopyRequest;

import java.util.UUID;
```

## ローカルディレクトリを S3 バケットにアップロードする
<a name="transfer-manager-upload_directory"></a>

次の例は、ローカルディレクトリを S3 にアップロードする方法を示しています。

まず、`S3TransferManager` インスタンスの [uploadDirectory](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/transfer/s3/S3TransferManager.html#uploadDirectory(software.amazon.awssdk.transfer.s3.model.UploadDirectoryRequest)) メソッドを呼び出し、[UploadDirectoryRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/transfer/s3/model/UploadDirectoryRequest.html) を渡します。

[DirectoryUpload](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/transfer/s3/model/DirectoryUpload.html) オブジェクトはアップロードプロセスを表し、リクエストが完了すると [CompletedDirectoryUpload](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/transfer/s3/model/CompletedDirectoryUpload.html) を生成します。`CompleteDirectoryUpload` オブジェクトは、どのファイルが転送に失敗したかなど、転送の結果に関する情報を含めます。

```
    public Integer uploadDirectory(S3TransferManager transferManager,
            URI sourceDirectory, String bucketName) {
        DirectoryUpload directoryUpload = transferManager.uploadDirectory(UploadDirectoryRequest.builder()
                .source(Paths.get(sourceDirectory))
                .bucket(bucketName)
                .build());

        CompletedDirectoryUpload completedDirectoryUpload = directoryUpload.completionFuture().join();
        completedDirectoryUpload.failedTransfers()
                .forEach(fail -> logger.warn("Object [{}] failed to transfer", fail.toString()));
        return completedDirectoryUpload.failedTransfers().size();
    }
```

### インポート
<a name="transfer-manager-upload_directory-import"></a>

```
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import software.amazon.awssdk.services.s3.model.ObjectIdentifier;
import software.amazon.awssdk.transfer.s3.S3TransferManager;
import software.amazon.awssdk.transfer.s3.model.CompletedDirectoryUpload;
import software.amazon.awssdk.transfer.s3.model.DirectoryUpload;
import software.amazon.awssdk.transfer.s3.model.UploadDirectoryRequest;

import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.Paths;
import java.util.UUID;
```

## ローカルディレクトリへの S3 バケットオブジェクトのダウンロード
<a name="transfer-manager-download_directory"></a>

次の例に示すように、S3 バケットのオブジェクトをローカルディレクトリにダウンロードできます。

S3 バケット内のオブジェクトをローカルディレクトリにダウンロードするには、まず Transfer Manager の [downloadDirectory](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/transfer/s3/S3TransferManager.html#downloadDirectory(software.amazon.awssdk.transfer.s3.model.DownloadDirectoryRequest)) メソッドを呼び出し、[DownloadDirectoryRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/transfer/s3/model/DownloadDirectoryRequest.html) を渡します。

[DirectoryDownload](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/transfer/s3/model/DirectoryDownload.html) オブジェクトはダウンロードプロセスを表し、リクエストが完了すると [CompletedDirectoryDownload](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/transfer/s3/model/CompletedDirectoryDownload.html) を生成します。`CompleteDirectoryDownload` オブジェクトは、どのファイルが転送に失敗したかなど、転送の結果に関する情報を含めます。

```
    public Integer downloadObjectsToDirectory(S3TransferManager transferManager,
            URI destinationPathURI, String bucketName) {
        DirectoryDownload directoryDownload = transferManager.downloadDirectory(DownloadDirectoryRequest.builder()
                .destination(Paths.get(destinationPathURI))
                .bucket(bucketName)
                .build());
        CompletedDirectoryDownload completedDirectoryDownload = directoryDownload.completionFuture().join();

        completedDirectoryDownload.failedTransfers()
                .forEach(fail -> logger.warn("Object [{}] failed to transfer", fail.toString()));
        return completedDirectoryDownload.failedTransfers().size();
    }
```

### インポート
<a name="transfer-manager-download_directory-import"></a>

```
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import software.amazon.awssdk.core.sync.RequestBody;
import software.amazon.awssdk.services.s3.model.ObjectIdentifier;
import software.amazon.awssdk.transfer.s3.S3TransferManager;
import software.amazon.awssdk.transfer.s3.model.CompletedDirectoryDownload;
import software.amazon.awssdk.transfer.s3.model.DirectoryDownload;
import software.amazon.awssdk.transfer.s3.model.DownloadDirectoryRequest;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;
```

## 完全な例を見る
<a name="transfer-manager-example-location"></a>

GitHub には、このページのすべての例の[完全なコードが含まれています](https://github.com/awsdocs/aws-doc-sdk-examples/tree/d73001daea05266eaa9e074ccb71b9383832369a/javav2/example_code/s3/src/main/java/com/example/s3/transfermanager)。

# S3 イベント通知の使用
<a name="examples-s3-event-notifications"></a>

バケット内のアクティビティのモニタリングに向けて、Amazon S3 は特定のイベントが発生したときに通知を送信できます。Amazon S3 ユーザーガイドには、[バケットが送信できる通知](https://docs.aws.amazon.com/AmazonS3/latest/userguide/EventNotifications.html#notification-how-to-overview)に関する情報が記載されています。

SDK for Java を使用して、4 つの送信先にイベントを送信するようにバケットを設定できます。
+ Amazon Simple Notification Service トピック
+ Amazon Simple Queue Service キュー
+ AWS Lambda 関数
+ Amazon EventBridge

EventBridge にイベントを送信するようにバケットを設定すると、同じイベントを複数の送信先にファンアウトするように EventBridge ルールを設定できます。最初の 3 つの送信先のいずれかに直接送信するようにバケットを設定する場合、イベントごとに指定できる送信先タイプは 1 つだけです。

次のセクションでは、SDK for Java を使用してバケットを設定し、Amazon SQS キューと EventBridge の 2 つの送信先に S3 イベント通知を送信する方法について説明します。

最後のセクションでは、S3 イベント通知 API を使用して、オブジェクト指向の方法で通知を使用する方法を示します。

## 送信先に直接送信するようにバケットを設定する
<a name="s3-event-conf-bucket-direct"></a>

次の例では、*オブジェクトの作成*イベントまたは*オブジェクトのタグ付け*イベントがバケットに対して発生したときに通知を送信するようにバケットを設定します。

```
static void processS3Events(String bucketName, String queueArn) {
    // Configure the bucket to send Object Created and Object Tagging notifications to an existing SQS queue.
    s3Client.putBucketNotificationConfiguration(b -> b
            .notificationConfiguration(ncb -> ncb
                    .queueConfigurations(qcb -> qcb
                            .events(Event.S3_OBJECT_CREATED, Event.S3_OBJECT_TAGGING)
                            .queueArn(queueArn)))
                    .bucket(bucketName)
    );
}
```

上記のコードは、2 種類のイベントを受信するように 1 つのキューを設定します。`queueConfigurations` メソッドを使用すると、必要に応じて複数のキューの送信先を設定できるため、便利です。また、 `notificationConfiguration` メソッドでは、1 つ以上の Amazon SNS トピックや 1 つ以上の Lambda 関数など、追加の送信先を設定できます。次のスニペットは、2 つのキューと 3 種類の送信先を含む例を示しています。

```
s3Client.putBucketNotificationConfiguration(b -> b
                .notificationConfiguration(ncb -> ncb
                        .queueConfigurations(qcb -> qcb
                                .events(Event.S3_OBJECT_CREATED, Event.S3_OBJECT_TAGGING)
                                .queueArn(queueArn), 
                                qcb2 -> qcb2.<...>)
                        .topicConfigurations(tcb -> tcb.<...>)
                        .lambdaFunctionConfigurations(lfcb -> lfcb.<...>))
                        .bucket(bucketName)
        );
```

「Code Examples」の GitHub リポジトリには、S3 イベント通知をキューに直接送信するための[完全な例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/main/javav2/example_code/s3/src/main/java/com/example/s3/ProcessS3EventNotification.java)が記載されています。

## EventBridge に送信するようにバケットを設定する
<a name="s3-event-conf-bucket-eventbridge"></a>

次の例では、EventBridge に通知を送信するようにバケットを設定します。

```
public static String setBucketNotificationToEventBridge(String bucketName) {
    // Enable bucket to emit S3 Event notifications to EventBridge.
    s3Client.putBucketNotificationConfiguration(b -> b
            .bucket(bucketName)
            .notificationConfiguration(b1 -> b1
                    .eventBridgeConfiguration(SdkBuilder::build))
    .build());
```

EventBridge にイベントを送信するようにバケットを設定するときは、EventBridge の送信先を指定するだけです。イベントのタイプや EventBridge がディスパッチする最終的な送信先を指定する必要はありません。Java SDK の EventBridge クライアントを使用して、最終的なターゲットとイベントタイプを設定します。

次のコードは、*オブジェクトの作成*イベントをトピックとキューにファンアウトするように EventBridge を設定する方法を示しています。

```
   public static String configureEventBridge(String topicArn, String queueArn) {
        try {
            // Create an EventBridge rule to route Object Created notifications.
            PutRuleRequest putRuleRequest = PutRuleRequest.builder()
                    .name(RULE_NAME)
                    .eventPattern("""
                            {
                              "source": ["aws.s3"],
                              "detail-type": ["Object Created"],
                              "detail": {
                                "bucket": {
                                  "name": ["%s"]
                                }
                              }
                            }
                            """.formatted(bucketName))
                    .build();

            // Add the rule to the default event bus.
            PutRuleResponse putRuleResponse = eventBridgeClient.putRule(putRuleRequest)
                    .whenComplete((r, t) -> {
                        if (t != null) {
                            logger.error("Error creating event bus rule: " + t.getMessage(), t);
                            throw new RuntimeException(t.getCause().getMessage(), t);
                        }
                        logger.info("Event bus rule creation request sent successfully. ARN is: {}", r.ruleArn());
                    }).join();

            // Add the existing SNS topic and SQS queue as targets to the rule.
            eventBridgeClient.putTargets(b -> b
                    .eventBusName("default")
                    .rule(RULE_NAME)
                    .targets(List.of (
                            Target.builder()
                                    .arn(queueArn)
                                    .id("Queue")
                                    .build(),
                            Target.builder()
                                    .arn(topicArn)
                                    .id("Topic")
                                    .build())
                            )
                    ).join();
            return putRuleResponse.ruleArn();
        } catch (S3Exception e) {
            System.err.println(e.awsErrorDetails().errorMessage());
            System.exit(1);
        }
        return null;
    }
```

Java コードで EventBridge を使用するには、Maven `pom.xml` ファイルに `eventbridge` アーティファクトの依存関係を追加します。

```
<dependency>
    <groupId>software.amazon.awssdk</groupId>
    <artifactId>eventbridge</artifactId>
</dependency>
```

「Code Examples」の GitHub リポジトリには、S3 イベント通知を EventBridge に送信し、その後トピックとキューに送信するための[完全な例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/main/javav2/example_code/s3/src/main/java/com/example/s3/PutBucketS3EventNotificationEventBridge.java)が記載されています。

## S3 イベント通知 API を使用してイベントを処理する
<a name="s3-event-notification-read"></a>

送信先が S3 通知イベントを受信したら、S3 イベント通知 API を使用して、オブジェクト指向の方法でイベントを処理できます。S3 イベント通知 API を使用して、ターゲットに直接ディスパッチされるイベント通知 ([最初の例](#s3-event-conf-bucket-direct)を参照) を使用できますが、EventBridge 経由でルーティングされる通知は使用できません。バケットから EventBridge に送信される S3 イベント通知には、S3 イベント通知 API が現在対応していない[別の構造](https://docs.aws.amazon.com/AmazonS3/latest/userguide/ev-events.html#ev-events-list)が含まれています。

### 依存関係を追加する
<a name="s3-event-notifications-dep"></a>

S3 イベント通知 API は、SDK for Java 2.x のバージョン 2.25.11 でリリースされました。

S3 イベント通知 API を使用するには、次のスニペットに示すように、必要な依存関係要素を Maven `pom.xml` に追加します。

```
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>software.amazon.awssdk</groupId>
            <artifactId>bom</artifactId>
            <version>2.X.X1</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>
<dependencies>
    <dependency>
        <groupId>software.amazon.awssdk</groupId>
        <artifactId>s3-event-notifications</artifactId>
    </dependency>
</dependencies>
```

1 [最新バージョン](https://central.sonatype.com/artifact/software.amazon.awssdk/bom)。

### `S3EventNotification` クラスを使用する
<a name="s3-event-notifications-use"></a>

#### JSON 文字列から `S3EventNotification` インスタンスを作成する
<a name="s3-event-notifications-use-from-json"></a>

JSON 文字列を `S3EventNotification` オブジェクトに変換するには、次の例に示すように、 `S3EventNotification` クラスの静的メソッドを使用します。

```
import software.amazon.awssdk.eventnotifications.s3.model.S3EventNotification
import software.amazon.awssdk.eventnotifications.s3.model.S3EventNotificationRecord
import software.amazon.awssdk.services.sqs.model.Message; 

public class S3EventNotificationExample {
    ...
    
    void receiveMessage(Message message) {
       // Message received from SQSClient.
       String sqsEventBody = message.body();
       S3EventNotification s3EventNotification = S3EventNotification.fromJson(sqsEventBody);
    
       // Use getRecords() to access all the records in the notification.                                                                                                       
       List<S3EventNotificationRecord> records = s3EventNotification.getRecords();   
    
        S3EventNotificationRecord record = records.stream().findFirst();
        // Use getters on the record to access individual attributes.
        String awsRegion = record.getAwsRegion();
        String eventName = record.getEventName();
        String eventSource = record.getEventSource();                                                                                                   
    }
}
```

この例では、 `fromJson` メソッドは JSON 文字列を `S3EventNotification` オブジェクトに変換します。JSON 文字列にフィールドが欠けている場合、対応する Java オブジェクトのフィールドの値は `null` になり、JSON に余分なフィールドが含まれていても無視されます。

イベント通知レコードの他の API は、`[S3EventNotificationRecord](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/eventnotifications/s3/model/S3EventNotificationRecord.html)` の API リファレンスに記載されています。

#### `S3EventNotification` インスタンスを JSON 文字列に変換する
<a name="s3-event-notifications-use-to-json"></a>

次の例に示すように、 `toJson` (または `toJsonPretty`) メソッドを使用して、`S3EventNotification` オブジェクトを JSON 文字列に変換します。

```
import software.amazon.awssdk.eventnotifications.s3.model.S3EventNotification

public class S3EventNotificationExample {
    ...

    void toJsonString(S3EventNotification event) {

        String json = event.toJson();
        String jsonPretty = event.toJsonPretty();

        System.out.println("JSON: " + json);
        System.out.println("Pretty JSON: " + jsonPretty);
    }
}
```

`GlacierEventData`、`ReplicationEventData`、`IntelligentTieringEventData`、および `LifecycleEventData` のフィールドは、`null` の場合は JSON から除外されます。他の `null` フィールドは `null` としてシリアル化されます。

S3 オブジェクトタグ付けイベントの `toJsonPretty` メソッドの出力例を次に示します。

```
{
  "Records" : [ {
    "eventVersion" : "2.3",
    "eventSource" : "aws:s3",
    "awsRegion" : "us-east-1",
    "eventTime" : "2024-07-19T20:09:18.551Z",
    "eventName" : "ObjectTagging:Put",
    "userIdentity" : {
      "principalId" : "AWS:XXXXXXXXXXX"
    },
    "requestParameters" : {
      "sourceIPAddress" : "XXX.XX.XX.XX"
    },
    "responseElements" : {
      "x-amz-request-id" : "XXXXXXXXXXXX",
      "x-amz-id-2" : "XXXXXXXXXXXXX"
    },
    "s3" : {
      "s3SchemaVersion" : "1.0",
      "configurationId" : "XXXXXXXXXXXXX",
      "bucket" : {
        "name" : "amzn-s3-demo-bucket",
        "ownerIdentity" : {
          "principalId" : "XXXXXXXXXXX"
        },
        "arn" : "arn:aws:s3:::XXXXXXXXXX"
      },
      "object" : {
        "key" : "akey",
        "size" : null,
        "eTag" : "XXXXXXXXXX",
        "versionId" : null,
        "sequencer" : null
      }
    }
  } ]
}
```

GitHub には、API を使用して Amazon SQS キューによって受信された通知を使用する方法を示す[完全な例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/75c3daadf750406156fc87fa30ee499a206b4a36/javav2/example_code/s3/src/main/java/com/example/s3/ProcessS3EventNotification.java#L117)があります。

## Java ライブラリを使用して Lambda で S3 イベントを処理する: AWS SDK for Java 2.x および `aws-lambda-java-events`
<a name="s3-event-notif-processing-options"></a>

SDK for Java 2.x を使用して Lambda 関数で Amazon S3 イベント通知を処理する代わりに、バージョン 3.x.x. AWS `[aws-lambda-java-events](https://github.com/aws/aws-lambda-java-libs/tree/main/aws-lambda-java-events)`の`aws-lambda-java-events`ライブラリを個別に維持し、独自の依存要件があります。`aws-lambda-java-events` ライブラリは Lambda 関数の S3 イベントでのみ動作しますが、SDK for Java 2.x は Lambda 関数、Amazon SNS、Amazon SQS の S3 イベントで動作します。

どちらのアプローチも、オブジェクト指向の方法で JSON のイベント通知ペイロードをモデル化し、類似した API を提供します。次の表は、2 つのアプローチの使用における顕著な違いを示しています。


****  

|  | AWS SDK for Java | aws-lambda-java-events ライブラリ | 
| --- | --- | --- | 
| パッケージの命名 |  `software.amazon.awssdk.eventnotifications.s3.model.S3EventNotification`  | com.amazonaws.services.lambda.runtime.events.models.s3.S3EventNotification | 
| RequestHandler パラメータ |  Lambda 関数の `RequestHandler` 実装を記述して JSON 文字列を受け取ります。 <pre>import com.amazonaws.services.lambda.runtime.Context;<br />import com.amazonaws.services.lambda.runtime.RequestHandler;<br />import software.amazon.awssdk.eventnotifications.s3.model.S3EventNotification;<br /><br />public class Handler implements RequestHandler<String, String> {<br /><br />    @Override<br />        public String handleRequest(String jsonS3Event, Context context) {<br />            S3EventNotification s3Event = S3EventNotification<br />                                             .fromJson(jsonS3Event);<br />            // Work with the s3Event object.        <br />            ...<br />    }<br />}</pre>  | Lambda 関数の RequestHandler 実装を記述して S3Event オブジェクトを受け取ります。<pre>import com.amazonaws.services.lambda.runtime.Context;<br />import com.amazonaws.services.lambda.runtime.RequestHandler;<br />import com.amazonaws.services.lambda.runtime.events.S3Event;<br /><br />public class Handler implements RequestHandler<S3Event, String> {<br /><br />    @Override<br />        public String handleRequest(S3Event s3event, Context context) {<br />            // Work with the s3Event object.        <br />            ...<br />    }<br />}</pre> | 
| Maven の依存関係 |  <pre><dependencyManagement><br />    <dependencies><br />        <dependency><br />            <groupId>software.amazon.awssdk</groupId><br />            <artifactId>bom</artifactId><br />            <version>2.X.X</version><br />            <type>pom</type><br />            <scope>import</scope><br />        </dependency><br />    </dependencies><br /></dependencyManagement><br /><dependencies><br />    <dependency><br />        <groupId>software.amazon.awssdk</groupId><br />        <artifactId>s3-event-notifications</artifactId><br />    </dependency><br />    <!-- Add other SDK dependencies that you need. --><br /></dependencies></pre>  |  <pre><dependencyManagement><br />    <dependencies><br />        <dependency><br />            <groupId>software.amazon.awssdk</groupId><br />            <artifactId>bom</artifactId><br />            <version>2.X.X</version><br />            <type>pom</type><br />            <scope>import</scope><br />        </dependency><br />    </dependencies><br /></dependencyManagement><br /><dependencies><br />    <!-- The following two dependencies are for the <br />         aws-lambda-java-events library. --><br />    <dependency><br />        <groupId>com.amazonaws</groupId><br />        <artifactId>aws-lambda-java-core</artifactId><br />        <version>1.2.3</version>     <br />    </dependency><br />    <dependency><br />        <groupId>com.amazonaws</groupId><br />        <artifactId>aws-lambda-java-events</artifactId><br />        <version>3.15.0</version><br />    </dependency><br />    <!-- Add other SDK dependencies that you need. --><br /></dependencies></pre>  | 

# Amazon Simple Notification Service を使用する
<a name="examples-simple-notification-service"></a>

Amazon Simple Notification Service では、アプリケーションからのリアルタイムの通知メッセージを複数の通信チャネル経由でサブスクライバーに簡単にプッシュできます。このトピックでは、Amazon SNS の基本機能の一部を実行する方法について説明します。

## トピックの作成
<a name="sns-create-topic"></a>

**トピック**は、メッセージの送信先システムを定義する通信チャネルの論理的なグループです。たとえば、AWS Lambda や HTTP ウェブフックへのメッセージのファンアウトなどです。Amazon SNS にメッセージを送信すると、トピックで定義されているチャネルに配信されます。これにより、サブスクライバーがメッセージを使用できるようになります。

トピックを作成するには、最初に、ビルダーの `name()` メソッドを使用して設定されたトピックの名前で [CreateTopicRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/sns/model/CreateTopicRequest.html) オブジェクトを構築します。その後、[SnsClient](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/sns/SnsClient.html) の `createTopic()` メソッドを使用して、リクエストオブジェクトを Amazon SNS に送信します。次のコードスニペットに示すように、このリクエストの結果を [CreateTopicResponse](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/sns/model/CreateTopicResponse.html) オブジェクトとしてキャプチャできます。

 **インポート** 

```
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.sns.SnsClient;
import software.amazon.awssdk.services.sns.model.CreateTopicRequest;
import software.amazon.awssdk.services.sns.model.CreateTopicResponse;
import software.amazon.awssdk.services.sns.model.SnsException;
```

 **Code** 

```
    public static String createSNSTopic(SnsClient snsClient, String topicName ) {

        CreateTopicResponse result = null;
        try {
            CreateTopicRequest request = CreateTopicRequest.builder()
                    .name(topicName)
                    .build();

            result = snsClient.createTopic(request);
            return result.topicArn();
        } catch (SnsException e) {

            System.err.println(e.awsErrorDetails().errorMessage());
            System.exit(1);
        }
        return "";
    }
```

[GitHub](https://github.com/awsdocs/aws-doc-sdk-examples/blob/da520cb4436f8567a90b6f73f77232fd590a50bf/javav2/example_code/sns/src/main/java/com/example/sns/CreateTopic.java) で完全な例をご覧ください。

## Amazon SNS トピックをリストする
<a name="sns-crelistate-topics"></a>

既存の Amazon SNS トピックのリストを取得するには、[ListTopicsRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/sns/model/ListTopicsRequest.html) オブジェクトを構築します。次に、Amazon SNS の `listTopics()` メソッドを使用して、リクエストオブジェクトを `SnsClient` に送信します。このリクエストの結果は、[ListTopicsResponse](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/sns/model/ListTopicsResponse.html) オブジェクトとしてキャプチャできます。

次のコードスニペットは、リクエストの HTTP ステータスコードと、Amazon SNS トピックの Amazon リソースネーム (ARN) のリストを出力します。

 **インポート** 

```
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.sns.SnsClient;
import software.amazon.awssdk.services.sns.model.ListTopicsRequest;
import software.amazon.awssdk.services.sns.model.ListTopicsResponse;
import software.amazon.awssdk.services.sns.model.SnsException;
```

 **Code** 

```
    public static void listSNSTopics(SnsClient snsClient) {

        try {
            ListTopicsRequest request = ListTopicsRequest.builder()
                   .build();

            ListTopicsResponse result = snsClient.listTopics(request);
            System.out.println("Status was " + result.sdkHttpResponse().statusCode() + "\n\nTopics\n\n" + result.topics());

        } catch (SnsException e) {
            System.err.println(e.awsErrorDetails().errorMessage());
            System.exit(1);
        }
    }
```

[GitHub](https://github.com/awsdocs/aws-doc-sdk-examples/blob/da520cb4436f8567a90b6f73f77232fd590a50bf/javav2/example_code/sns/src/main/java/com/example/sns/ListTopics.java) で完全な例をご覧ください。

## トピックへのエンドポイントのサブスクライブ
<a name="sns-subscribe-endpoint-topic"></a>

トピックを作成したら、そのトピックのエンドポイントとなる通信チャネルを設定できます。メッセージは、Amazon SNS による受信後にこれらのエンドポイントに配信されます。

通信チャネルをトピックのエンドポイントとして設定するには、そのエンドポイントをトピックにサブスクライブします。開始するには、[SubscribeRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/sns/model/SubscribeRequest.html) オブジェクトを構築します。通信チャネル (`lambda` や `email` など) を `protocol()` として指定します。`endpoint()` を関連する出力場所 (Lambda 関数の ARN や E メールアドレスなど) に設定し、サブスクライブするトピックの ARN を `topicArn()` として設定します。`SnsClient` の `subscribe()` メソッドを使用して、リクエストオブジェクトを Amazon SNS に送信します。このリクエストの結果は、[SubscribeResponse](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/sns/model/SubscribeResponse.html) オブジェクトとしてキャプチャできます。

次のコードスニペットは、トピックに E メールアドレスをサブスクライブする方法を示しています。

 **インポート** 

```
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.sns.SnsClient;
import software.amazon.awssdk.services.sns.model.SnsException;
import software.amazon.awssdk.services.sns.model.SubscribeRequest;
import software.amazon.awssdk.services.sns.model.SubscribeResponse;
```

 **Code** 

```
    public static void subEmail(SnsClient snsClient, String topicArn, String email) {

        try {
            SubscribeRequest request = SubscribeRequest.builder()
                .protocol("email")
                .endpoint(email)
                .returnSubscriptionArn(true)
                .topicArn(topicArn)
                .build();

            SubscribeResponse result = snsClient.subscribe(request);
            System.out.println("Subscription ARN: " + result.subscriptionArn() + "\n\n Status is " + result.sdkHttpResponse().statusCode());

        } catch (SnsException e) {
            System.err.println(e.awsErrorDetails().errorMessage());
            System.exit(1);
        }
    }
```

[GitHub](https://github.com/awsdocs/aws-doc-sdk-examples/blob/da520cb4436f8567a90b6f73f77232fd590a50bf/javav2/example_code/sns/src/main/java/com/example/sns/SubscribeEmail.java) で完全な例をご覧ください。

## トピックへのメッセージの発行
<a name="sns-publish-message-topic"></a>

トピックと 1 つ以上のエンドポイントを設定したら、そのトピックにメッセージを発行できます。開始するには、[PublishRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/sns/model/PublishRequest.html) オブジェクトを構築します。送信する `message()` と、送信先のトピック (`topicArn()`) の ARN を指定します。次に、Amazon SNS の `publish()` メソッドを使用して、リクエストオブジェクトを `SnsClient` に送信します。このリクエストの結果は、[PublishResponse](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/sns/model/PublishResponse.html) オブジェクトとして取得できます。

 **インポート** 

```
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.sns.SnsClient;
import software.amazon.awssdk.services.sns.model.PublishRequest;
import software.amazon.awssdk.services.sns.model.PublishResponse;
import software.amazon.awssdk.services.sns.model.SnsException;
```

 **Code** 

```
    public static void pubTopic(SnsClient snsClient, String message, String topicArn) {

        try {
            PublishRequest request = PublishRequest.builder()
                .message(message)
                .topicArn(topicArn)
                .build();

            PublishResponse result = snsClient.publish(request);
            System.out.println(result.messageId() + " Message sent. Status is " + result.sdkHttpResponse().statusCode());

         } catch (SnsException e) {
            System.err.println(e.awsErrorDetails().errorMessage());
            System.exit(1);
         }
    }
```

[GitHub](https://github.com/awsdocs/aws-doc-sdk-examples/blob/da520cb4436f8567a90b6f73f77232fd590a50bf/javav2/example_code/sns/src/main/java/com/example/sns/PublishTopic.java) で完全な例をご覧ください。

## トピックからのエンドポイントの登録解除
<a name="sns-unsubscribe-endpoint-topic"></a>

トピックのエンドポイントとして設定されている通信チャネルを削除できます。その後、トピック自体は引き続き存在し、そのトピックに設定されている他のエンドポイントにメッセージを配信します。

トピックのエンドポイントとしての通信チャネルを削除するには、そのエンドポイントをトピックから登録解除します。開始するには、[UnsubscribeRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/sns/model/UnsubscribeRequest.html) オブジェクトを構築し、登録解除するトピックの ARN を `subscriptionArn()` として設定します。次に、`unsubscribe()` の `SnsClient` メソッドを使用して、リクエストオブジェクトを SNS に送信します。このリクエストの結果は、[UnsubscribeResponse](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/sns/model/UnsubscribeResponse.html) オブジェクトとしてキャプチャできます。

 **インポート** 

```
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.sns.SnsClient;
import software.amazon.awssdk.services.sns.model.SnsException;
import software.amazon.awssdk.services.sns.model.UnsubscribeRequest;
import software.amazon.awssdk.services.sns.model.UnsubscribeResponse;
```

 **Code** 

```
    public static void unSub(SnsClient snsClient, String subscriptionArn) {

        try {
            UnsubscribeRequest request = UnsubscribeRequest.builder()
                .subscriptionArn(subscriptionArn)
                .build();

            UnsubscribeResponse result = snsClient.unsubscribe(request);

            System.out.println("\n\nStatus was " + result.sdkHttpResponse().statusCode()
                + "\n\nSubscription was removed for " + request.subscriptionArn());

        } catch (SnsException e) {
            System.err.println(e.awsErrorDetails().errorMessage());
            System.exit(1);
        }
    }
```

[GitHub](https://github.com/awsdocs/aws-doc-sdk-examples/blob/da520cb4436f8567a90b6f73f77232fd590a50bf/javav2/example_code/sns/src/main/java/com/example/sns/Unsubscribe.java) で完全な例をご覧ください。

## トピックの削除
<a name="sns-delete-topic"></a>

Amazon SNS トピックを削除するには、最初に、トピックの ARN をビルダーの `topicArn()` メソッドとして設定して [DeleteTopicRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/sns/model/DeleteTopicRequest.html) オブジェクトを構築します。次に、Amazon SNS の `deleteTopic()` メソッドを使用して、リクエストオブジェクトを `SnsClient` に送信します。次のコードスニペットに示すように、このリクエストの結果を [DeleteTopicResponse](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/sns/model/DeleteTopicResponse.html) オブジェクトとしてキャプチャできます。

 **インポート** 

```
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.sns.SnsClient;
import software.amazon.awssdk.services.sns.model.DeleteTopicRequest;
import software.amazon.awssdk.services.sns.model.DeleteTopicResponse;
import software.amazon.awssdk.services.sns.model.SnsException;
```

 **Code** 

```
    public static void deleteSNSTopic(SnsClient snsClient, String topicArn ) {

        try {
            DeleteTopicRequest request = DeleteTopicRequest.builder()
                .topicArn(topicArn)
                .build();

            DeleteTopicResponse result = snsClient.deleteTopic(request);
            System.out.println("\n\nStatus was " + result.sdkHttpResponse().statusCode());

        } catch (SnsException e) {
            System.err.println(e.awsErrorDetails().errorMessage());
            System.exit(1);
        }
    }
```

[GitHub](https://github.com/awsdocs/aws-doc-sdk-examples/blob/da520cb4436f8567a90b6f73f77232fd590a50bf/javav2/example_code/sns/src/main/java/com/example/sns/DeleteTopic.java) で完全な例をご覧ください。

詳細については、「[Amazon Simple Notification Service デベロッパーガイド](https://docs.aws.amazon.com/sns/latest/dg/)」を参照してください。

# Amazon Simple Queue Service を使用する
<a name="examples-sqs"></a>

このセクションでは、AWS SDK for Java 2.x を使用して [Amazon Simple Queue Service](https://docs.aws.amazon.com/sqs/) をプログラムする例を示します。

次の例には各手法を示すのに必要なコードのみが含まれます。[完全なサンプルコードは GitHub で入手できます](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/javav2)。そこから、単一のソースファイルをダウンロードするかリポジトリをローカルにクローン作成して、ビルドし実行するためのすべての例を取得できます。

**Topics**
+ [自動リクエストバッチ処理を使用する](sqs-auto-batch.md)
+ [キューオペレーション](examples-sqs-message-queues.md)
+ [メッセージオペレーション](examples-sqs-messages.md)

# で Amazon SQS の自動リクエストバッチ処理を使用する AWS SDK for Java 2.x
<a name="sqs-auto-batch"></a>

Amazon SQS の自動リクエストバッチ処理 API は、SQS オペレーションのリクエストをバッチ処理およびバッファリングする効率的な方法を提供する高レベルライブラリです。バッチ処理 API を使用すると、SQS へのリクエストの数を減らすことができるため、スループットが向上し、コストが最小限に抑えられます。

バッチ処理 API メソッドは、`[SqsAsyncClient](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/sqs/SqsAsyncClient.html)` メソッド (`sendMessage`、`changeMessageVisibility`、`deleteMessage`、`receiveMessage`) と一致するため、最小限の変更でドロップイン置換としてバッチ処理 API を使用できます。

このトピックでは、Amazon SQS の自動リクエストバッチ処理 API を設定して使用する方法の概要を説明します。

## 前提条件をチェックする
<a name="sqs-auto-batch-requirements"></a>

バッチ処理 API にアクセスするには、SDK for Java 2.x のバージョン *2.28.0* 以降を使用する必要があります。Maven `pom.xml` には、少なくとも次の要素が含まれている必要があります。

```
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>software.amazon.awssdk</groupId>
            <artifactId>bom</artifactId>
            <version>2.28.231</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>
<dependencies>
    <dependency>
        <groupId>software.amazon.awssdk</groupId>
        <artifactId>sqs</artifactId>
    </dependency>
</dependencies>
```

1 [最新バージョン](https://central.sonatype.com/artifact/software.amazon.awssdk/bom)

## バッチマネージャーを作成する
<a name="sqs-auto-batch-create"></a>

自動リクエストバッチ処理 API は、[SqsAsyncBatchManager](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/sqs/batchmanager/SqsAsyncBatchManager.html) インターフェイスによって実装されます。マネージャーのインスタンスは、いくつかの方法で作成できます。

### `SqsAsyncClient` を使用したデフォルト設定
<a name="sqs-batch-manager-create-default"></a>

バッチマネージャーを作成する最も簡単な方法は、既存の [SqsAsyncClient](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/sqs/SqsAsyncClient.html) インスタンスで `batchManager` ファクトリメソッドを呼び出すことです。次のスニペットは、シンプルなアプローチを示しています。

```
SqsAsyncClient asyncClient = SqsAsyncClient.create();
SqsAsyncBatchManager sqsAsyncBatchManager = asyncClient.batchManager();
```

この方法を使用する場合、`SqsAsyncBatchManager` インスタンスは [`SqsAsyncBatchManager` の設定を上書きする](#sqs-auto-batch-config-settings) セクションの表に示されているデフォルト値を使用します。さらに、`SqsAsyncBatchManager` インスタンスは、作成された `SqsAsyncClient` インスタンスの `ExecutorService` を使用します。

### `SqsAsyncBatchManager.Builder` を使用したカスタム設定
<a name="sqs-batch-manager-create-custom"></a>

より高度なユースケースでは、[https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/sqs/batchmanager/SqsAsyncBatchManager.Builder.html](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/sqs/batchmanager/SqsAsyncBatchManager.Builder.html) を使用してバッチマネージャーをカスタマイズできます。このアプローチを使用して `SqsAsyncBatchManager` インスタンスを作成すると、バッチ処理の動作をファインチューニングできます。次のスニペットは、ビルダーを使用してバッチ処理の動作をカスタマイズする方法の例を示しています。

```
SqsAsyncBatchManager batchManager = SqsAsyncBatchManager.builder()
    .client(SqsAsyncClient.create())
    .scheduledExecutor(Executors.newScheduledThreadPool(5))
    .overrideConfiguration(b -> b
        .receiveMessageMinWaitDuration(Duration.ofSeconds(10))
        .receiveMessageVisibilityTimeout(Duration.ofSeconds(1))
        .receiveMessageAttributeNames(Collections.singletonList("*"))
        .receiveMessageSystemAttributeNames(Collections.singletonList(MessageSystemAttributeName.ALL)))
    .build();
```

このアプローチを使用すると、 [`SqsAsyncBatchManager` の設定を上書きする](#sqs-auto-batch-config-settings) セクションの表に表示される `BatchOverrideConfiguration` オブジェクトの設定を調整できます。このアプローチを使用して、バッチマネージャーにカスタム [https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/concurrent/ScheduledExecutorService.html](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/concurrent/ScheduledExecutorService.html) を指定することもできます。

## メッセージを送信する
<a name="sqs-auto-batch-send"></a>

バッチマネージャーでメッセージを送信するには、 `[SqsAsyncBatchManager\$1sendMessage](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/sqs/batchmanager/SqsAsyncBatchManager.html#sendMessage(software.amazon.awssdk.services.sqs.model.SendMessageRequest))` メソッドを使用します。SDK はリクエストをバッファリングし、 `maxBatchSize` または `sendRequestFrequency` の値に達するとバッチとして送信します。

次の例では、`sendMessage` リクエストの直後に別のリクエストが発生しています。この場合、SDK は両方のメッセージを 1 つのバッチで送信します。

```
// Sending the first message
CompletableFuture<SendMessageResponse> futureOne = 
    sqsAsyncBatchManager.sendMessage(r -> r.messageBody("One").queueUrl("queue"));

// Sending the second message
CompletableFuture<SendMessageResponse> futureTwo = 
    sqsAsyncBatchManager.sendMessage(r -> r.messageBody("Two").queueUrl("queue"));

// Waiting for both futures to complete and retrieving the responses
SendMessageResponse messageOne = futureOne.join();
SendMessageResponse messageTwo = futureTwo.join();
```

## メッセージの可視性タイムアウトを変更する
<a name="sqs-auto-batch-change-vis"></a>

[https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/sqs/batchmanager/SqsAsyncBatchManager.html#changeMessageVisibility(java.util.function.Consumer)](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/sqs/batchmanager/SqsAsyncBatchManager.html#changeMessageVisibility(java.util.function.Consumer)) メソッドを使用して、メッセージの可視性タイムアウトをバッチで変更できます。SDK はリクエストをバッファリングし、 `maxBatchSize` または `sendRequestFrequency` の値に達するとバッチとして送信します。

次の例は、`changeMessageVisibility` メソッドを呼び出す方法を示しています。

```
CompletableFuture<ChangeMessageVisibilityResponse> futureOne =
    sqsAsyncBatchManager.changeMessageVisibility(r -> 
        r.receiptHandle("receiptHandle")
         .queueUrl("queue"));
ChangeMessageVisibilityResponse response = futureOne.join();
```

## メッセージの削除
<a name="sqs-auto-batch-delete"></a>

[https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/sqs/batchmanager/SqsAsyncBatchManager.html#deleteMessage(java.util.function.Consumer)](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/sqs/batchmanager/SqsAsyncBatchManager.html#deleteMessage(java.util.function.Consumer)) メソッドを使用して、メッセージをバッチで削除できます。SDK はリクエストをバッファリングし、 `maxBatchSize` または `sendRequestFrequency` の値に達するとバッチとして送信します。

次の例は、 `deleteMessage` メソッドを呼び出す方法を示しています。

```
CompletableFuture<DeleteMessageResponse> futureOne = 
    sqsAsyncBatchManager.deleteMessage(r -> 
        r.receiptHandle("receiptHandle")
         .queueUrl("queue"));
DeleteMessageResponse response = futureOne.join();
```

## メッセージを受信する
<a name="sqs-auto-batch-receive"></a>

### デフォルト設定を使用する
<a name="sqs-auto-batch-receive-default-settings"></a>

アプリケーションで `[SqsAsyncBatchManager\$1receiveMessage](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/sqs/batchmanager/SqsAsyncBatchManager.html#receiveMessage(java.util.function.Consumer))` メソッドをポーリングすると、バッチマネージャーは内部バッファからメッセージを取得し、SDK は自動的にバックグラウンドで更新します。

次の例は、`receiveMessage` メソッドを呼び出す方法を示しています。

```
CompletableFuture<ReceiveMessageResponse> responseFuture = 
    sqsAsyncBatchManager.receiveMessage(r -> r.queueUrl("queueUrl"));
```

### カスタム設定を使用する
<a name="sqs-auto-batch-receive-custom-settings"></a>

例えばカスタム待機時間を設定し、取得するメッセージの数を指定してリクエストをさらにカスタマイズする場合は、次の例に示すようにリクエストをカスタマイズできます。

```
CompletableFuture<ReceiveMessageResponse> response = 
    sqsAsyncBatchManager.receiveMessage(r -> 
        r.queueUrl("queueUrl")
         .waitTimeSeconds(5)
         .visibilityTimeout(20));
```

**注記**  
次のいずれかのパラメータを含む `[ReceiveMessageRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/sqs/model/ReceiveMessageRequest.html)`で `receiveMessage` を呼び出すと、SDK はバッチマネージャーをバイパスし、通常の非同期 `receiveMessage` リクエストを送信します。  
`messageAttributeNames`
`messageSystemAttributeNames`
`messageSystemAttributeNamesWithStrings`
`overrideConfiguration`

## `SqsAsyncBatchManager` の設定を上書きする
<a name="sqs-auto-batch-config-settings"></a>

`SqsAsyncBatchManager` インスタンスを作成するときに、次の設定を調整できます。[https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/sqs/batchmanager/BatchOverrideConfiguration.Builder.html](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/sqs/batchmanager/BatchOverrideConfiguration.Builder.html) では、以下の設定が可能です。


| 設定 | 説明 | デフォルトの値 | 
| --- | --- | --- | 
| maxBatchSize | SendMessageBatchRequest、ChangeMessageVisibilityBatchRequest、または DeleteMessageBatchRequest ごとのバッチあたりのリクエストの最大数。最大値は 10 です。 | 10 | 
| sendRequestFrequency |  すでに `maxBatchSize` に達していない場合の、バッチを送信するまでの時間。値を大きくするとリクエストは減少しますが、レイテンシーは増加する可能性があります。  | 200 ms | 
| receiveMessageVisibilityTimeout | メッセージの可視性タイムアウト。設定しない場合、キューのデフォルトが使用されます。 | キューのデフォルト | 
| receiveMessageMinWaitDuration | receiveMessage リクエストの最小待機時間。CPU の無駄を防ぐため、0 には設定しないでください。 | 50 ms | 
| receiveMessageSystemAttributeNames | receiveMessage 呼び出しをリクエストする[システム属性名](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/sqs/model/MessageSystemAttributeName.html)のリスト。 | なし | 
| receiveMessageAttributeNames | receiveMessage 呼び出しをリクエストする[属性名](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-message-metadata.html#sqs-message-attributes)のリスト。 | なし | 

# Amazon Simple Queue Service メッセージキューの操作
<a name="examples-sqs-message-queues"></a>

*メッセージキュー*は、メッセージを確実に送信するために使用される論理コンテナです Amazon Simple Queue Service。キューには、*標準*と*先入れ先出し* (FIFO) の 2 種類があります。キューおよびキュータイプ間の相違点の詳細については、「[Amazon Simple Queue Service デベロッパーガイド](https://docs.aws.amazon.com//AWSSimpleQueueService/latest/SQSDeveloperGuide/welcome.html)」を参照してください。

このトピックでは、 を使用して Amazon Simple Queue Service キューの URL を作成、一覧表示、削除、取得する方法について説明します AWS SDK for Java。

次の例で使用されている `sqsClient` 変数は、次のスニペットから作成できます。

```
SqsClient sqsClient = SqsClient.create();
```

静的 `create()` メソッドを使用して `SqsClient` を作成すると、SDK は[デフォルトのリージョンプロバイダーチェーン](region-selection.md#default-region-provider-chain)によってリージョンを設定し、[デフォルトの認証情報プロバイダーチェーン](credentials-chain.md)によって認証情報を設定します。

## キューを作成する
<a name="sqs-create-queue"></a>

次のコードスニペットに示すように、`SqsClient’s` `createQueue` メソッドを使用し、キューパラメータを記述する `[CreateQueueRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/sqs/model/CreateQueueRequest.html)` オブジェクトを指定します。

 **インポート** 

```
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.sqs.SqsClient;
import software.amazon.awssdk.services.sqs.model.*;
import java.util.List;
```

 **コード** 

```
            CreateQueueRequest createQueueRequest = CreateQueueRequest.builder()
                .queueName(queueName)
                .build();

            sqsClient.createQueue(createQueueRequest);
```

GitHub の「[完全なサンプル](https://github.com/awsdocs/aws-doc-sdk-examples/blob/cf25559da654a7b74bec039c0ab9397dc5951dd4/javav2/example_code/sqs/src/main/java/com/example/sqs/SQSExample.java#L52)」をご覧ください。

## キューの一覧表示
<a name="sqs-list-queues"></a>

アカウントの Amazon Simple Queue Service キューを一覧表示するには、 `[ListQueuesRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/sqs/model/ListQueuesRequest.html)` オブジェクトを使用して `SqsClient’s``listQueues`メソッドを呼び出します。

パラメータを使用しない [https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/sqs/SqsClient.html#listQueues()](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/sqs/SqsClient.html#listQueues()) メソッドの形式を使用すると、サービスは最大 1,000 個のキューを含む*すべてのキュー*を返します。

以下のコードに示すように、`[ListQueuesRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/sqs/model/ListQueuesRequest.html)` オブジェクトにキュー名のプレフィックスを指定して、そのプレフィックスに一致するキューの結果を絞り込むことができます。

 **インポート** 

```
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.sqs.SqsClient;
import software.amazon.awssdk.services.sqs.model.*;
import java.util.List;
```

 **コード** 

```
        String prefix = "que";

        try {
            ListQueuesRequest listQueuesRequest = ListQueuesRequest.builder().queueNamePrefix(prefix).build();
            ListQueuesResponse listQueuesResponse = sqsClient.listQueues(listQueuesRequest);

            for (String url : listQueuesResponse.queueUrls()) {
                System.out.println(url);
            }

        } catch (SqsException e) {
            System.err.println(e.awsErrorDetails().errorMessage());
            System.exit(1);
        }
```

GitHub の「[完全なサンプル](https://github.com/awsdocs/aws-doc-sdk-examples/blob/cf25559da654a7b74bec039c0ab9397dc5951dd4/javav2/example_code/sqs/src/main/java/com/example/sqs/SQSExample.java#L79)」をご覧ください。

## キューの URL の取得
<a name="sqs-get-queue-url"></a>

次のコードは、 `[GetQueueUrlRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/sqs/model/GetQueueUrlRequest.html)` オブジェクトを指定して `SqsClient’s` `getQueueUrl` メソッドを呼び出してキューの URL を取得する方法を示しています。

 **インポート** 

```
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.sqs.SqsClient;
import software.amazon.awssdk.services.sqs.model.*;
import java.util.List;
```

 **コード** 

```
            GetQueueUrlResponse getQueueUrlResponse =
                sqsClient.getQueueUrl(GetQueueUrlRequest.builder().queueName(queueName).build());
            String queueUrl = getQueueUrlResponse.queueUrl();
            return queueUrl;
```

GitHub の「[完全なサンプル](https://github.com/awsdocs/aws-doc-sdk-examples/blob/7486a1a092aa8e16a21698ef26f9d524fef62e55/javav2/example_code/sqs/src/main/java/com/example/sqs/SQSExample.java#L70)」をご覧ください。

## キューの削除
<a name="sqs-delete-queue"></a>

`[DeleteQueueRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/sqs/model/DeleteQueueRequest.html)` オブジェクトへのキューの [URL](#sqs-get-queue-url) を指定します。次に、次のコードに示すように、 `SqsClient’s` `deleteQueue` メソッドを呼び出してキューを削除します。

 **インポート** 

```
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.sqs.SqsClient;
import software.amazon.awssdk.services.sqs.model.*;
import java.util.List;
```

 **コード** 

```
    public static void deleteSQSQueue(SqsClient sqsClient, String queueName) {

        try {

            GetQueueUrlRequest getQueueRequest = GetQueueUrlRequest.builder()
                    .queueName(queueName)
                    .build();

            String queueUrl = sqsClient.getQueueUrl(getQueueRequest).queueUrl();

            DeleteQueueRequest deleteQueueRequest = DeleteQueueRequest.builder()
                    .queueUrl(queueUrl)
                    .build();

            sqsClient.deleteQueue(deleteQueueRequest);

        } catch (SqsException e) {
            System.err.println(e.awsErrorDetails().errorMessage());
            System.exit(1);
        }
    }
```

GitHub の「[完全なサンプル](https://github.com/awsdocs/aws-doc-sdk-examples/blob/6240df86c5f17eae1e23d1139d1435c7dc4b2a11/javav2/example_code/sqs/src/main/java/com/example/sqs/DeleteQueue.java#L48)」をご覧ください。

## 詳細情報
<a name="more-information"></a>
+  Amazon Simple Queue Service API リファレンスの [CreateQueue](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_CreateQueue.html) 
+  Amazon Simple Queue Service API リファレンスの [GetQueueUrl](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_GetQueueUrl.html) 
+  Amazon Simple Queue Service API リファレンスの [ListQueues](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_ListQueues.html) 
+  Amazon Simple Queue Service API リファレンスの [DeleteQueue](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_DeleteQueue.html) 

# Amazon Simple Queue Service メッセージの送信、受信、削除
<a name="examples-sqs-messages"></a>

メッセージは、分散コンポーネントによって送受信できるデータの一部です。メッセージは、常に [SQS キュー](examples-sqs-message-queues.md)を使用して提供されます。

次の例で使用されている `sqsClient` 変数は、次のスニペットから作成できます。

```
SqsClient sqsClient = SqsClient.create();
```

静的 `create()` メソッドを使用して `SqsClient` を作成すると、SDK は[デフォルトのリージョンプロバイダーチェーン](region-selection.md#default-region-provider-chain)によってリージョンを設定し、[デフォルトの認証情報プロバイダーチェーン](credentials-chain.md)によって認証情報を設定します。

## メッセージの送信
<a name="sqs-message-send"></a>

SqsClient クライアント`sendMessage`メソッドを呼び出して、 Amazon Simple Queue Service キューに 1 つのメッセージを追加します。キューの [URL](examples-sqs-message-queues.md#sqs-get-queue-url)、メッセージ本文、およびオプションの遅延値 (秒単位) が含まれる [SendMessageRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/sqs/model/SendMessageRequest.html) オブジェクトを指定します。

 **インポート** 

```
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.sqs.SqsClient;
import software.amazon.awssdk.services.sqs.model.*;
import java.util.List;
```

 **コード** 

```
            sqsClient.sendMessage(SendMessageRequest.builder()
                .queueUrl(queueUrl)
                .messageBody("Hello world!")
                .delaySeconds(10)
                .build());

            sqsClient.sendMessage(sendMsgRequest);
```

## リクエストで複数のメッセージを送信する
<a name="sqs-messages-send-multiple"></a>

SqsClient の `sendMessageBatch` メソッドを使用して 1 つのリクエストで複数のメッセージを送信します。このメソッドは、キューの URL と送信するメッセージのリストを含む [SendMessageBatchRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/sqs/model/SendMessageBatchRequest.html) を受け取ります (各メッセージは [SendMessageBatchRequestEntry](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/sqs/model/SendMessageBatchRequestEntry.html))。また、メッセージの遅延値を設定して、特定のメッセージの送信を遅延させることもできます。

 **インポート** 

```
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.sqs.SqsClient;
import software.amazon.awssdk.services.sqs.model.*;
import java.util.List;
```

 **コード** 

```
            SendMessageBatchRequest sendMessageBatchRequest = SendMessageBatchRequest.builder()
                .queueUrl(queueUrl)
                .entries(SendMessageBatchRequestEntry.builder().id("id1").messageBody("Hello from msg 1").build(),
                        SendMessageBatchRequestEntry.builder().id("id2").messageBody("msg 2").delaySeconds(10).build())
                .build();
            sqsClient.sendMessageBatch(sendMessageBatchRequest);
```

GitHub の「[完全なサンプル](https://github.com/awsdocs/aws-doc-sdk-examples/blob/cf25559da654a7b74bec039c0ab9397dc5951dd4/javav2/example_code/sqs/src/main/java/com/example/sqs/SQSExample.java#L133)」をご覧ください。

## メッセージを取得する
<a name="sqs-messages-receive"></a>

キューに現在含まれているメッセージを取得するには、SqsClient の `receiveMessage` メソッドを呼び出します。このメソッドは、キュー URL を含む [ReceiveMessageRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/sqs/model/ReceiveMessageRequest.html) を受け取ります。また、返るメッセージの最大数を指定することもできます。メッセージは、[Message](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/sqs/model/Message.html) オブジェクトのリストとして返されます。

 **インポート** 

```
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.sqs.SqsClient;
import software.amazon.awssdk.services.sqs.model.*;
import java.util.List;
```

 **コード** 

```
        try {
            ReceiveMessageRequest receiveMessageRequest = ReceiveMessageRequest.builder()
                .queueUrl(queueUrl)
                .maxNumberOfMessages(5)
                .build();
            List<Message> messages = sqsClient.receiveMessage(receiveMessageRequest).messages();
            return messages;
        } catch (SqsException e) {
            System.err.println(e.awsErrorDetails().errorMessage());
            System.exit(1);
        }
        return null;
```

GitHub の「[完全なサンプル](https://github.com/awsdocs/aws-doc-sdk-examples/blob/cf25559da654a7b74bec039c0ab9397dc5951dd4/javav2/example_code/sqs/src/main/java/com/example/sqs/SQSExample.java#L148)」をご覧ください。

## 受信後にメッセージを削除する
<a name="sqs-messages-delete"></a>

メッセージを受信し、その内容を処理した後で、メッセージをキューから削除するには、メッセージの受信ハンドルとキュー URL を `SqsClient's` [https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/sqs/SqsClient.html#deleteMessage(software.amazon.awssdk.services.sqs.model.DeleteMessageRequest)](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/sqs/SqsClient.html#deleteMessage(software.amazon.awssdk.services.sqs.model.DeleteMessageRequest)) メソッドに送信します。

 **インポート** 

```
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.sqs.SqsClient;
import software.amazon.awssdk.services.sqs.model.*;
import java.util.List;
```

 **コード** 

```
        try {
            for (Message message : messages) {
                DeleteMessageRequest deleteMessageRequest = DeleteMessageRequest.builder()
                        .queueUrl(queueUrl)
                        .receiptHandle(message.receiptHandle())
                        .build();
                sqsClient.deleteMessage(deleteMessageRequest);
            }
```

GitHub の「[完全なサンプル](https://github.com/awsdocs/aws-doc-sdk-examples/blob/cf25559da654a7b74bec039c0ab9397dc5951dd4/javav2/example_code/sqs/src/main/java/com/example/sqs/SQSExample.java#L187)」をご覧ください。

## 詳細情報
<a name="more-info"></a>
+  デベロッパーガイド[の Amazon Simple Queue Service キューの仕組み](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-basic-architecture.html) Amazon Simple Queue Service 
+  Amazon Simple Queue Service API リファレンスの [SendMessage](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_SendMessage.html) 
+  Amazon Simple Queue Service API リファレンスの [SendMessageBatch](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_SendMessageBatch.html) 
+  Amazon Simple Queue Service API リファレンスの [ReceiveMessage](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_ReceiveMessage.html) 
+  Amazon Simple Queue Service API リファレンスの [DeleteMessage](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_DeleteMessage.html) 

# の使用 Amazon Transcribe
<a name="examples-transcribe"></a>

以下の例では、 Amazon Transcribeを使用した双方向ストリーミングの仕組みを示しています。双方向ストリーミングとは、サービスに送信されるデータストリームと、サービスからリアルタイムで受信されるデータストリームが、両方あることを意味します。この例では、 Amazon Transcribe ストリーミング文字起こしを使用してオーディオストリームを送信し、文字起こしされたテキストのストリームをリアルタイムで受信します。

この機能の詳細については、 Amazon Transcribe デベロッパーガイドの[「ストリーミング文字起こし](https://docs.aws.amazon.com//transcribe/latest/dg/streaming.html)」を参照してください。

の使用を開始するには、[「 ](https://docs.aws.amazon.com//transcribe/latest/dg/getting-started.html) Amazon Transcribe デベロッパーガイド」の「開始方法」を参照してください Amazon Transcribe。

## マイクを設定する
<a name="set-up-the-microphone"></a>

このコードは、javax.sound.sampled パッケージを使用して、入力デバイスからの音声をストリーミングします。

 **Code** 

```
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.TargetDataLine;

public class Microphone {

    public static TargetDataLine get() throws Exception {
        AudioFormat format = new AudioFormat(16000, 16, 1, true, false);
        DataLine.Info datalineInfo = new DataLine.Info(TargetDataLine.class, format);

        TargetDataLine dataLine = (TargetDataLine) AudioSystem.getLine(datalineInfo);
        dataLine.open(format);

        return dataLine;
    }
}
```

[GitHub](https://github.com/awsdocs/aws-doc-sdk-examples/blob/ac748d8ef99cd17e297cb74fe13aa671e2679088/javav2/example_code/transcribe/src/main/java/com/amazonaws/transcribe/Microphone.java) で完全な例をご覧ください。

## パブリッシャーを作成する
<a name="create-a-publisher"></a>

このコードは、オーディオストリームから Amazon Transcribe オーディオデータを発行するパブリッシャーを実装します。

 **Code** 

```
package com.amazonaws.transcribe;

import java.io.IOException;
import java.io.InputStream;
import java.io.UncheckedIOException;
import java.nio.ByteBuffer;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicLong;
import org.reactivestreams.Publisher;
import org.reactivestreams.Subscriber;
import org.reactivestreams.Subscription;
import software.amazon.awssdk.core.SdkBytes;
import software.amazon.awssdk.services.transcribestreaming.model.AudioEvent;
import software.amazon.awssdk.services.transcribestreaming.model.AudioStream;
import software.amazon.awssdk.services.transcribestreaming.model.TranscribeStreamingException;


public class AudioStreamPublisher implements Publisher<AudioStream> {
    private final InputStream inputStream;

    public AudioStreamPublisher(InputStream inputStream) {
        this.inputStream = inputStream;
    }

    @Override
    public void subscribe(Subscriber<? super AudioStream> s) {
        s.onSubscribe(new SubscriptionImpl(s, inputStream));
    }

    private class SubscriptionImpl implements Subscription {
        private static final int CHUNK_SIZE_IN_BYTES = 1024 * 1;
        private ExecutorService executor = Executors.newFixedThreadPool(1);
        private AtomicLong demand = new AtomicLong(0);

        private final Subscriber<? super AudioStream> subscriber;
        private final InputStream inputStream;

        private SubscriptionImpl(Subscriber<? super AudioStream> s, InputStream inputStream) {
            this.subscriber = s;
            this.inputStream = inputStream;
        }

        @Override
        public void request(long n) {
            if (n <= 0) {
                subscriber.onError(new IllegalArgumentException("Demand must be positive"));
            }

            demand.getAndAdd(n);

            executor.submit(() -> {
                try {
                    do {
                        ByteBuffer audioBuffer = getNextEvent();
                        if (audioBuffer.remaining() > 0) {
                            AudioEvent audioEvent = audioEventFromBuffer(audioBuffer);
                            subscriber.onNext(audioEvent);
                        } else {
                            subscriber.onComplete();
                            break;
                        }
                    } while (demand.decrementAndGet() > 0);
                } catch (TranscribeStreamingException e) {
                    subscriber.onError(e);
                }
            });
        }

        @Override
        public void cancel() {

        }

        private ByteBuffer getNextEvent() {
            ByteBuffer audioBuffer;
            byte[] audioBytes = new byte[CHUNK_SIZE_IN_BYTES];

            int len = 0;
            try {
                len = inputStream.read(audioBytes);

                if (len <= 0) {
                    audioBuffer = ByteBuffer.allocate(0);
                } else {
                    audioBuffer = ByteBuffer.wrap(audioBytes, 0, len);
                }
            } catch (IOException e) {
                throw new UncheckedIOException(e);
            }

            return audioBuffer;
        }

        private AudioEvent audioEventFromBuffer(ByteBuffer bb) {
            return AudioEvent.builder()
                    .audioChunk(SdkBytes.fromByteBuffer(bb))
                    .build();
        }
    }
}
```

[GitHub](https://github.com/awsdocs/aws-doc-sdk-examples/blob/ac748d8ef99cd17e297cb74fe13aa671e2679088/javav2/example_code/transcribe/src/main/java/com/amazonaws/transcribe/AudioStreamPublisher.java) で完全な例をご覧ください。

## クライアントを作成してストリーミングを開始する
<a name="create-the-client-and-start-the-stream"></a>

main メソッドで、リクエストオブジェクトを作成し、音声入力ストリームを開始して、音声入力でパブリッシャーをインスタンス化します。

また、[StartStreamTranscriptionResponseHandler](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/transcribestreaming/model/StartStreamTranscriptionResponseHandler.html) を作成して、レスポンスの処理方法を指定する必要があります Amazon Transcribe。

その後、TranscribeStreamingAsyncClient の `startStreamTranscription` メソッドを使用して双方向ストリーミングを開始します。

 **インポート** 

```
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.TargetDataLine;
import javax.sound.sampled.AudioInputStream;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.transcribestreaming.TranscribeStreamingAsyncClient;
import software.amazon.awssdk.services.transcribestreaming.model.TranscribeStreamingException ;
import software.amazon.awssdk.services.transcribestreaming.model.StartStreamTranscriptionRequest;
import software.amazon.awssdk.services.transcribestreaming.model.MediaEncoding;
import software.amazon.awssdk.services.transcribestreaming.model.LanguageCode;
import software.amazon.awssdk.services.transcribestreaming.model.StartStreamTranscriptionResponseHandler;
import software.amazon.awssdk.services.transcribestreaming.model.TranscriptEvent;
```

 **Code** 

```
    public static void convertAudio(TranscribeStreamingAsyncClient client) throws Exception {

        try {

            StartStreamTranscriptionRequest request = StartStreamTranscriptionRequest.builder()
                    .mediaEncoding(MediaEncoding.PCM)
                    .languageCode(LanguageCode.EN_US)
                    .mediaSampleRateHertz(16_000).build();

            TargetDataLine mic = Microphone.get();
            mic.start();

            AudioStreamPublisher publisher = new AudioStreamPublisher(new AudioInputStream(mic));

            StartStreamTranscriptionResponseHandler response =
                    StartStreamTranscriptionResponseHandler.builder().subscriber(e -> {
                        TranscriptEvent event = (TranscriptEvent) e;
                        event.transcript().results().forEach(r -> r.alternatives().forEach(a -> System.out.println(a.transcript())));
                    }).build();

            // Keeps Streaming until you end the Java program
            client.startStreamTranscription(request, publisher, response);

        } catch (TranscribeStreamingException e) {
            System.err.println(e.awsErrorDetails().errorMessage());
            System.exit(1);
         }
    }
```

[GitHub](https://github.com/awsdocs/aws-doc-sdk-examples/blob/ac748d8ef99cd17e297cb74fe13aa671e2679088/javav2/example_code/transcribe/src/main/java/com/amazonaws/transcribe/BidirectionalStreaming.java) で完全な例をご覧ください。

## 詳細情報
<a name="more-info"></a>
+  Amazon Transcribe デベロッパーガイドの[仕組み](https://docs.aws.amazon.com//transcribe/latest/dg/how-it-works.html)。
+  Amazon Transcribe デベロッパーガイドの[ストリーミングオーディオの開始方法](https://docs.aws.amazon.com//transcribe/latest/dg/getting-started.html)。