

As traduções são geradas por tradução automática. Em caso de conflito entre o conteúdo da tradução e da versão original em inglês, a versão em inglês prevalecerá.

# Chamar Serviços da AWS pelo AWS SDK for Java 2.x
<a name="work-with-services"></a>

Esta seção fornece tutoriais curtos e orientações sobre como trabalhar com os Serviços da AWS selecionados. Para ver um conjunto completo de exemplos, consulte a [seção Exemplos de código](java_code_examples.md).

**Topics**
+ [CloudWatch](examples-cloudwatch.md)
+ [serviços de banco de dados 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)

# Trabalhe com CloudWatch
<a name="examples-cloudwatch"></a>

Esta seção fornece exemplos de programação da [Amazon CloudWatch](https://docs.aws.amazon.com//AmazonCloudWatch/latest/monitoring/WhatIsCloudWatch.html) usando o AWS SDK para Java 2.x.

 Amazon CloudWatch monitora seus Amazon Web Services (AWS) recursos e os aplicativos em que você executa AWS em tempo real. Você pode usar CloudWatch para coletar e monitorar métricas, que são variáveis que você pode medir para seus recursos e aplicativos. CloudWatch os alarmes enviam notificações ou fazem alterações automáticas nos recursos que você está monitorando com base nas regras definidas por você.

Os exemplos a seguir incluem somente o código necessário para demonstrar cada técnica. O [código de exemplo completo está disponível em GitHub](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/javav2). A partir daí, você pode fazer download de um único arquivo de origem ou clonar o repositório de maneira local para obter todos os exemplos para compilação e execução.

**Topics**
+ [Obtenha métricas de CloudWatch](examples-cloudwatch-get-metrics.md)
+ [Publique dados métricos personalizados em CloudWatch](examples-cloudwatch-publish-custom-metrics.md)
+ [Trabalhe com CloudWatch alarmes](examples-cloudwatch-create-alarms.md)
+ [Use os CloudWatch eventos da Amazon](examples-cloudwatch-send-events.md)

# Obtenha métricas de CloudWatch
<a name="examples-cloudwatch-get-metrics"></a>

## Listar métricas
<a name="listing-metrics"></a>

Para listar CloudWatch as métricas, crie um `listMetrics` método [ListMetricsRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/cloudwatch/model/ListMetricsRequest.html)e chame o CloudWatchClient. Você pode usar o `ListMetricsRequest` para filtrar as métricas retornadas por namespace, nome da métrica ou dimensões.

**nota**  
Uma lista de métricas e dimensões publicadas pelos AWS serviços pode ser encontrada na [Referência de Amazon CloudWatch métricas e dimensões](https://docs.aws.amazon.com//AmazonCloudWatch/latest/monitoring/aws-services-cloudwatch-metrics.html) no Guia do Amazon CloudWatch usuário.

 **Importações** 

```
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;
```

 **Código** 

```
    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);
        }
    }
```

As métricas são retornadas em a [ListMetricsResponse](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/cloudwatch/model/ListMetricsResponse.html)chamando seu `getMetrics` método.

Os resultados podem ser *paginados*. Para recuperar o próximo lote de resultados, chame `nextToken` no objeto de resposta e use o valor do token para compilar um novo objeto de solicitação. Em seguida, chame o método `listMetrics` novamente com a nova solicitação.

Veja o [exemplo completo](https://github.com/awsdocs/aws-doc-sdk-examples/blob/f4eaf2b2971805cfb2b87a8e5ab408f83169432e/javav2/example_code/cloudwatch/src/main/java/com/example/cloudwatch/ListMetrics.java) em GitHub.

## Mais informações
<a name="more-information"></a>
+  [ListMetrics](https://docs.aws.amazon.com//AmazonCloudWatch/latest/APIReference/API_ListMetrics.html)na Referência da Amazon CloudWatch API

# Publique dados métricos personalizados em CloudWatch
<a name="examples-cloudwatch-publish-custom-metrics"></a>

Vários AWS serviços [publicam suas próprias métricas](https://docs.aws.amazon.com//AmazonCloudWatch/latest/monitoring/aws-services-cloudwatch-metrics.html) em namespaces começando com "`AWS`" Você também pode publicar dados métricos personalizados usando seu próprio namespace (desde que não comece com "“). `AWS`

## Publicar dados de métrica personalizada
<a name="cwid1"></a>

Para publicar seus próprios dados métricos, chame o `putMetricData` método CloudWatchClient's com um [PutMetricDataRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/cloudwatch/model/PutMetricDataRequest.html). Eles `PutMetricDataRequest` devem incluir o namespace personalizado a ser usado para os dados e informações sobre o próprio ponto de dados em um [MetricDatum](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/cloudwatch/model/MetricDatum.html)objeto.

**nota**  
Você não pode especificar um namespace que começa com “`AWS`”. Os namespaces que começam com "`AWS`" são reservados para uso por Amazon Web Services produtos.

 **Importações** 

```
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;
```

 **Código** 

```
    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);
     }
```

Veja o [exemplo completo](https://github.com/awsdocs/aws-doc-sdk-examples/blob/f4eaf2b2971805cfb2b87a8e5ab408f83169432e/javav2/example_code/cloudwatch/src/main/java/com/example/cloudwatch/PutMetricData.java) em GitHub.

## Mais informações
<a name="more-information"></a>
+  [Use Amazon CloudWatch métricas](https://docs.aws.amazon.com//AmazonCloudWatch/latest/monitoring/working_with_metrics.html) no Guia do Amazon CloudWatch usuário.
+  [AWS Namespaces](https://docs.aws.amazon.com//AmazonCloudWatch/latest/monitoring/aws-services-cloudwatch-metrics.html) no Guia do Amazon CloudWatch usuário.
+  [PutMetricData](https://docs.aws.amazon.com//AmazonCloudWatch/latest/APIReference/API_PutMetricData.html)na Referência da Amazon CloudWatch API.

# Trabalhe com CloudWatch alarmes
<a name="examples-cloudwatch-create-alarms"></a>

## Criar um alarme
<a name="create-an-alarm"></a>

Para criar um alarme com base em uma CloudWatch métrica, chame o `putMetricAlarm` método CloudWatchClient's [PutMetricAlarmRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/cloudwatch/model/PutMetricAlarmRequest.html)preenchendo as condições do alarme.

 **Importações** 

```
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;
```

 **Código** 

```
    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);
        }
    }
```

Veja o [exemplo completo](https://github.com/awsdocs/aws-doc-sdk-examples/blob/f4eaf2b2971805cfb2b87a8e5ab408f83169432e/javav2/example_code/cloudwatch/src/main/java/com/example/cloudwatch/PutMetricAlarm.java) em GitHub.

## Listar alarmes
<a name="list-alarms"></a>

Para listar os CloudWatch alarmes que você criou, chame o `describeAlarms` método CloudWatchClient's com um [DescribeAlarmsRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/cloudwatch/model/DescribeAlarmsRequest.html)que você pode usar para definir opções para o resultado.

 **Importações** 

```
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;
```

 **Código** 

```
    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");
    }
```

A lista de alarmes pode ser obtida `MetricAlarms` chamando o [DescribeAlarmsResponse](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/cloudwatch/model/DescribeAlarmsResponse.html)que é retornado por`describeAlarms`.

Os resultados podem ser *paginados*. Para recuperar o próximo lote de resultados, chame `nextToken` no objeto de resposta e use o valor do token para compilar um novo objeto de solicitação. Em seguida, chame o método `describeAlarms` novamente com a nova solicitação.

**nota**  
Você também pode recuperar alarmes para uma métrica específica usando o método CloudWatchClient's`describeAlarmsForMetric`. O uso é semelhante a `describeAlarms`.

Veja o [exemplo completo](https://github.com/awsdocs/aws-doc-sdk-examples/blob/f4eaf2b2971805cfb2b87a8e5ab408f83169432e/javav2/example_code/cloudwatch/src/main/java/com/example/cloudwatch/DescribeAlarms.java) em GitHub.

## Excluir alarmes
<a name="delete-alarms"></a>

Para excluir CloudWatch alarmes, chame o `deleteAlarms` método CloudWatchClient's [DeleteAlarmsRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/cloudwatch/model/DeleteAlarmsRequest.html)contendo um ou mais nomes de alarmes que você deseja excluir.

 **Importações** 

```
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;
```

 **Código** 

```
    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);
        }
    }
```

Veja o [exemplo completo](https://github.com/awsdocs/aws-doc-sdk-examples/blob/f4eaf2b2971805cfb2b87a8e5ab408f83169432e/javav2/example_code/cloudwatch/src/main/java/com/example/cloudwatch/DeleteAlarm.java) em GitHub.

## Mais informações
<a name="more-information"></a>
+  [Usando Amazon CloudWatch alarmes](https://docs.aws.amazon.com//AmazonCloudWatch/latest/monitoring/AlarmThatSendsEmail.html) no Guia do Amazon CloudWatch usuário
+  [PutMetricAlarm](https://docs.aws.amazon.com//AmazonCloudWatch/latest/APIReference/API_PutMetricAlarm.html)na Referência da Amazon CloudWatch API
+  [DescribeAlarms](https://docs.aws.amazon.com//AmazonCloudWatch/latest/APIReference/API_DescribeAlarms.html)na Referência da Amazon CloudWatch API
+  [DeleteAlarms](https://docs.aws.amazon.com//AmazonCloudWatch/latest/APIReference/API_DeleteAlarms.html)na Referência da Amazon CloudWatch API

# Use os CloudWatch eventos da Amazon
<a name="examples-cloudwatch-send-events"></a>

 CloudWatch O Events fornece um fluxo quase em tempo real de eventos do sistema que descrevem mudanças nos AWS recursos em Amazon EC2 instâncias, Lambda funções, Kinesis fluxos, Amazon ECS tarefas, máquinas de Step Functions estado, Amazon SNS tópicos, Amazon SQS filas ou destinos integrados. Você pode comparar eventos e roteá-los para um ou mais fluxos ou funções de destino usando regras simples.

A Amazon EventBridge é a [evolução](https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-cwe-now-eb.html) dos CloudWatch eventos. Ambos os serviços usam a mesma API, para que você possa continuar usando o [cliente de CloudWatch eventos](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/cloudwatch/CloudWatchClient.html) fornecido pelo SDK ou migrar para o [EventBridge cliente](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/eventbridge/EventBridgeClient.html) do SDK for Java para a funcionalidade de eventos. CloudWatch CloudWatch A [documentação do Guia do Usuário](https://docs.aws.amazon.com/eventbridge/latest/userguide/index.html) de Eventos e a [referência da API](https://docs.aws.amazon.com/eventbridge/latest/APIReference/index.html) agora estão disponíveis nos sites de EventBridge documentação.

## Adicionar eventos
<a name="add-events"></a>

Para adicionar CloudWatch eventos personalizados, chame o `CloudWatchEventsClient’s` `putEvents` método com um [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)objeto que contém um ou mais [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)objetos que fornecem detalhes sobre cada evento. Você pode especificar vários parâmetros para a entrada, como a origem e o tipo do evento, recursos associados ao evento e assim por diante.

**nota**  
Você pode especificar um máximo de dez eventos por chamada para `putEvents`.

 **Importações** 

```
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;
```

 **Código** 

```
    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);
        }
    }
```

Veja o [exemplo completo](https://github.com/awsdocs/aws-doc-sdk-examples/blob/0b1785e42949ebf959eaa0f0da4dc2a48f92ea25/javav2/example_code/cloudwatch/src/main/java/com/example/cloudwatch/PutEvents.java) em GitHub.

## Adicionar regras
<a name="add-rules"></a>

Para criar ou atualizar uma regra, chame o `CloudWatchEventsClient’s` `putRule` método com a [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)com o nome da regra e parâmetros opcionais, como o [padrão do evento](https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-event-patterns.html), a IAM função a ser associada à regra e uma [expressão de agendamento](https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-create-rule-schedule.html) que descreva a frequência com que a regra é executada.

 **Importações** 

```
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;
```

 **Código** 

```
    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);
        }
    }
```

Veja o [exemplo completo](https://github.com/awsdocs/aws-doc-sdk-examples/blob/0b1785e42949ebf959eaa0f0da4dc2a48f92ea25/javav2/example_code/cloudwatch/src/main/java/com/example/cloudwatch/PutRule.java) em GitHub.

## Adicionar destinos
<a name="add-targets"></a>

Destinos são os recursos invocados quando uma regra é disparada. Os alvos de exemplo incluem Amazon EC2 instâncias, Lambda funções, Kinesis fluxos, Amazon ECS tarefas, máquinas de Step Functions estado e destinos integrados.

Para adicionar um destino a uma regra, chame o método `putTargets` do `CloudWatchEventsClient’s` com um [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) que contenha a regra que deve ser atualizada e uma lista de destinos que devem ser adicionados à regra.

 **Importações** 

```
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;
```

 **Código** 

```
    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);
        }
    }
```

Veja o [exemplo completo](https://github.com/awsdocs/aws-doc-sdk-examples/blob/0b1785e42949ebf959eaa0f0da4dc2a48f92ea25/javav2/example_code/cloudwatch/src/main/java/com/example/cloudwatch/PutTargets.java) em GitHub.

## Mais informações
<a name="more-information"></a>
+  [Adicionando eventos PutEvents](https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-putevents.html) no Guia do EventBridge usuário da Amazon
+  [Agende expressões para regras](https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-create-rule-schedule.html#eb-create-scheduled-rule-schedule) no Guia do EventBridge usuário da Amazon
+  [Tipos de eventos para CloudWatch Events](https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-service-event.html) o Amazon EventBridge User Guide
+  [Padrões de eventos](https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-event-patterns.html) no Guia EventBridge do usuário da Amazon
+  [PutEvents](https://docs.aws.amazon.com/eventbridge/latest/APIReference/API_PutEvents.html)na Amazon EventBridge API Reference
+  [PutTargets](https://docs.aws.amazon.com/eventbridge/latest/APIReference/API_PutTargets.html)na Amazon EventBridge API Reference
+  [PutRule](https://docs.aws.amazon.com/eventbridge/latest/APIReference/API_PutRule.html)na Amazon EventBridge API Reference

# serviços de banco de dados AWS e AWS SDK for Java 2.x
<a name="examples-databases"></a>

O AWS oferece vários tipos de banco de dados: relacional, chave-valor, na memória, documento e [vários outros](https://aws.amazon.com/products/databases/). O suporte do SDK for Java 2.x varia de acordo com a natureza do serviço de banco de dados no AWS.

Alguns serviços de banco de dados, por exemplo, o serviço [Amazon DynamoDB](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/Welcome.html), têm APIs de serviços web para gerenciar o recurso AWS (banco de dados), bem como APIs de serviços web para interagir com os dados. No SDK for Java 2.x, esses tipos de serviços têm clientes de serviço dedicados, por exemplo, [DynamoDBClient](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/DynamoDbClient.html).

Outros serviços de banco de dados têm APIs de serviços web que interagem com o recurso, como a API [Amazon DocumentDB](https://docs.aws.amazon.com/documentdb/latest/developerguide/api-reference.html) (para gerenciamento de clusters, instâncias e recursos), mas não têm uma API de serviços web para trabalhar com os dados. O SDK for Java 2.x tem uma interface [DocDbClient](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/docdb/DocDbClient.html) correspondente para trabalhar com o recurso. No entanto, você precisa de outra API Java, como [MongoDB para Java](https://www.mongodb.com/developer/languages/java/), para trabalhar com os dados.

Use os exemplos abaixo para saber como usar o SDK para clientes de serviço Java 2.x com os diferentes tipos de bancos de dados.

## Exemplos do Amazon DynamoDB
<a name="examples-db-dynamodb"></a>


| Trabalhar com os dados | Trabalhar com o banco de dados | 
| --- |--- |
| 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: [Aplicativo React/Spring REST usando o DynamoDB](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: [Vários exemplos do 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: [Aplicativo React/Spring REST usando o DynamoDB](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/javav2/usecases/creating_dynamodb_web_app) |  | 
| Examples: [Vários exemplos do 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") |  | 

Veja [exemplos adicionais do DynamoDB](examples-dynamodb.md) na seção de exemplos de código guiado deste guia.

## Exemplos do Amazon RDS
<a name="examples-db-rds"></a>


|  Trabalhar com os dados  |  Trabalhar com o banco de dados  | 
| --- | --- | 
| API não SDK: JDBC, sabor SQL específico do banco de dados; seu código gerencia conexões de banco de dados ou um pool de conexões. | Cliente de serviço SDK: [RdsClient](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/rds/RdsClient.html) | 
| Exemplo: [aplicativo React/Spring REST usando MySQL](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/javav2/usecases/Creating_rds_item_tracker) | Exemplos: [vários exemplos de RdsClient](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/javav2/example_code/rds/src/main/java/com/example/rds) | 

## Exemplos do Amazon Redshift
<a name="examples-db-redshift"></a>


|  Trabalhar com os dados  |  Trabalhar com o banco de dados  | 
| --- | --- | 
| Cliente de serviço SDK: [RedshiftDataClient](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/redshiftdata/RedshiftDataClient.html) | Cliente de serviço SDK: [RedshiftClient](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/redshift/RedshiftClient.html) | 
| Exemplos: [vários exemplos do RedshiftDataClient](https://github.com/awsdocs/aws-doc-sdk-examples/blob/c682a07a1e6abce793e3c32ef3b9661fa723d0ff/javav2/example_code/redshift/src/main/java/com/example/scenario/RedshiftScenario.java) | Exemplos: [vários exemplos do RedshiftClient](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/javav2/example_code/redshift/src/main/java/com/example/redshift) | 
| Exemplo: [aplicativo React/Spring REST usando RedshiftDataClient](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/javav2/usecases/CreatingSpringRedshiftRest) |  | 

## Exemplos do Amazon Aurora Sem Servidor v2
<a name="examples-db-aurora-sv1"></a>


|  Trabalhar com os dados  |  Trabalhar com o banco de dados  | 
| --- | --- | 
| Cliente de serviço SDK: [RdsDataClient](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/rdsdata/RdsDataClient.html) | Cliente de serviço SDK: [RdsClient](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/rds/RdsClient.html) | 
| Exemplo: [aplicativo React/Spring REST usando RdsDataClient](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/javav2/usecases/Creating_Spring_RDS_Rest) | Exemplos: [vários exemplos de RdsClient](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/javav2/example_code/rds/src/main/java/com/example/rds) | 

## Exemplos do Amazon DocumentDB
<a name="examples-db-docdb"></a>


|  Trabalhar com os dados  |  Trabalhar com o banco de dados  | 
| --- | --- | 
| API não SDK: biblioteca Java específica do MongoDB (por exemplo, [MongoDB para Java](https://www.mongodb.com/developer/languages/java/)); seu código gerencia conexões de banco de dados ou um pool de conexões. | Cliente de serviço SDK: [DocDbClient](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/docdb/DocDbClient.html) | 
| Exemplos: [Guia do desenvolvedor do DocumentDB (Mongo)](https://docs.aws.amazon.com/documentdb/latest/developerguide/connect_programmatically.html#connect_programmatically-tls_enabled) (selecione a guia 'Java') |  | 

# Trabalhe com DynamoDB
<a name="examples-dynamodb"></a>

O [DynamoDB](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Introduction.html) é um serviço de banco de dados NoSQL totalmente gerenciado que proporciona um desempenho rápido e previsível com escalabilidade contínua. Esta seção mostra como trabalhar com o DynamoDB usando o AWS SDK para Java 2.x.

## Escolher o cliente do DynamoDB
<a name="ddb-clients-overview"></a>

O SDK fornece duas abordagens principais para trabalhar com o DynamoDB:

Cliente de nível inferior (`DynamoDbClient`)  
Fornece acesso direto às operações do DynamoDB com controle total sobre solicitações e respostas. Use esse cliente quando precisar de um controle refinado ou trabalhar com esquemas dinâmicos.

Cliente aprimorado (`DynamoDbEnhancedClient`)  
Oferece programação orientada a objetos com mapeamento automático entre objetos do Java e itens do DynamoDB. Também fornece recursos orientados a documentos para trabalhar com dados semelhantes a JSON que não seguem um esquema fixo. Use esse cliente ao trabalhar com modelos de dados bem definidos ou dados do tipo de documento.

## Configurar clientes do DynamoDB
<a name="ddb-configuration-setup"></a>

Antes de trabalhar com o DynamoDB, configure o cliente para obter desempenho e confiabilidade ideais.

### Noções básicas do comportamento de nova tentativa do DynamoDB
<a name="ddb-retry-behavior"></a>

Os clientes do DynamoDB usam uma contagem máxima de novas tentativas padrão de 8, que é maior que a de outros clientes de AWS service (Serviço da AWS) . Essa contagem mais alta de tentativas ajuda a lidar com a natureza distribuída e as limitações temporárias de capacidade do DynamoDB. Consulte mais informações sobre estratégias de novas tentativas em [Configure o comportamento de repetição no AWS SDK for Java 2.x](retry-strategy.md).

### Otimize o desempenho com endpoints baseados em contas
<a name="ddb-account-based-endpoints-v2"></a>

O DynamoDB [AWS oferece endpoints baseados em contas](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Programming.SDKOverview.html#Programming.SDKs.endpoints) que melhoram o desempenho usando AWS seu ID de conta para simplificar o roteamento de solicitações. 

Para usar esse recurso, você precisa da versão 2.28.4 ou posterior do AWS SDK for Java 2.x. É possível encontrar a versão mais recente no [repositório central do Maven](https://central.sonatype.com/artifact/software.amazon.awssdk/bom/versions). As versões compatíveis do SDK usam os novos endpoints automaticamente.

Para desativar o roteamento baseado em conta, escolha uma destas opções:
+ Configurar um cliente de serviço do DynamoDB com `AccountIdEndpointMode` definido como `DISABLED`.
+ Definir uma variável de ambiente.
+ Definir uma propriedade do sistema da JVM.
+ Atualize a AWS configuração do arquivo de configuração compartilhado.

O seguinte exemplo mostra como desabilitar o roteamento baseado em contas configurando um cliente de serviço do DynamoDB:

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

Para obter mais informações sobre as outras opções de configuração, consulte [Endpoints baseados em conta](https://docs.aws.amazon.com/sdkref/latest/guide/feature-account-endpoints.html) no Guia de referência de ferramentas AWS SDKs e ferramentas.

## O que é abordado neste tópico
<a name="ddb-topics-overview"></a>

As seguintes seções mostram como trabalhar com o DynamoDB:
+ [Trabalhar com tabelas no DynamoDB](examples-dynamodb-tables.md): criar, descrever, atualizar e excluir tabelas
+ [Trabalhe com itens em DynamoDB](examples-dynamodb-items.md): adicionar, recuperar e atualizar itens individuais
+ [Mapeie objetos Java para itens do DynamoDB com o AWS SDK for Java 2.x](dynamodb-enhanced-client.md): usar mapeamento de objetos e dados orientados a documentos com o Cliente Aprimorado

Para ver exemplos adicionais de código do DynamoDB, consulte exemplos de código do [DynamoDB na Biblioteca de exemplos de códigos.](java_dynamodb_code_examples.md) AWS 

# Trabalhar com tabelas no DynamoDB
<a name="examples-dynamodb-tables"></a>

Tabelas são os contêineres de todos os itens em um banco de dados do DynamoDB. Para adicionar ou remover dados do DynamoDB, você deve criar uma tabela.

Para cada tabela, você deve definir:
+ Um *nome* de tabela é exclusivo para a conta e a região.
+ Uma *chave primária* para a qual cada valor deve ser único; dois itens na tabela não podem ter o mesmo valor de chave primária.

  Uma chave primária pode ser *simples*, consistindo em uma única chave de partição (HASH) ou *composta*, que consiste em uma partição e uma chave de classificação (RANGE).

  Cada valor de chave tem um *tipo de dados* associado, enumerado pela classe [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). O valor da chave pode ser binário (B), numérico (N) ou uma string (S). Para obter mais informações, consulte [Regras de nomenclatura e tipos de dados](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.NamingRulesDataTypes.html) no Guia do desenvolvedor do Amazon DynamoDB.
+  *Throughput provisionado* são valores que definem o número de unidades de capacidade de leitura/gravação reservado para a tabela.
**nota**  
 A [definição de preço do Amazon DynamoDB](https://aws.amazon.com/dynamodb/pricing/) se baseia nos valores de throughput provisionados definidos por você nas tabelas. Dessa forma, reserve somente a capacidade máxima de que você imagina precisar para a tabela.

  O throughput provisionado para uma tabela pode ser modificado a qualquer momento. Dessa forma, você poderá ajustar a capacidade conforme suas necessidades mudam.

## Criar uma tabela
<a name="dynamodb-create-table"></a>

Use o método `createTable` do `DynamoDbClient’s` para criar uma tabela do DynamoDB. Você precisa construir atributos de tabela e um esquema de tabela, ambos usados para identificar a chave primária da tabela. Você também deve fornecer valores de throughput provisionado iniciais e um nome de tabela.

**nota**  
Se uma tabela com o nome escolhido por você já existir, uma `[DynamoDbException](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/model/DynamoDbException.html)` será lançada.

### Criar uma tabela com uma chave primária simples
<a name="dynamodb-create-table-simple"></a>

Esse código cria uma tabela com um atributo, que é a chave primária simples da tabela. O exemplo usa os objetos `[AttributeDefinition](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/model/AttributeDefinition.html)` e `[KeySchemaElement](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/model/KeySchemaElement.html)` para [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).

 **Importações** 

```
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;
```

 **Código da** 

```
    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 "";
    }
```

Veja o [exemplo completo](https://github.com/awsdocs/aws-doc-sdk-examples/blob/0b1785e42949ebf959eaa0f0da4dc2a48f92ea25/javav2/example_code/dynamodb/src/main/java/com/example/dynamodb/CreateTable.java) no GitHub.

### Criar uma tabela com uma chave primária composta
<a name="dynamodb-create-table-composite"></a>

O exemplo a seguir cria uma tabela com dois atributos. Os dois atributos são usados para a chave primária composta.

 **Importações** 

```
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;
```

 **Código da** 

```
    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 "";
    }
```

Veja o [exemplo completo](https://github.com/awsdocs/aws-doc-sdk-examples/blob/0b1785e42949ebf959eaa0f0da4dc2a48f92ea25/javav2/example_code/dynamodb/src/main/java/com/example/dynamodb/CreateTableCompositeKey.java) no GitHub.

## Listar tabelas
<a name="dynamodb-list-tables"></a>

É possível listar as tabelas em determinada região chamando o método `listTables` do `DynamoDbClient’s`.

**nota**  
Se a tabela nomeada não existir para a conta e a região, uma [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) será lançada.

 **Importações** 

```
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;
```

 **Código da** 

```
    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!");
    }
```

Por padrão, até 100 tabelas são retornadas por chamada. Use `lastEvaluatedTableName` no objeto [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) retornado para obter a tabela mais recentemente avaliada. Você pode usar esse valor para iniciar a listagem depois do último valor retornado da listagem anterior.

Veja o [exemplo completo](https://github.com/awsdocs/aws-doc-sdk-examples/blob/0b1785e42949ebf959eaa0f0da4dc2a48f92ea25/javav2/example_code/dynamodb/src/main/java/com/example/dynamodb/ListTables.java) no GitHub.

## Descrever (obter informações sobre) uma tabela
<a name="dynamodb-describe-table"></a>

Use o método `DynamoDbClient’s` `describeTable` para obter informações sobre uma tabela.

**nota**  
Se a tabela nomeada não existir para a conta e a região, uma [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) será lançada.

 **Importações** 

```
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;
```

 **Código da** 

```
    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!");
    }
```

Veja o [exemplo completo](https://github.com/awsdocs/aws-doc-sdk-examples/blob/0b1785e42949ebf959eaa0f0da4dc2a48f92ea25/javav2/example_code/dynamodb/src/main/java/com/example/dynamodb/DescribeTable.java) no GitHub.

## Modificar (atualizar) uma tabela
<a name="dynamodb-update-table"></a>

Você pode modificar os valores de throughput provisionada da tabela a qualquer momento chamando o método `DynamoDbClient’s` `updateTable`.

**nota**  
Se a tabela nomeada não existir para a conta e a região, uma [ResourceNotFoundException](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/model/ResourceNotFoundException.html) será lançada.

 **Importações** 

```
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;
```

 **Código da** 

```
    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!");
    }
```

Veja o [exemplo completo](https://github.com/awsdocs/aws-doc-sdk-examples/blob/0b1785e42949ebf959eaa0f0da4dc2a48f92ea25/javav2/example_code/dynamodb/src/main/java/com/example/dynamodb/UpdateTable.java) no GitHub.

## Excluir uma tabela
<a name="dynamodb-delete-table"></a>

Para excluir uma tabela, chame o método `DynamoDbClient’s` `deleteTable` e forneça o nome da tabela.

**nota**  
Se a tabela nomeada não existir para a conta e a região, uma [ResourceNotFoundException](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/model/ResourceNotFoundException.html) será lançada.

 **Importações** 

```
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;
```

 **Código da** 

```
    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!");
    }
```

Veja o [exemplo completo](https://github.com/awsdocs/aws-doc-sdk-examples/blob/0b1785e42949ebf959eaa0f0da4dc2a48f92ea25/javav2/example_code/dynamodb/src/main/java/com/example/dynamodb/DeleteTable.java) no GitHub.

## Mais informações
<a name="more-information"></a>
+  [Diretrizes para trabalhar com tabelas](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GuidelinesForTables.html) no Guia do desenvolvedor do Amazon DynamoDB
+  [Trabalhar com tabelas no DynamoDB](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/WorkingWithTables.html) no Guia do Desenvolvedor do Amazon DynamoDB

# Trabalhe com itens em DynamoDB
<a name="examples-dynamodb-items"></a>

Em DynamoDB, um item é uma coleção de *atributos*, cada um com um *nome* e um *valor*. Um valor de atributo pode ser uma escalar, um conjunto ou um tipo de documento. Para obter mais informações, consulte [Regras de nomenclatura e tipos de dados](https://docs.aws.amazon.com//amazondynamodb/latest/developerguide/HowItWorks.NamingRulesDataTypes.html) no Guia do desenvolvedor do Amazon DynamoDB .

## Recuperar (obter) um item de uma tabela
<a name="dynamodb-get-item"></a>

Chame o `getItem` método DynamoDbClient's e passe a ele um [GetItemRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/model/GetItemRequest.html)objeto com o nome da tabela e o valor da chave primária do item que você deseja. Ele retorna um [GetItemResponse](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/model/GetItemResponse.html)objeto com todos os atributos desse item. Você pode especificar uma ou mais [expressões de projeção](https://docs.aws.amazon.com//amazondynamodb/latest/developerguide/Expressions.ProjectionExpressions.html) no `GetItemRequest` para recuperar atributos específicos.

Você pode usar o `item()` método do `GetItemResponse` objeto retornado para recuperar um [mapa](https://docs.oracle.com/javase/8/docs/api/index.html?java/util/Map.html) dos pares de chave (String [AttributeValue](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/model/AttributeValue.html)) e valor () associados ao item.

 **Importações** 

```
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;
```

 **Código** 

```
    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);
        }
    }
```

Veja o [exemplo completo](https://github.com/awsdocs/aws-doc-sdk-examples/blob/bc964a243276990f05c180618ea8b34777c68f0e/javav2/example_code/dynamodb/src/main/java/com/example/dynamodb/GetItem.java) em GitHub.

## Recuperar (obter) um item de uma tabela usando o cliente assíncrono
<a name="id1ddb"></a>

Invoque o `getItem` método do DynamoDbAsyncClient e passe a ele um [GetItemRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/model/GetItemRequest.html)objeto com o nome da tabela e o valor da chave primária do item desejado.

Você pode retornar uma instância de [Collection](https://docs.oracle.com/javase/8/docs/api/index.html?java/util/Collection.html) com todos os atributos desse item (consulte o exemplo a seguir).

 **Importações** 

```
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;
```

 **Código** 

```
    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);
        }
```

Veja o [exemplo completo](https://github.com/awsdocs/aws-doc-sdk-examples/blob/bc964a243276990f05c180618ea8b34777c68f0e/javav2/example_code/dynamodbasync/src/main/java/com/example/dynamodbasync/DynamoDBAsyncGetItem.java) em GitHub.

## Adicionar um novo item a uma tabela
<a name="dynamodb-add-item"></a>

Crie um [Mapa](https://docs.oracle.com/javase/8/docs/api/index.html?java/util/Map.html) de pares de chave/valor que representem os atributos do item. Eles devem incluir valores para os campos de chave primária da tabela. Se o item identificado pela chave primária já existir, os campos serão *atualizados* pela requisição.

**nota**  
Se a tabela nomeada não existir para sua conta e região, um [ResourceNotFoundException](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/model/ResourceNotFoundException.html)será lançado.

 **Importações** 

```
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;
```

 **Código** 

```
    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);
        }
    }
```

Veja o [exemplo completo](https://github.com/awsdocs/aws-doc-sdk-examples/blob/f4eaf2b2971805cfb2b87a8e5ab408f83169432e/javav2/example_code/dynamodb/src/main/java/com/example/dynamodb/PutItem.java) em GitHub.

## Atualizar um item existente em uma tabela
<a name="dynamodb-update-item"></a>

Você pode atualizar um atributo para um item já existente em uma tabela usando o método `updateItem` do DynamoDbClient, fornecendo um nome de tabela, o valor da chave primária e um mapa de campos a ser atualizado.

**nota**  
Se a tabela nomeada não existir para sua conta e região, ou se o item identificado pela chave primária que você inseriu não existir, um [ResourceNotFoundException](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/model/ResourceNotFoundException.html)será lançado.

 **Importações** 

```
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;
```

 **Código** 

```
    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!");
    }
```

Veja o [exemplo completo](https://github.com/awsdocs/aws-doc-sdk-examples/blob/f4eaf2b2971805cfb2b87a8e5ab408f83169432e/javav2/example_code/dynamodb/src/main/java/com/example/dynamodb/UpdateItem.java) em GitHub.

## Excluir um item existente em uma tabela
<a name="dynamodb-delete-item"></a>

Você pode excluir um item que existe em uma tabela usando o `deleteItem` método DynamoDbClient's e fornecendo um nome de tabela, bem como o valor da chave primária.

**nota**  
Se a tabela nomeada não existir para sua conta e região, ou se o item identificado pela chave primária que você inseriu não existir, um [ResourceNotFoundException](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/model/ResourceNotFoundException.html)será lançado.

 **Importações** 

```
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;
```

 **Código** 

```
  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);
        }
    }
```

Veja o [exemplo completo](https://github.com/awsdocs/aws-doc-sdk-examples/blob/f4eaf2b2971805cfb2b87a8e5ab408f83169432e/javav2/example_code/dynamodb/src/main/java/com/example/dynamodb/DeleteItem.java) em GitHub.

## Mais informações
<a name="more-information"></a>
+  [Diretrizes para trabalhar com itens](https://docs.aws.amazon.com//amazondynamodb/latest/developerguide/best-practices.html) no Guia do desenvolvedor do Amazon DynamoDB 
+  [Trabalhando com itens DynamoDB no](https://docs.aws.amazon.com//amazondynamodb/latest/developerguide/WorkingWithItems.html) Guia do Amazon DynamoDB desenvolvedor

# Mapeie objetos Java para itens do DynamoDB com o AWS SDK for Java 2.x
<a name="dynamodb-enhanced-client"></a>

A [API do Cliente Aprimorado do DynamoDB](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/package-summary.html) é uma biblioteca de alto nível que é a sucessora da classe `DynamoDBMapper` no SDK para Java v1.x. Ela oferece uma maneira simples de mapear classes do lado do cliente para tabelas do DynamoDB. Basta definir as relações entre as tabelas e suas classes de dados correspondentes no seu código. Depois que você definir essas relações, poderá executar intuitivamente várias operações de criação, leitura, atualização ou exclusão (CRUD) em tabelas ou itens do DynamoDB.

A API do Cliente Aprimorado do DynamoDB também inclui a [API de Documento Aprimorado](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/document/package-summary.html), que permite trabalhar com itens do tipo documento que não seguem um esquema definido. 

**Topics**
+ [Conceitos básicos da API do Cliente Aprimorado do DynamoDB](ddb-en-client-getting-started.md)
+ [Saiba mais sobre os fundamentos da API do cliente avançado do DynamoDB](ddb-en-client-use.md)
+ [Usar recursos avançados de mapeamento](ddb-en-client-adv-features.md)
+ [Trabalhar com documentos JSON com a API de documentos aprimorados do DynamoDB](ddb-en-client-doc-api.md)
+ [Usar extensões para personalizar as operações do Cliente Aprimorado do DynamoDB](ddb-en-client-extensions.md)
+ [Usar a API do cliente avançado do DynamoDB de forma assíncrona](ddb-en-client-async.md)
+ [Anotações de classes de dados](ddb-en-client-anno-index.md)

# Conceitos básicos da API do Cliente Aprimorado do DynamoDB
<a name="ddb-en-client-getting-started"></a>

O tutorial a seguir apresenta os fundamentos necessários para trabalhar com a API do Cliente Aprimorado do DynamoDB.

## Adicionar dependências
<a name="ddb-en-client-gs-dep"></a>

Para começar a trabalhar com a API do Cliente Aprimorado do DynamoDB em seu projeto, adicione uma dependência no artefato `dynamodb-enhanced` do Maven. Essa ação será mostrada nos exemplos a seguir. 

------
#### [ 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>
```

Faça uma pesquisa no repositório central do Maven para obter a [versão mais recente](https://central.sonatype.com/artifact/software.amazon.awssdk/bom) e *<VERSION>* substitua por esse valor.

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

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

Faça uma pesquisa no repositório central do Maven para obter a [versão mais recente](https://central.sonatype.com/artifact/software.amazon.awssdk/bom) e *<VERSION>* substitua por esse valor.

------

# Gerar um `TableSchema` com base em uma classe de dados
<a name="ddb-en-client-gs-tableschema"></a>

O `[TableSchema](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/TableSchema.html)` permite que o cliente avançado mapeie valores de atributos do DynamoDB de e para suas classes do lado do cliente. Neste tutorial, você aprenderá sobre `TableSchema`s derivados de uma classe de dados estática e gerados a partir de código usando um construtor.

## Usar uma classe de dados anotada
<a name="ddb-en-client-gs-tableschema-anno-bean"></a>

O SDK para Java 2.x inclui um [conjunto de anotações](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/mapper/annotations/package-summary.html) que você pode usar com uma classe de dados para gerar um `TableSchema` de modo rápido para mapear suas classes usando tabelas.

Comece criando uma classe de dados que esteja em conformidade com a [JavaBean especificação](https://download.oracle.com/otn-pub/jcp/7224-javabeans-1.01-fr-spec-oth-JSpec/beans.101.pdf). A especificação exige que uma classe tenha um construtor público sem argumentos e que tenha getters e setters para cada atributo na classe. Inclua uma anotação de classe para indicar que a classe de dados é uma `DynamoDbBean`. Além disso, no mínimo, inclua uma anotação `DynamoDbPartitionKey` no getter ou setter do atributo da chave primária. 

É possível aplicar [anotações no nível de atributo](ddb-en-client-anno-index.md) a getters ou setters, mas não a ambos.

**nota**  
O termo normalmente `property` é usado para um valor encapsulado em um. JavaBean No entanto, no lugar desse termo, este guia usa o termo `attribute`, para ser consistente com a terminologia usada pelo DynamoDB.

A classe `Customer` a seguir mostra as anotações que vinculam a definição da classe à tabela do DynamoDB.

### Classe `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 + "]";
    }
}
```

Depois de criar uma classe de dados anotada, use-a para criar o `TableSchema`, como será mostrado no trecho a seguir.

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

Um `TableSchema` é projetado para ser estático e imutável. Normalmente, você pode instanciá-lo no momento do carregamento da classe.

O método de fábrica estático `TableSchema.fromBean()` inspeciona o bean para gerar o mapeamento entre os atributos da classe de dados (propriedades) e os atributos do DynamoDB.

Para ver um exemplo de como trabalhar com um modelo de dados composto por várias classes de dados, consulte a classe `Person` na seção [Trabalhar com atributos que são beans, mapas, listas e conjuntos](ddb-en-client-adv-features-nested.md).

## Usar um construtor
<a name="ddb-en-client-gs-tableschema-builder"></a>

Você pode ignorar o custo da introspecção do bean se definir o esquema da tabela no código. Se você codificar o esquema, sua classe não precisará seguir os padrões de JavaBean nomenclatura nem precisará ser anotada. O exemplo a seguir usa um construtor e é equivalente ao exemplo de classe `Customer` que usa anotações.

```
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();
```

# Criar um cliente aprimorado e uma `DynamoDbTable`
<a name="ddb-en-client-getting-started-dynamodbTable"></a>

## Criar um cliente aprimorado
<a name="ddb-en-client-getting-started-dynamodbTable-eclient"></a>

A [DynamoDbEnhancedClient](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/DynamoDbEnhancedClient.html)classe, ou sua contraparte assíncrona, [DynamoDbEnhancedAsyncClient](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/DynamoDbEnhancedAsyncClient.html), é o ponto de entrada para trabalhar com a API do DynamoDB Enhanced Client.

O cliente aprimorado exige um `[DynamoDbClient](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/DynamoDbClient.html)` padrão para realizar operações. A API oferece duas maneiras de criar uma instância `DynamoDbEnhancedClient`. A primeira opção, mostrada no trecho a seguir, cria um `DynamoDbClient` padrão com configurações padrão retiradas das definições de configuração.

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

Se quiser configurar o cliente padrão subjacente, você poderá fornecê-lo ao método construtor do cliente aprimorado, conforme mostrado no trecho a seguir.

```
// 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();
```

## Criar uma instância `DynamoDbTable`
<a name="ddb-en-client-getting-started-dynamodbTable-table"></a>

Pense em uma [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) como a representação do lado do cliente de uma tabela do DynamoDB que usa a funcionalidade de mapeamento fornecida por um `TableSchema`. A classe `DynamoDbTable` fornece métodos para operações CRUD que permitem que você interaja com uma única tabela do DynamoDB.

`DynamoDbTable<T>` é uma classe genérica que usa um argumento de tipo único, seja uma classe personalizada ou `EnhancedDocument`, ao trabalhar com itens do tipo documento. Esse tipo de argumento estabelece a relação entre a classe que você usa e a tabela única do DynamoDB.

Use o método de fábrica `table()` do `DynamoDbEnhancedClient` para criar uma instância `DynamoDbTable` conforme será mostrado no trecho a seguir.

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

Instâncias `DynamoDbTable` são candidatas a singletons porque são imutáveis e podem ser usadas em toda a sua aplicação.

O código agora tem uma representação na memória de uma tabela do DynamoDB que pode funcionar com instâncias `Customer`. A tabela do DynamoDB pode ou não existir. Se a tabela chamada `Customer` já existir, você poderá começar a realizar operações CRUD nela. Se ela não existir, use a instância `DynamoDbTable` para criar a tabela conforme será discutido na próxima seção.

# Criar uma tabela do DynamoDB se for necessário
<a name="ddb-en-client-gs-ddbtable"></a>

Depois de criar uma instância `DynamoDbTable`, use-a para realizar uma criação *única* de uma tabela no DynamoDB.

## Exemplo de código para criar tabela
<a name="ddb-en-client-gs-ddbtable-createex"></a>

O exemplo a seguir cria uma tabela do DynamoDB com base na classe de dados `Customer`. 

Este exemplo cria uma tabela do DynamoDB com o nome `Customer`, que é idêntico ao nome da classe, mas o nome da tabela pode ser diferente. Seja qual for o nome da tabela, você deverá usar esse nome em aplicativos adicionais para trabalhar com a tabela. Forneça esse nome ao método `table()` sempre que criar outro objeto de `DynamoDbTable` para trabalhar com a tabela subjacente do DynamoDB.

O parâmetro Java lambda, `builder`, passado para o método `createTable`, permite que você [personalize a tabela](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/CreateTableEnhancedRequest.Builder.html). Neste exemplo, o [throughput provisionado](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.ReadWriteCapacityMode.html#HowItWorks.ProvisionedThroughput.Manual) está configurado. Se você quiser usar as configurações padrão ao criar uma tabela, ignore o construtor, conforme mostrado no trecho a seguir.

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

Quando as configurações padrão são usadas, os valores para o throughput provisionado não são definidos. Em vez disso, o modo de faturamento da tabela é definido como [sob demanda](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.ReadWriteCapacityMode.html#HowItWorks.OnDemand).

O exemplo também usa um `[DynamoDbWaiter](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/waiters/DynamoDbWaiter.html)` antes de tentar imprimir o nome da tabela recebida na resposta. A criação de uma tabela leva algum tempo. Portanto, usar um waiter significa que você não precisa escrever uma lógica que pesquise no DynamoDB para ver se a tabela existe antes de usá-la.

### Importações
<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;
```

### Código
<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.");
     }
 }
```

**nota**  
Os nomes dos atributos de uma tabela do DynamoDB começam com uma letra minúscula quando a tabela é gerada a partir de uma classe de dados. Se você quiser que o nome do atributo da tabela comece com uma letra maiúscula, use a [anotação `@DynamoDbAttribute(NAME)`](ddb-en-client-adv-features-inex-attr.md) e forneça o nome desejado como parâmetro.

# Executar operações
<a name="ddb-en-client-gs-use"></a>

Depois que a tabela for criada, use a instância `DynamoDbTable` para realizar operações na tabela do DynamoDB. 

No exemplo a seguir, um singleton `DynamoDbTable<Customer>` é passado como parâmetro junto com uma instância de [classe de dados `Customer`](ddb-en-client-gs-tableschema.md#ddb-en-client-gs-tableschema-anno-bean-cust) para adicionar um novo item à tabela.

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

## Objeto `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"));
```

Antes de enviar o objeto `customer` para o DynamoDB, registre a saída do método `toString()` do objeto para compará-la com o que é enviado pelo cliente aprimorado.

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

O registro em log em nível de conexão mostra a carga útil da solicitação gerada. O cliente aprimorado gerou a representação de nível baixo da classe de dados. O atributo `regDate`, que é um tipo `Instant` em Java, é representado como uma cadeia de caracteres do DynamoDB.

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

# Trabalhar com uma tabela existente
<a name="ddb-en-client-gs-existingtable"></a>

A seção anterior mostrou como criar uma tabela do DynamoDB começando com uma classe de dados Java. Se você já tiver uma tabela existente e quiser usar os atributos do cliente aprimorado, poderá criar uma classe de dados Java para trabalhar com a tabela. Você precisa examinar a tabela do DynamoDB e adicionar as anotações necessárias à classe de dados. 

Antes de trabalhar com uma tabela existente, chame o método `DynamoDbEnhanced.table()`. Isso foi feito no exemplo anterior com a seguinte instrução:

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

Depois que a instância `DynamoDbTable` for retornada, você poderá começar a trabalhar imediatamente com a tabela subjacente. Você não precisa recriar a tabela chamando o método `DynamoDbTable.createTable()`.

O exemplo a seguir demonstra isso recuperando imediatamente uma instância `Customer` da tabela do DynamoDB.

```
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());
```

**Importante**  
O nome da tabela usado no método `table()` deve corresponder ao nome da tabela existente do DynamoDB.

# Saiba mais sobre os fundamentos da API do cliente avançado do DynamoDB
<a name="ddb-en-client-use"></a>

Este tópico discute os atributos básicos da API do Cliente Aprimorado do DynamoDB e a compara com a [API do cliente padrão do DynamoDB](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/package-summary.html).

Se você não conhece a API do Cliente Aprimorado do DynamoDB, recomendamos que leia o [tutorial introdutório](ddb-en-client-getting-started.md) para se familiarizar com as classes fundamentais.

## Itens do DynamoDB em Java
<a name="ddb-en-client-use-usecase"></a>

As tabelas do DynamoDB armazenam itens. Dependendo do seu caso de uso, os itens no lado Java podem assumir a forma de dados estruturados por estatísticas ou estruturas criadas de modo dinâmico. 

Se seu caso de uso exigir itens com um conjunto consistente de atributos, use [classes anotadas](ddb-en-client-gs-tableschema.md#ddb-en-client-gs-tableschema-anno-bean) ou use um [construtor](ddb-en-client-gs-tableschema.md#ddb-en-client-gs-tableschema-builder) para gerar a tipagem estática apropriada `TableSchema`. 

Como alternativa, se você precisar armazenar itens que consistem em estruturas variadas, crie um `DocumentTableSchema`. `DocumentTableSchema` faz parte da [API de Documento Aprimorado](ddb-en-client-doc-api.md) e requer somente uma chave primária digitada estaticamente e funciona com instâncias `EnhancedDocument` para armazenar os elementos de dados. A API de Documento Aprimorado é abordada em outro [tópico.](ddb-en-client-doc-api.md)

## Tipos de atributos para classes de modelo de dados
<a name="ddb-en-client-use-types"></a>

Embora o DynamoDB ofereça suporte a [um pequeno número de tipos de atributos](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.NamingRulesDataTypes.html#HowItWorks.DataTypes) em comparação com o sistema de tipos avançados do Java, a API do Cliente Aprimorado do DynamoDB fornece mecanismos para converter membros de uma classe Java de e para tipos de atributos do DynamoDB.

Os tipos de atributos (propriedades) de suas classes de dados do Java devem ser tipos de objetos, não primitivos. Por exemplo, sempre use tipos de dados de objetos `Long` e `Integer`, não primitivos `long` e `int`.

[Por padrão, a API do DynamoDB Enhanced Client suporta conversores de atributos para um grande número de tipos, [como Integer[,](https://docs.oracle.com/javase/8/docs/api/java/lang/String.html) String](https://docs.oracle.com/javase/8/docs/api/java/lang/Integer.html) e Instant. [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) A lista aparece nas [classes de implementação conhecidas da AttributeConverter interface](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/AttributeConverter.html). A lista inclui muitos tipos e coleções, como mapas, listas e conjuntos.

Para armazenar os dados de um tipo de atributo que não é suportado por padrão ou não está em conformidade com a JavaBean convenção, você pode escrever uma `AttributeConverter` implementação personalizada para fazer a conversão. Consulte a seção de conversão de atributos para ver um [exemplo](ddb-en-client-adv-features-conversion.md#ddb-en-client-adv-features-conversion-example).

Para armazenar os dados de um tipo de atributo cuja classe está em conformidade com a especificação Java Beans (ou uma [classe de dados imutável](ddb-en-client-use-immut.md)), você pode adotar duas abordagens. 
+ Se você tiver acesso ao arquivo de origem, poderá anotar a classe com `@DynamoDbBean` (ou `@DynamoDbImmutable`). A seção que discute atributos aninhados mostra [exemplos](ddb-en-client-adv-features-nested.md#ddb-en-client-adv-features-nested-map-anno) do uso de classes anotadas.
+ Se você não tiver acesso ao arquivo de origem da classe de JavaBean dados do atributo (ou não quiser anotar o arquivo de origem de uma classe à qual você tem acesso), você pode usar a abordagem do construtor. Isso cria um esquema de tabela sem definir as chaves. Em seguida, você pode aninhar esse esquema de tabela dentro de outro esquema de tabela para realizar o mapeamento. A seção de atributos aninhados tem um [exemplo](ddb-en-client-adv-features-nested.md#ddb-en-client-adv-features-nested-map-builder) que mostra o uso de esquemas aninhados.

### Valores nulos
<a name="ddb-en-client-use-types-nulls"></a>

Quando você usa o método `putItem`, o cliente aprimorado não inclui atributos de valor nulo de um objeto de dados mapeado na solicitação ao DynamoDB.

O comportamento padrão do SDK para solicitações `updateItem` remove atributos do item no DynamoDB que estão definidos como nulos no objeto que você envia no método `updateItem`. Se você pretende atualizar alguns valores de atributos e manter os outros inalterados, existem duas opções:
+ Recuperar o item (usando `getItem`) antes de fazer alterações nos valores. Ao usar essa abordagem, o SDK envia todos os valores antigos e atualizados para o DynamoDB.
+ Usar o `[IgnoreNullsMode](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/IgnoreNullsMode.html).SCALAR_ONLY` ou `IgnoreNullsMode.MAPS_ONLY` ao criar a solicitação para atualizar o item. Ambos os modos ignoram propriedades de valor nulo no objeto que representam atributos escalares no DynamoDB. O tópico [Atualizar itens que contêm tipos complexos](ddb-en-client-adv-features-nested.md#ddb-en-client-adv-features-nested-updates) deste guia contém mais informações sobre os valores de `IgnoreNullsMode` e como trabalhar com tipos complexos.

O exemplo a seguir demonstra `ignoreNullsMode()` para o método `updateItem()`.

```
    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]
```

## Métodos básicos do Cliente Aprimorado do DynamoDB
<a name="ddb-en-client-use-basic-ops"></a>

Os métodos básicos do cliente aprimorado mapeiam as operações de serviço do DynamoDB que deram nome a eles. Os exemplos a seguir mostram a variação mais simples de cada método. Você pode personalizar cada método passando um objeto de solicitação aprimorado. Os objetos de solicitação aprimorada oferecem a maioria dos atributos disponíveis no cliente padrão do DynamoDB. Eles estão totalmente documentados na Referência da API do AWS SDK for Java 2.x .

O exemplo usa o [Classe `Customer`](ddb-en-client-gs-tableschema.md#ddb-en-client-gs-tableschema-anno-bean-cust) mostrado anteriormente.

```
// 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));
```

## Comparar o Cliente Aprimorado do DynamoDB com o cliente padrão do DynamoDB
<a name="ddb-en-client-use-compare"></a>

Tanto o APIs cliente DynamoDB [— padrão [quanto](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/package-summary.html) aprimorado —](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/package-summary.html) permitem que você trabalhe com tabelas do DynamoDB para realizar operações CRUD (criar, ler, atualizar e excluir) em nível de dados. A diferença entre o cliente APIs é como isso é feito. Usando o cliente padrão, você trabalha diretamente com atributos de dados de nível baixo. A API do cliente aprimorado usa classes Java conhecidas e mapeia a API de nível baixo nos bastidores.

Embora ambos os clientes ofereçam APIs suporte a operações em nível de dados, o cliente padrão do DynamoDB também oferece suporte a operações em nível de recursos. As operações em nível de recurso gerenciam o banco de dados, como criar backups, listar e atualizar tabelas. A API do cliente aprimorado fornece suporte a um número selecionado de operações em nível de recurso, como criar, descrever e excluir tabelas.

Para ilustrar as diferentes abordagens usadas pelos dois clientes APIs, os exemplos de código a seguir mostram a criação da mesma `ProductCatalog` tabela usando o cliente padrão e o cliente aprimorado.

### Comparar: criar uma tabela usando o cliente do DynamoDB padrão
<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))
);
```

### Comparar: criar uma tabela usando o Cliente Aprimorado do DynamoDB
<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))
        )
);
```

O cliente aprimorado usa a seguinte classe de dados anotada: O Cliente Aprimorado do DynamoDB mapeia tipos de dados Java para tipos de dados do DynamoDB para obter um código menos detalhado e mais fácil de seguir. `ProductCatalog` é um exemplo do uso de uma classe imutável com o Cliente Aprimorado do DynamoDB. O uso de classes imutáveis para classes de dados mapeados será [discutido posteriormente](ddb-en-client-use-immut.md) neste tópico.

### Classe `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);
        }
    }
}
```

Os dois exemplos de código de uma gravação em lote a seguir ilustram a verbosidade e a falta de segurança de tipo ao usar o cliente padrão em vez do cliente aprimorado.

### Comparar: operação de gravação em lote usando o cliente DynamoDB padrão
<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());
    }
```

### Comparar: operação de gravação em lote usando o Cliente Aprimorado do DynamoDB
<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());
    }
```

# Trabalhar com classes de dados imutáveis
<a name="ddb-en-client-use-immut"></a>

O atributo de mapeamento da API do Cliente Aprimorado do DynamoDB funciona com classes de dados imutáveis. Uma classe imutável tem apenas getters e requer uma classe construtora que o SDK usa para criar instâncias da classe. Em vez de usar a anotação `@DynamoDbBean` conforme mostrado na [classe Customer](ddb-en-client-gs-tableschema.md#ddb-en-client-gs-tableschema-anno-bean-cust), as classes imutáveis usam a anotação `@DynamoDbImmutable`, a qual usa um parâmetro que indica a classe do construtor a ser usada.

A classe a seguir é uma versão imutável de `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); }
    }
}
```

Você deve atender aos seguintes requisitos ao anotar uma classe de dados com `@DynamoDbImmutable`.

1. Todo método que não é uma substituição de `Object.class` e não foi anotado com `@DynamoDbIgnore` deve ser um getter de um atributo da tabela do DynamoDB.

1. Cada getter deve ter um setter correspondente com distinção entre maiúsculas e minúsculas na classe builder.

1. Somente uma das seguintes condições de estrutura precisa ser atendida:
   + A classe builder deve ter um construtor padrão público.
   + A classe de dados deve ter um método estático público chamado `builder()` que não usa parâmetros e que retorna uma instância da classe builder. Essa opção é mostrada na classe imutável `Customer`.

1.  A classe builder deve ter um método público chamado `build()` que não use parâmetros e retorne uma instância da classe imutável. 

Para criar um `TableSchema` para sua classe imutável, use o método `fromImmutableClass()` no `TableSchema` conforme mostrado no trecho a seguir.

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

Assim como você pode criar uma tabela do DynamoDB a partir de uma classe mutável, você pode criar uma a partir de uma classe imutável com uma chamada *única* para `createTable()` do `DynamoDbTable` conforme mostrado no exemplo de trecho a seguir.

```
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));
}
```

## Usar bibliotecas de terceiros, como Lombok
<a name="ddb-en-client-use-immut-lombok"></a>

Bibliotecas de terceiros, como [Project Lombok](https://projectlombok.org/), ajudam a gerar código clichê associado a objetos imutáveis. A API do Cliente Aprimorado do DynamoDB funciona com essas bibliotecas, desde que as classes de dados sigam as convenções detalhadas nesta seção. 

O exemplo a seguir mostra a classe `CustomerImmutable` imutável com anotações do Lombok. Observe como o atributo `onMethod` do Lombok copia anotações do DynamoDB baseadas em atributos, como `@DynamoDbPartitionKey`, no código gerado.

```
@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;
}
```

# Usar expressões e condições
<a name="ddb-en-client-expressions"></a>

As expressões na API do Cliente Aprimorado do DynamoDB são representações Java das [expressões do DynamoDB](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.html).

A API do Cliente Aprimorado do DynamoDB usa três tipos de expressões:

[Expressão](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/Expression.html)  
A classe `Expression` é usada quando você define condições e filtros.

[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)  
Esse tipo de expressão representa as [principais condições](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Query.html#Query.KeyConditionExpressions) para operações de consulta.

[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)  
Essa classe ajuda você a escrever [expressões de atualização](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.UpdateExpressions.html) do DynamoDB e é usada atualmente na estrutura de extensão quando você atualiza um item.

## Anatomia da expressão
<a name="ddb-en-client-expressions-compoonents"></a>

Uma expressão é composta do seguinte:
+ Uma expressão em cadeia de caracteres (obrigatório). Uma cadeia de caracteres contém uma expressão lógica do DynamoDB com nomes de espaço reservado para nomes e valores de atributos.
+ Um mapa dos valores da expressão (geralmente obrigatório).
+ Um mapa dos nomes das expressões (opcional).

Use um construtor para gerar um objeto `Expression` que tenha a seguinte forma geral.

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

`Expression`s geralmente exigem um mapa dos valores da expressão. O mapa fornece os valores dos espaços reservados na expressão da cadeia de caracteres. A chave do mapa consiste no nome do espaço reservado precedido por dois pontos (`:`) e o valor do mapa é uma instância de. [AttributeValue](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/model/AttributeValue.html) A [AttributeValues](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/internal/AttributeValues.html)classe tem métodos convenientes para gerar uma `AttributeValue` instância a partir de um literal. Como alternativa, você pode usar o `AttributeValue.Builder` para gerar uma instância `AttributeValue`.

O trecho a seguir mostra um mapa com duas entradas após a linha de comentário 2. A cadeia de caracteres passada para o método `expression()`, mostrada após a linha de comentário 1, contém os espaços reservados que o DynamoDB determina antes de realizar a operação. Esse trecho não contém um mapa dos nomes das expressões, porque *price* é um nome de atributo permissível.

```
    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();
```

Se um nome de atributo na tabela do DynamoDB for uma palavra reservada, começar com um número ou contiver um espaço, um mapa dos nomes das expressões será necessário para a `Expression`.

Por exemplo, se o nome do atributo fosse `1price` em vez de `price` no exemplo de código anterior, o exemplo precisaria ser modificado conforme mostrado no exemplo a seguir.

```
        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();
```

Um espaço reservado para o nome de uma expressão começa com o sinal de libra (`#`). Uma entrada para o mapa de nomes de expressão usa o espaço reservado como chave e o nome do atributo como valor. O mapa é adicionado ao construtor de expressões com o método `expressionNames()`. O DynamoDB resolve o nome do atributo antes de realizar a operação.

Os valores de expressão não são necessários se uma função for usada na expressão da cadeia de caracteres. Um exemplo de função de expressão é `attribute_exists(<attribute_name>)`.

O exemplo a seguir cria uma `Expression` que usa uma [função do DynamoDB](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.OperatorsAndFunctions.html#Expressions.OperatorsAndFunctions.Functions). Uma cadeia de caracteres de expressão neste exemplo não usa espaços reservados. Essa expressão pode ser usada em uma operação `putItem` para verificar se um item já existe no banco de dados com um valor de atributo `movie` igual ao atributo `movie` do objeto de dados.

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

O Guia do desenvolvedor do DynamoDB contém informações completas sobre as expressões[ de nível baixo](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.html) usadas com o DynamoDB.

## Expressões de condição e condicionais
<a name="ddb-en-client-expressions-cond"></a>

Ao usar os métodos `putItem()`, `updateItem()`, `deleteItem()` e também ao usar operações de transação e em lote, você usa objetos de `[Expression](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/Expression.html)` para especificar as condições que o DynamoDB deve atender para continuar com a operação. Essas expressões são chamadas de expressões de condição. Para ver um exemplo, consulte a expressão de condição usada no método `addDeleteItem()` (após a linha de comentário 1) do [exemplo de transação](ddb-en-client-use-multiop-trans.md#ddb-en-client-use-multiop-trans-writeitems-opcondition) mostrado neste guia.

Quando você trabalha com os métodos `query()`, uma condição é expressa como uma [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). A classe `QueryConditional` tem vários métodos estáticos de conveniência que ajudam você a escrever os critérios que determinam quais itens ler no DynamoDB.

Para ver exemplos de `QueryConditionals`, consulte o primeiro exemplo de código da seção [Exemplos de métodos `Query`](ddb-en-client-use-multirecord.md#ddb-en-client-use-multirecord-query-example) deste guia.

## Expressões de filtro
<a name="ddb-en-client-expressions-filter"></a>

As expressões de filtro são usadas em operações de digitalização e consulta para filtrar os itens retornados. 

Uma expressão de filtro é aplicada depois que todos os dados são lidos do banco de dados, de modo que o custo de leitura é o mesmo que se não houvesse filtro. O *Guia do desenvolvedor do Amazon DynamoDB* tem mais informações sobre o uso de expressões de filtro para operações de [consulta](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Query.html#Query.FilterExpression) e [verificação](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Scan.html#Scan.FilterExpression).

O exemplo a seguir mostra uma expressão de filtro adicionada a uma solicitação de verificação. O critério restringe os itens devolvidos a itens com um preço de 8,00 a 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();
```

## Expressões de atualização
<a name="ddb-en-client-expressions-update"></a>

O método `updateItem()` do Cliente Aprimorado do DynamoDB fornece uma forma padrão de atualizar itens no DynamoDB. [No entanto, quando você precisar de mais funcionalidades, [UpdateExpressions](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/update/UpdateExpression.html)forneça uma representação segura da sintaxe da expressão de atualização do DynamoDB.](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.UpdateExpressions.html) Por exemplo, você pode usar `UpdateExpressions` para aumentar valores sem primeiro ler itens do DynamoDB ou adicionar membros individuais a uma lista. Atualmente, as expressões de atualização estão disponíveis em extensões personalizadas para o método `updateItem()`.

Para ver um exemplo que usa expressões de atualização, consulte o [exemplo de extensão personalizada](ddb-en-client-extensions-custom.md) neste guia.

Mais informações sobre expressões de atualização estão disponíveis no [Guia do desenvolvedor do Amazon DynamoDB](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.UpdateExpressions.html).

# Trabalhar com resultados paginados: verificações e consultas
<a name="ddb-en-client-use-multirecord"></a>

Os métodos `scan`, `query` e `batch` da API do Cliente Aprimorado do DynamoDB retornam respostas com uma ou mais *páginas*. Uma página contém um ou mais itens. Seu código pode processar a resposta por página ou pode processar itens individuais.

Uma resposta paginada retornada pelo `DynamoDbEnhancedClient` cliente síncrono retorna um [PageIterable](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/PageIterable.html)objeto, enquanto uma resposta retornada pelo `DynamoDbEnhancedAsyncClient` assíncrono retorna um objeto. [PagePublisher](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/PagePublisher.html)

Esta seção analisa o processamento de resultados paginados e fornece exemplos que usam a verificação e a consulta. APIs

## Verificar uma tabela
<a name="ddb-en-client-use-multirecord-scan"></a>

O método do 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)) corresponde à [operação do DynamoDB](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_Scan.html) com o mesmo nome. A API do Cliente Aprimorado do DynamoDB oferece as mesmas opções, mas usa um modelo de objeto familiar e gerencia a paginação para você.

Primeiro, exploramos a `PageIterable` interface examinando o `scan` método da classe de mapeamento síncrono, [DynamoDbTable](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/DynamoDbTable.html).

### Usar a API síncrona
<a name="ddb-en-client-use-multirecord-scan-sync"></a>

O exemplo a seguir mostra o método `scan` que usa uma [expressão](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/Expression.html) para filtrar os itens retornados. [ProductCatalog](ddb-en-client-use.md#ddb-en-client-use-compare-cs3)É o objeto do modelo que foi mostrado anteriormente.

A expressão de filtragem mostrada após a linha de comentário 2 limita os `ProductCatalog` itens que são retornados àqueles com um valor de preço entre 8,00 e 80,00, inclusive.

Este exemplo também exclui os `isbn` valores usando o `attributesToProject` método mostrado após a linha de comentário 1.

Depois da linha de comentário 3, o objeto `PageIterable`, `pagedResults`, é retornado pelo método `scan`. O método `stream` de `PageIterable` retorna um objeto [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), que você pode usar para processar as páginas. Neste exemplo, o número de páginas é contado e registrado.

Começando com a linha de comentários 4, o exemplo mostra duas variações de acesso aos itens `ProductCatalog`. A versão após a linha de comentário 4a percorre cada página e classifica e registra os itens em cada página. A versão após a linha de comentário 4b ignora a iteração da página e acessa os itens diretamente.

A interface `PageIterable` oferece várias maneiras de processar resultados por causa de suas duas interfaces principais: [https://docs.oracle.com/javase/8/docs/api/java/lang/Iterable.html](https://docs.oracle.com/javase/8/docs/api/java/lang/Iterable.html) e [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). `Iterable` traz os métodos `forEach`, `iterator` e `spliterator`, e `SdkIterable` traz o método `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())
                );
    }
```

### Usar a API assíncrona
<a name="ddb-en-client-use-multirecord-scan-async"></a>

O método `scan` assíncrono retorna os resultados como um objeto `PagePublisher`. A interface `PagePublisher` tem dois métodos `subscribe` que você pode usar para processar páginas de resposta. Um método `subscribe` vem da interface principal `org.reactivestreams.Publisher`. Para processar páginas usando essa primeira opção, transmita uma instância `[Subscriber](https://www.reactive-streams.org/reactive-streams-1.0.0-javadoc/org/reactivestreams/Subscriber.html)` para o método `subscribe`. O primeiro exemplo a seguir mostra o uso do método `subscribe`.

O segundo `subscribe` método vem da [SdkPublisher](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/core/async/SdkPublisher.html)interface. Esta versão de `subscribe` aceita um [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) em vez de um `Subscriber`. Essa variação do método `subscribe` é mostrada no segundo exemplo.

O exemplo a seguir mostra a versão assíncrona do método `scan` que usa a mesma expressão de filtro mostrada no exemplo anterior. 

Após a linha de comentário 3, `DynamoDbAsyncTable.scan` retorna um objeto `PagePublisher`. Na próxima linha, o código cria uma instância da interface `org.reactivestreams.Subscriber`, `ProductCatalogSubscriber`, que assina a `PagePublisher` após o comentário na linha 4.

O objeto `Subscriber` coleta os itens `ProductCatalog` de cada página no método `onNext` após a linha de comentário 8 no exemplo da classe `ProductCatalogSubscriber`. Os itens são armazenados na varável `List` privada e acessados no código de chamada com o método `ProductCatalogSubscriber.getSubscribedItems()`. A chamado é feita após a linha de comentários 5.

Depois que a lista é recuperada, o código classifica todos os itens `ProductCatalog` por preço e registra cada item.

O [CountDownLatch](https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/CountDownLatch.html)in the `ProductCatalogSubscriber` class bloqueia o tópico de chamada até que todos os itens tenham sido adicionados à lista antes de continuar após a linha de comentários 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;
        }
    }
```

O exemplo de trecho a seguir usa a versão do método `PagePublisher.subscribe` que aceita um `Consumer` após a linha de comentário 6. O parâmetro lambda em Java consome páginas, que processam ainda mais cada item. Neste exemplo, cada página é processada e os itens em cada página são classificados e, em seguida, registrados.

```
        // 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.
```

O método `items` do `PagePublisher` desempacota as instâncias do modelo para que seu código possa processar os itens diretamente. Essa abordagem é mostrada no trecho a seguir.

```
        // 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.
```

## Consultar uma tabela
<a name="ddb-en-client-use-multirecord-query"></a>

É possível usar o Cliente Aprimorado do DynamoDB para consultar sua tabela e recuperar vários itens que correspondam a critérios específicos. O método [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)) encontra itens com base nos valores da chave primária usando as anotações `@DynamoDbPartitionKey` e, opcionalmente, `@DynamoDbSortKey` definidas em sua classe de dados.

O método `query()` requer um valor de chave de partição e, opcionalmente, aceita condições de chave de classificação para refinar ainda mais os resultados. Assim como a API `scan`, as consultas retornam um `PageIterable` para chamadas síncronas e um `PagePublisher` para chamadas assíncronas.

### Exemplos de métodos `Query`
<a name="ddb-en-client-use-multirecord-query-example"></a>

O exemplo de código do método `query()` a seguir usa a classe `MovieActor`. A classe de dados define uma chave primária composta constituída pelo atributo **`movie`** como a chave de partição e pelo atributo **`actor`** como a chave de classificação. 

#### Classe `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);
        }
    }
}
```

Os exemplos de código a seguir são consultados com base nos itens a seguir.

#### Itens na tabela `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'}
```

O código a seguir define duas instâncias `QueryConditional`: `keyEqual` (após a linha de comentário 1) e `sortGreaterThanOrEqualTo` (após a linha de comentário 1a).

#### Consultar itens por chave de partição
<a name="keyEqual-query-conditional-example"></a>

A instância `keyEqual` combina itens com um valor de chave de partição de **`movie01`**. 

Esse exemplo também define uma expressão de filtro após a linha de comentário 2 que filtra qualquer item que não tenha um valor **`actingschoolname`**.

O `QueryEnhancedRequest` combina a condição da chave e a expressão do filtro para a consulta.

```
    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 – Saída usando a consulta condicional `keyEqual`**  
Esta é a saída gerada pela execução do método. A saída exibe itens com um valor `movieName` de **movie01** e não exibe nenhum item com `actingSchoolName` igual a **`null`**.  

```
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'}
```

#### Consultar itens por chave de partição e chave de classificação
<a name="sort-type-query-conditional-example"></a>

O `sortGreaterThanOrEqualTo` `QueryConditional` refina uma correspondência de chave de partição (**movie01**) adicionando uma condição de chave de classificação para valores maiores ou iguais a **actor2**.

Os [métodos `QueryConditional`](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/QueryConditional.html) que começam com `sort` exigem que o valor da chave de partição corresponda e refinam ainda mais a consulta por meio de uma comparação com base no valor da chave de classificação. `Sort` no nome do método não significa que os resultados estão classificados, mas que um valor de chave de classificação será usado para comparação.

No trecho a seguir, alteramos a solicitação de consulta mostrada anteriormente após a linha de comentário 3. Esse trecho substitui a condicional de consulta “KeyEqual” pela condicional de consulta "sortGreaterThanOrEqualTo" que foi definida após a linha de comentário 1a. O código a seguir também remove a expressão do filtro.

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

**Example – Saída usando a consulta condicional `sortGreaterThanOrEqualTo`**  
A saída a seguir exibe os resultados da consulta. A consulta retorna itens que têm um valor `movieName` igual a **movie01** e somente itens que têm um valor `actorName` maior ou igual a **actor2**. Como removemos o filtro, a consulta retorna itens que não têm valor para o atributo `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'}
```

# Realizar operações em lote
<a name="ddb-en-client-use-multiop-batch"></a>

A API do Cliente Aprimorado do DynamoDB oferece dois métodos em lote, [`batchGetItem`()](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/DynamoDbEnhancedClient.html#batchGetItem(java.util.function.Consumer)) e [`batchWriteItem`()](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/DynamoDbEnhancedClient.html#batchWriteItem(java.util.function.Consumer)).

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

Com o método [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)), você pode recuperar até 100 itens individuais em várias tabelas com uma solicitação geral. O exemplo a seguir usa as classes de dados [`Customer`](ddb-en-client-gs-tableschema.md#ddb-en-client-gs-tableschema-anno-bean-cust) e [`MovieActor`](ddb-en-client-use-multirecord.md#ddb-en-client-use-movieactor-class) mostradas anteriormente.

No exemplo após as linhas 1 e 2, você cria objetos `[ReadBatch](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/ReadBatch.html)` que são adicionados posteriormente como parâmetros ao método `batchGetItem()` após a linha de comentário 3. 

O código após a linha de comentário 1 cria o lote para ser lido na tabela `Customer`. O código após a linha de comentário 1a mostra o uso de um compilador `[GetItemEnhancedRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/GetItemEnhancedRequest.Builder.html)` que usa um valor de chave primária e um valor de chave de classificação para especificar o item a ser lido. Se a classe de dados tiver uma chave composta, você deverá fornecer o valor da chave de partição e o valor da chave de classificação. 

Ao contrário de especificar valores-chave para solicitar um item, você pode usar uma classe de dados para solicitar um item, conforme mostrado após a linha de comentário 1b. O SDK extrai os valores-chave nos bastidores antes de enviar a solicitação.

Ao especificar o item usando a abordagem baseada em chaves, conforme mostrado nas duas instruções após 2a, você também pode especificar que o DynamoDB deve realizar uma [leitura altamente consistente](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.ReadConsistency.html). Quando o método `consistentRead()` é usado, ele deve ser usado em todos os itens solicitados para a mesma tabela.

Para recuperar os itens encontrados pelo DynamoDB, use o método `[resultsForTable() ](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/BatchGetResultPage.html#resultsForTable(software.amazon.awssdk.enhanced.dynamodb.MappedTableResource))` mostrado após a linha de comentário 4. Chame o método para cada tabela que foi lida na solicitação. `resultsForTable()` retorna uma lista de itens encontrados que você pode processar usando qualquer método `java.util.List`. Este exemplo registra cada item.

Para descobrir itens que o DynamoDB não processou, use a abordagem após a linha de comentários 5. A classe `BatchGetResultPage` tem o método `[unprocessedKeysForTable()](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/BatchGetResultPage.html#unprocessedKeysForTable(software.amazon.awssdk.enhanced.dynamodb.MappedTableResource))` que dá acesso a cada chave que não foi processada. A [referência BatchGetItem da API](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_BatchGetItem.html) tem mais informações sobre situações que resultam em itens não processados.

```
    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()));
        });
    }
```

Suponha que os itens a seguir estejam nas duas tabelas antes de executar o código de exemplo.

### Itens em tabelas
<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'}
```

A saída a seguir mostra os itens retornados e registrados após a linha de comentários 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'}
```

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

O método `batchWriteItem()` coloca ou exclui vários itens em uma ou mais tabelas. Você pode especificar até 25 operações individuais de colocação ou exclusão na solicitação. O exemplo a seguir usa as classes modelo [`ProductCatalog`](ddb-en-client-use.md#ddb-en-client-use-compare-cs3) e [`MovieActor`](ddb-en-client-use-multirecord.md#ddb-en-client-use-movieactor-class) mostradas anteriormente.

Os objetos `WriteBatch` são construídos após as linhas de comentário 1 e 2. Para a tabela `ProductCatalog`, o código coloca um item e exclui um item. Para a tabela `MovieActor` após a linha de comentário 2, o código coloca dois itens e exclui um.

O método `batchWriteItem` é chamado após a linha de comentário 3. O parâmetro `[builder](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/BatchWriteItemEnhancedRequest.Builder.html)` fornece as solicitações em lote para cada tabela.

O objeto `[BatchWriteResult](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/BatchWriteResult.html)` retornado fornece métodos separados para cada operação para visualizar solicitações não processadas. O código após a linha de comentário 4a fornece as chaves para solicitações de exclusão não processadas e o código após a linha de comentário 4b fornece os itens de venda não processados.

```
    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()));
        }
    }
```

Os métodos auxiliares a seguir fornecem os objetos de modelo para as operações colocar e excluir.

### Métodos auxiliares
<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.     }
```

Suponha que as tabelas contenham os itens a seguir antes de você executar o código de exemplo.

```
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}
```

Depois que o código de exemplo for concluído, as tabelas conterão os itens a seguir.

```
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}
```

Observe na tabela `MovieActor` que o item do filme `Blue Jasmine` foi substituído pelo item usado na solicitação de colocação adquirida por meio do método `getMovieActorBlanchettPartial()` auxiliar. Se um valor de atributo do bean de dados não tiver sido fornecido, o valor no banco de dados será removido. É por isso que o resultado `actingSchoolName` é nulo para o item do filme `Blue Jasmine`.

**nota**  
Embora a documentação da API sugira que expressões de condição possam ser usadas e que a capacidade consumida e as métricas de coleta possam ser retornadas com solicitações individuais de [colocar](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/PutItemEnhancedRequest.html) e [excluir](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/DeleteItemEnhancedRequest.html), esse não é o caso em um cenário de gravação em lote. Para melhorar o desempenho das operações em lote, essas opções individuais são ignoradas.

# Realizar operações de transação
<a name="ddb-en-client-use-multiop-trans"></a>

A API do Cliente Aprimorado do DynamoDB fornece o `transactGetItems()` e os métodos `transactWriteItems()`. Os métodos de transação do SDK para Java fornecem atomicidade, consistência, isolamento e durabilidade (ACID) nas tabelas do DynamoDB, ajudando você a manter a correção dos dados em suas aplicações.

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

O método `[transactGetItems()](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/DynamoDbEnhancedClient.html#transactGetItems(java.util.function.Consumer))` aceita até 100 solicitações individuais de itens. Todos os itens são lidos em uma única transação atômica. O *Guia do desenvolvedor do Amazon DynamoDB* tem informações sobre as [condições que causam a falha do método `transactGetItems()`](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/transaction-apis.html#transaction-apis-txgetitems) e também sobre o nível de isolamento usado ao chamar `[transactGetItem()](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/transaction-apis.html#transaction-isolation)`.

Depois da linha de comentário 1 no exemplo a seguir, o código chama o método `transactGetItems()` com um parâmetro `[builder](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/TransactGetItemsEnhancedRequest.Builder.html)`. O `[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))` do construtor é chamado três vezes com um objeto de dados contendo os valores-chave que o SDK usará para gerar a solicitação final.

A solicitação retorna uma lista de objetos `[Document](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/Document.html)` após a linha de comentário 2. A lista de documentos que é retornada contém instâncias de [Documentos](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/Document.html) não nulas dos dados do item na mesma ordem solicitada. O método `[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))` converte um objeto não digitado em um objeto `Document` Java digitado se os dados do item forem retornados, caso contrário, o método retornará nulo.

```
    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());
        }
    }
```

As tabelas do DynamoDB contêm os seguintes itens antes da execução do exemplo de código.

```
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'}
```

A saída a seguir é registrada. Se um item for solicitado, mas não encontrado, ele não será retornado, como é o caso da solicitação do filme nomeado `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'}
```

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

O `[transactWriteItems()](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/DynamoDbEnhancedClient.html#transactWriteItems(java.util.function.Consumer))` aceita até 100 ações de colocar, atualizar ou excluir em uma única transação atômica em várias tabelas. O *Guia do desenvolvedor do Amazon DynamoDB *contém detalhes sobre restrições e condições de falha da [operação do serviço subjacente do DynamoDB](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/transaction-apis.html#transaction-apis-txwriteitems).

### Exemplo básico
<a name="ddb-en-client-use-multiop-trans-writeitems-basic"></a>

No exemplo a seguir, quatro operações são solicitadas para duas tabelas. As classes de modelo correspondentes [`ProductCatalog`](ddb-en-client-use.md#ddb-en-client-use-compare-cs3) e [`MovieActor`](ddb-en-client-use-multirecord.md#ddb-en-client-use-movieactor-class) foram mostradas anteriormente.

Cada uma das três operações possíveis: colocar, atualizar e excluir usa um parâmetro de solicitação dedicado para especificar os detalhes. 

O código após a linha de comentário 1 mostra a variação simples do método `addPutItem()`. O método aceita um objeto `[MappedTableResource](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/MappedTableResource.html)` e a instância do objeto de dados onde colocar. A declaração após a linha de comentário 2 mostra a variação que aceita uma instância `[TransactPutItemEnhancedRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/TransactPutItemEnhancedRequest.html)`. Essa variação permite adicionar mais opções na solicitação, como uma expressão de condição. Um [exemplo](#ddb-en-client-use-multiop-trans-writeitems-opcondition) subsequente mostra uma expressão de condição para uma operação individual.

Uma operação de atualização é solicitada após a linha de comentários 3. `[TransactUpdateItemEnhancedRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/TransactUpdateItemEnhancedRequest.Builder.html)` tem um método `ignoreNulls()` que permite configurar o que o SDK faz com os valores `null` no objeto modelo. Se o método `ignoreNulls()` retornar true, o SDK não removerá os valores dos atributos da tabela para os atributos do objeto de dados que são `null`. Se o método `ignoreNulls()` retornar false, o SDK solicitará que o serviço do DynamoDB remova os atributos do item na tabela. O valor padrão para `ignoreNulls` é false.

A afirmação após a linha de comentário 4 mostra a variação de uma solicitação de exclusão que usa um objeto de dados. O cliente aprimorado extrai os valores-chave antes de enviar a solicitação final.

```
    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())
        );
    }
```

Os métodos auxiliares a seguir fornecem os objetos de dados para os parâmetros `add*Item`.

#### Métodos auxiliares
<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;
    }
```

As tabelas do DynamoDB contêm os seguintes itens antes da execução do exemplo de código.

```
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'}
```

Os itens a seguir estão nas tabelas após a conclusão da execução do código.

```
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'}
```

O item na linha 2 foi excluído e as linhas 3 e 5 mostram os itens que foram colocados. A linha 4 mostra a atualização da linha 1. O valor `price` é o único valor que foi alterado no item. Se `ignoreNulls()` tivesse retornado false, a linha 4 ficaria como a seguinte linha:

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

### Exemplo de verificação de condição
<a name="ddb-en-client-use-multiop-trans-writeitems-checkcond"></a>

O exemplo a seguir mostra o uso de uma verificação de condição. Uma verificação de condição é usada para verificar se um item existe ou para verificar a condição de atributos específicos de um item no banco de dados. O item verificado na verificação de condição não pode ser usado em outra operação na transação.

**nota**  
Você não pode visar o mesmo item com várias operações dentro da mesma transação. Por exemplo, você não pode executar uma verificação de condição e também tentar atualizar o item na mesma transação.

O exemplo mostra um tipo de cada operação em uma solicitação transacional de itens de gravação. Depois da linha de comentário 2, o método `addConditionCheck()` fornece a condição que falha na transação se o parâmetro `conditionExpression` for avaliado como `false`. A expressão de condição que é retornada do método mostrado no bloco de métodos auxiliares verifica se o ano de premiação do filme `Sophie's Choice` não é igual a `1982`. Se for igual, a expressão será avaliada como `false` e a transação falhará.

Este guia discutirá [expressões](ddb-en-client-expressions.md) em profundidade em outro tópico.

```
    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());
            });
        }
    }
```

Os métodos auxiliares a seguir são usados no exemplo de código anterior.

#### Métodos auxiliares
<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;
    }
```

As tabelas do DynamoDB contêm os seguintes itens antes da execução do exemplo de código.

```
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'}
```

Os itens a seguir estão nas tabelas após a conclusão da execução do código.

```
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'}
```

Os itens permanecem inalterados nas tabelas porque a transação falhou. O valor `actingYear` do filme `Sophie's Choice` é `1982`, conforme mostrado na linha 2 dos itens na tabela antes da chamada do método `transactWriteItem()`.

Para capturar as informações de cancelamento da transação, inclua a chamada do método `transactWriteItems()` em um bloco `try` e `catch` o [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). Depois da linha de comentário 4 do exemplo, o código registra cada objeto `[CancellationReason](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/model/CancellationReason.html)`. Como o código após a linha de comentário 3 do exemplo especifica que os valores devem ser retornados para o item que causou a falha da transação, o registro exibe os valores brutos do banco de dados do item do filme `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.)
```

### Exemplo de condição de operação única
<a name="ddb-en-client-use-multiop-trans-writeitems-opcondition"></a>

O exemplo a seguir mostra o uso de uma condição em uma única operação em uma solicitação de transação. A operação de exclusão após a linha de comentário 1 contém uma condição que verifica o valor do item de destino da operação em relação ao banco de dados. Neste exemplo, a expressão de condição criada com o método auxiliar após a linha de comentário 2 especifica que o item deve ser excluído do banco de dados se o ano de atuação do filme não for igual a 2013.

As [expressões](ddb-en-client-expressions.md) serão discutidas posteriormente neste guia.

```
    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();
    }
```

Os métodos auxiliares a seguir são usados no exemplo de código anterior.

#### Métodos auxiliares
<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;
    }
```

As tabelas do DynamoDB contêm os seguintes itens antes da execução do exemplo de código.

```
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'}
```

Os itens a seguir estão nas tabelas após a conclusão da execução do código.

```
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'}
```

Os itens permanecem inalterados nas tabelas porque a transação falhou. O valor `actingYear` do filme `Blue Jasmine` é `2013` como mostrado na linha 2 da lista de itens antes da execução do código de exemplo.

As linhas a seguir são registradas no console.

```
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)
```

# Usar índices secundários
<a name="ddb-en-client-use-secindex"></a>

Os índices secundários melhoram o acesso aos dados definindo chaves alternativas que você usa nas operações de consulta e verificação. Índices secundários globais (GSI) têm uma chave de partição e uma chave de classificação que podem ser diferentes daquelas contidas na tabela base. Por outro lado, os índices secundários locais (LSI) usam a chave de partição do índice primário.

## Anotar a classe de dados com anotações de índice secundário
<a name="ddb-en-client-use-secindex-annomodel"></a>

Os atributos que participam de índices secundários exigem a anotação `@DynamoDbSecondaryPartitionKey` ou `@DynamoDbSecondarySortKey`.

A classe a seguir mostra anotações para dois índices. O GSI nomeado *SubjectLastPostedDateIndex*usa o `Subject` atributo para a chave de partição e o `LastPostedDateTime` para a chave de classificação. O LSI nomeado *ForumLastPostedDateIndex*usa o `ForumName` como chave de partição e `LastPostedDateTime` como chave de classificação.

Observe que o atributo `Subject` tem uma função dupla. É a chave de classificação da chave primária e a chave de partição do GSI nomeado *SubjectLastPostedDateIndex*.

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

A classe `MessageThread` é adequada para ser usada como uma classe de dados para a [tabela Thread de exemplo](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/AppendixSampleTables.html) no *Guia de desenvolvedor do Amazon DynamoDB*.

#### Importações
<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 +
                '}';
    }
}
```

## Criar o índice
<a name="ddb-en-client-use-secindex-confindex"></a>

A partir da versão 2.20.86 do SDK para Java, o método `createTable()` gera automaticamente índices secundários a partir de anotações de classes de dados. Por padrão, todos os atributos da tabela base são copiados para um índice e os valores de throughput provisionados são 20 unidades de capacidade de leitura e 20 unidades de capacidade de gravação.

No entanto, se você usar uma versão do SDK anterior à 2.20.86, precisará criar o índice junto com a tabela, conforme mostrado no exemplo a seguir. Este exemplo cria os dois índices para a tabela `Thread`. O parâmetro [builder](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/CreateTableEnhancedRequest.Builder.html) tem métodos para configurar os dois tipos de índices, conforme mostrado após as linhas de comentário 1 e 2. Você usa o método `indexName()` do construtor de índices para associar os nomes de índice especificados nas anotações da classe de dados ao tipo de índice pretendido.

Esse código configura todos os atributos da tabela para terminam nos dois índices após as linhas de comentário 3 e 4. Mais informações sobre [projeções de atributos](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/LSI.html#LSI.Projections) estão disponíveis no *Guia do desenvolvedor do 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))
                )
        );
```

## Consultar usando um índice
<a name="ddb-en-client-use-secindex-query"></a>

O exemplo a seguir consulta o índice secundário local *ForumLastPostedDateIndex*.

Seguindo a linha de comentário 2, você cria um [QueryConditional](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/QueryConditional.html)objeto que é necessário ao chamar o método [DynamoDbIndex.query ()](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/DynamoDbIndex.html#query(java.util.function.Consumer)). 

Você obtém uma referência ao índice que deseja consultar após a linha de comentário 3 ao passar o nome do índice. Seguindo a linha de comentário 4, você chama o método `query()` no índice que passa o objeto `QueryConditional`. 

Você também configura a consulta para retornar três valores de atributos, conforme mostrado após a linha de comentário 5. Se `attributesToProject()` não for chamado, a consulta retornará todos os valores dos atributos. Observe que os nomes dos atributos especificados começam com letras minúsculas. Esses nomes de atributos correspondem aos usados na tabela, não necessariamente aos nomes dos atributos da classe de dados.

Seguindo a linha de comentário 6, revise os resultados e registre cada item retornado pela consulta e os armazene na lista para retornar ao chamador.

```
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;
    }
```

Os itens a seguir existem no banco de dados antes da execução da consulta.

```
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}
```

As instruções de registro nas linhas 1 e 6 resultam na seguinte saída do console:

```
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}
```

A consulta retornou itens com um valor `forumName` de *Forum02* e um valor `lastPostedDateTime` maior ou igual a *2023.03.31*. Os resultados mostram valores `message` com uma cadeia de caracteres vazia, embora os atributos `message` tenham valores no índice. Isso ocorre porque o atributo da mensagem não foi projetado pelo código após a linha de comentário 5. 

# Usar recursos avançados de mapeamento
<a name="ddb-en-client-adv-features"></a>

Saiba mais sobre os atributos avançados do esquema de tabelas na API do Cliente Aprimorado do DynamoDB.

## Entender os tipos de esquema de tabela
<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)` é a interface para a funcionalidade de mapeamento da API do Cliente Aprimorado do DynamoDB. Ele pode mapear um objeto de dados de e para um mapa de [AttributeValues](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/model/AttributeValue.html). Um objeto `TableSchema` precisa conhecer a estrutura da tabela que está mapeando. Essas informações de estrutura são armazenadas em um objeto [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).

A API de cliente aprimorado tem várias implementações de `TableSchema`, conforme será visto a seguir. 

### Esquema de tabela gerado a partir de classes anotadas
<a name="ddb-en-client-adv-features-schema-mapped"></a>

Criar uma `TableSchema` a partir de classes anotadas é uma operação moderadamente dispendiosa, portanto, recomendamos fazer isso uma vez, na inicialização do aplicativo.

 [ BeanTableSchema ](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/mapper/BeanTableSchema.html)   
Essa implementação é construída com base nos atributos e anotações de uma classe de bean. Um exemplo dessa abordagem é demonstrado na [seção Conceitos básicos](ddb-en-client-gs-tableschema.md#ddb-en-client-gs-tableschema-anno-bean).  
Se uma `BeanTableSchema` não estiver se comportando conforme o esperado, habilite o registro de depuração para `software.amazon.awssdk.enhanced.dynamodb.beans`.

[ImmutableTableSchema](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/mapper/ImmutableTableSchema.html)  
Essa implementação é criada a partir de uma classe de dados imutável. Esse método é descrito na seção [Trabalhar com classes de dados imutáveis](ddb-en-client-use-immut.md).

### Esquema de tabela gerado com um construtor
<a name="ddb-en-client-adv-features-schema-static"></a>

As seguintes `TableSchema`s são criadas a partir do código usando um construtor. Essa abordagem é menos dispendiosa do que a abordagem que usa classes de dados anotadas. A abordagem do construtor evita o uso de anotações e não exige JavaBean padrões de nomenclatura.

[StaticTableSchema](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/mapper/StaticTableSchema.html)  
Essa implementação foi criada para classes de dados mutáveis. A seção de introdução deste guia demonstrou como [gerar uma `StaticTableSchema` usando um construtor](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)  
Da mesma forma que você cria um `StaticTableSchema`, você gera uma implementação desse tipo de `TableSchema` usando um [construtor](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/mapper/StaticImmutableTableSchema.html) para uso com classes de dados imutáveis.

### Esquema de tabela para dados sem um esquema fixo
<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)  
Ao contrário de outras implementações de `TableSchema`, você não define atributos para uma instância `DocumentTableSchema`. Normalmente, você especifica somente chaves primárias e provedores de conversão de atributos. Uma instância `EnhancedDocument` fornece os atributos que você cria a partir de elementos individuais ou de uma cadeia de caracteres JSON.

# Inclua ou exclua atributos explicitamente
<a name="ddb-en-client-adv-features-inex-attr"></a>

A API do Cliente Aprimorado do DynamoDB oferece anotações para impedir que atributos da classe de dados se tornem atributos em uma tabela. Com a API, você também pode usar um nome de atributo diferente do nome do atributo da classe de dados.

## Excluir atributos
<a name="ddb-en-client-adv-features-inex-attr-ex"></a>

Para ignorar atributos que não devem ser mapeados para uma tabela do DynamoDB, marque o atributo com a anotação `@DynamoDbIgnore`.

```
private String internalKey;

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

## Incluir atributos
<a name="ddb-en-client-adv-features-inex-attr-in"></a>

Para alterar o nome de um atributo usado na tabela do DynamoDB, marque-o com a anotação `@DynamoDbAttribute` e forneça um nome diferente.

```
private String internalKey;

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

# Conversão de atributo de controle
<a name="ddb-en-client-adv-features-conversion"></a>

Por padrão, um esquema de tabela fornece conversores para muitos tipos comuns de Java por meio de uma implementação padrão da interface `[AttributeConverterProvider](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/AttributeConverterProvider.html)`. Você pode alterar o comportamento padrão geral com uma implementação `AttributeConverterProvider` personalizada. Você também pode alterar o conversor para um único atributo.

Para obter uma lista dos conversores disponíveis, consulte a [AttributeConverter](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/AttributeConverter.html)interface Java doc.

## Forneça provedores de conversão de atributos personalizados
<a name="ddb-en-client-adv-features-conversion-prov"></a>

Você pode fornecer um único `AttributeConverterProvider` ou uma cadeia de `AttributeConverterProvider`s ordenados por meio da anotação `@DynamoDbBean` `(converterProviders = {…})`. Qualquer personalização do `AttributeConverterProvider` deve estender a interface do `AttributeConverterProvider`.

Observe que, se fornecer sua própria cadeia de provedores de conversão de atributos, você substituirá o provedor de conversão padrão, `DefaultAttributeConverterProvider`. Se quiser usar a funcionalidade do `DefaultAttributeConverterProvider`, você deverá incluí-la na cadeia. 

Também é possível anotar o bean com uma matriz vazia `{}`. Isso desativa o uso de qualquer provedor de conversão de atributos, incluindo o padrão. Nesse caso, todos os atributos a serem mapeados devem ter seu próprio conversor de atributos.

O trecho a seguir mostra um único provedor de conversor.

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

}
```

O trecho a seguir mostra o uso de uma cadeia de provedores de conversores. Como o SDK padrão é fornecido por último, ele tem a menor prioridade.

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

}
```

Os criadores de esquemas de tabelas estáticas têm um método `attributeConverterProviders()` que funciona da mesma maneira. Isso é mostrado no trecho a seguir.

```
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();
```

## Substituir o mapeamento de um único atributo
<a name="ddb-en-client-adv-features-conversion-single"></a>

Para substituir a forma como um único atributo é mapeado, forneça um `AttributeConverter` para o atributo. Essa adição substitui todos os conversores fornecidos pelo `AttributeConverterProviders` no esquema da tabela. A ação adiciona um conversor personalizado somente para esse atributo. Outros atributos, mesmo aqueles do mesmo tipo, não usarão esse conversor, a menos que ele seja explicitamente especificado para esses outros atributos.

A anotação `@DynamoDbConvertedBy` é usada para especificar a classe `AttributeConverter` personalizada, conforme mostrado no trecho a seguir.

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

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

Os construtores de esquemas estáticos têm um método construtor de atributos `attributeConverter()` equivalente. Esse método usa uma instância de um `AttributeConverter`, conforme mostrado a seguir.

```
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();
```

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

Este exemplo mostra uma implementação `AttributeConverterProvider` que fornece um conversor de atributos para objetos [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). 

A classe `SimpleUser` a seguir contém um atributo chamado `lastUsedCookie` que é uma instância de `HttpCookie`.

O parâmetro para as anotações `@DynamoDbBean` lista as duas classes `AttributeConverterProvider` que fornecem conversores.

------
#### [ 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();
```

------

O `CookieConverterProvider` no exemplo a seguir fornece uma instância de um `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);
        }
    }
```

### Código de conversão
<a name="ddb-en-client-adv-features-conversion-example-code"></a>

No método `transformFrom()` da classe `HttpCookieConverter` a seguir, o código recebe uma instância `HttpCookie` e a transforma em um mapa do DynamoDB que é armazenado como um atributo.

O método `transformTo()` recebe um parâmetro de mapa do DynamoDB e, em seguida, invoca o construtor `HttpCookie` que exige um nome e um valor.

```
    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;
        }
    }
```

# Alterar o comportamento de atualização dos atributos
<a name="ddb-en-client-adv-features-upd-behavior"></a>

Você pode personalizar o comportamento de atualização de atributos individuais ao realizar uma operação de *atualização*. [Alguns exemplos de operações de atualização na API de cliente aprimorada do DynamoDB [são updateItem](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/DynamoDbTable.html#updateItem(T)) () e (). transactWriteItems](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/DynamoDbEnhancedClient.html#transactWriteItems(java.util.function.Consumer))

Por exemplo, imagine que você queira armazenar um carimbo de data/hora *criado em* seu registro. No entanto, você deseja que o valor seja gravado somente se ainda não houver nenhum valor existente para o atributo no banco de dados. Nesse caso, você usa o comportamento de atualização `[WRITE\$1IF\$1NOT\$1EXISTS](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/mapper/UpdateBehavior.html#WRITE_IF_NOT_EXISTS)`.

O exemplo a seguir mostra a anotação que adiciona o comportamento ao atributo `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; }
}
```

Você pode declarar o mesmo comportamento de atualização ao criar um esquema de tabela estática, conforme mostrado no exemplo a seguir após a linha de comentário 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();
```

# Nivelar atributos de outras classes
<a name="ddb-en-client-adv-features-flatmap"></a>

Se os atributos da sua tabela estiverem espalhados por várias classes Java diferentes, seja por herança ou composição, a API do Cliente Aprimorado do DynamoDB fornece suporte para nivelar os atributos em uma classe.

## Usar herança
<a name="ddb-en-client-adv-features-flatmap-inheritance"></a>

Se suas classes usam herança, use as seguintes abordagens para nivelar a hierarquia.

### Usar beans anotados
<a name="ddb-en-client-adv-features-flatmap-inheritance-anno"></a>

Para a abordagem de anotação, ambas as classes devem conter a anotação `@DynamoDbBean` e uma classe deve conter uma ou mais anotações de chave primária.

Veja a seguir exemplos de classes de dados que têm uma relação de herança.

------
#### [ 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 ]

A [opção `onMethod`](https://projectlombok.org/features/experimental/onX) do Lombok copia anotações do DynamoDB baseadas em atributos, como `@DynamoDbPartitionKey`, no código gerado.

```
@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;
}
```

------

### Usar esquemas estáticos
<a name="ddb-en-client-adv-features-flatmap-inheritance-static"></a>

Para a abordagem do esquema estático, use o método `extend()` do construtor para reduzir os atributos da classe principal para a classe secundária. Isso é mostrado depois da linha de comentário 1 no seguinte exemplo:

```
        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();
```

O exemplo anterior do esquema estático usa as seguintes classes de dados: Uma vez que o mapeamento é definido quando você cria o esquema de tabela estática, as classes de dados não exigem anotações.

#### Classes de dados
<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;
}
```

------

## Usar composição
<a name="ddb-en-client-adv-features-flatmap-comp"></a>

Se suas classes usam composição, use as seguintes abordagens para nivelar a hierarquia.

### Usar beans anotados
<a name="ddb-en-client-adv-features-flatmap-comp-anno"></a>

A anotação `@DynamoDbFlatten` nivela a classe contida.

Os exemplos de classes de dados a seguir usam a anotação `@DynamoDbFlatten` para adicionar efetivamente todos os atributos da classe `GenericRecord` contida à classe `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;
}
```

------

Você pode usar a anotação de nivelamento para nivelar quantas classes elegíveis forem necessárias. As limitações a seguir aplicam-se:
+ Todos os nomes de atributos devem ser exclusivos depois de serem nivelados.
+ Nunca deve haver mais de uma chave de partição, chave de classificação ou nome de tabela.

### Usar esquemas estáticos
<a name="ddb-en-client-adv-features-flatmap-comp-static"></a>

Ao criar um esquema de tabela estático, use o método `flatten()` do construtor. Você também fornece os métodos getter e setter que identificam a classe contida.

```
        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();
```

O exemplo anterior do esquema estático usa as seguintes classes de dados:

#### Classes de dados
<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;
}
```

------

Você pode usar o padrão do construtor para nivelar quantas classes elegíveis forem necessárias.

## Implicações para outro código
<a name="ddb-en-client-adv-features-flatmap-compare"></a>

Quando você usa o atributo `@DynamoDbFlatten` (ou método `flatten()` do construtor), o item no DynamoDB contém um atributo para cada atributo do objeto composto. Isso também inclui os atributos do objeto de composição. 

Por outro lado, se você anotar uma classe de dados com uma classe composta e não usar `@DynamoDbFlatten`, o item será salvo com o objeto composto como um único atributo.

Por exemplo, compare a classe `Customer` mostrada no [exemplo de nivelamento com composição](#ddb-en-client-adv-features-flatmap-comp-anno) com e sem nivelamento do atributo `record`. Você pode visualizar a diferença com JSON conforme mostrado na tabela a seguir.


****  

| Com nivelamento | Sem nivelamento | 
| --- | --- | 
| 3 atributos | 2 atributos | 
|  <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>  | 

A diferença se torna importante se você tiver outro código acessando a tabela do DynamoDB que espera encontrar certos atributos.

# Trabalhar com atributos que são beans, mapas, listas e conjuntos
<a name="ddb-en-client-adv-features-nested"></a>

Uma definição de bean, como a classe `Person` mostrada abaixo, pode definir propriedades (ou atributos) que se referem a tipos com atributos adicionais. Por exemplo, na classe `Person`, `mainAddress` é uma propriedade que se refere a um bean `Address` que define atributos de valor adicionais. `addresses` refere-se a um mapa Java, cujos elementos se referem a beans `Address`. Esses tipos complexos podem ser considerados contêineres de atributos simples que você usa como valor de dados no contexto do DynamoDB. 

O DynamoDB se refere às propriedades de valor de elementos aninhados, como mapas, listas ou beans, como *atributos aninhados*. O [Guia do desenvolvedor do Amazon DynamoDB](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.NamingRulesDataTypes.html#HowItWorks.DataTypes) se refere à forma salva de um mapa, lista ou bean Java como um *tipo de documento*. Os atributos simples que você usa como valor de dados em Java são chamados de *tipos escalares* no DynamoDB. Conjuntos, que contêm vários elementos escalares do mesmo tipo e chamados de *tipos de conjuntos*. 

É importante saber que a API do Cliente Aprimorado do DynamoDB converte uma propriedade que é bean em um tipo de documento de mapa do DynamoDB quando é salva.

## Classe `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 +
               '}';
    }
}
```

## Classe `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 + '\'' +
                '}';
    }
}
```

## Classe `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 + '\'' +
                '}';
    }
}
```

## Salvar tipos complexos
<a name="ddb-en-client-adv-features-nested-mapping"></a>

### Usar classes de dados anotadas
<a name="ddb-en-client-adv-features-nested-map-anno"></a>

Salve atributos aninhados para classes personalizadas simplesmente fazendo anotações neles. A classe `Address` e a classe `PhoneNumber` mostradas anteriormente são anotadas somente com a anotação `@DynamoDbBean`. Quando a API do Cliente Aprimorado do DynamoDB cria o esquema de tabela para a classe `Person` com o seguinte trecho, a API descobre o uso das classes `Address` e `PhoneNumber` e cria os mapeamentos correspondentes para funcionar com o DynamoDB.

```
TableSchema<Person> personTableSchema = TableSchema.fromBean(Person.class);
```

### Usar esquemas abstratos com compiladores
<a name="ddb-en-client-adv-features-nested-map-builder"></a>

A abordagem alternativa é usar compiladores de esquemas de tabelas estáticas para cada classe de bean aninhada, conforme mostrado no código a seguir.

Os esquemas de tabela das classes `Address` e `PhoneNumber` são abstratos, uma vez que não podem ser usados com uma tabela do DynamoDB. Isso ocorre porque eles não têm definições para a chave primária. No entanto, eles são usados como esquemas aninhados no esquema de tabela da classe `Person`.

Depois de comentar as linhas 1 e 2 na definição de `PERSON_TABLE_SCHEMA`, você vê o código que usa os esquemas de tabela abstrata. O uso de `documentOf` no método `EnhanceType.documentOf(...)` não indica que o método retorne um tipo `EnhancedDocument` da API de documento aprimorado. O método `documentOf(...)` nesse contexto retorna um objeto que sabe como mapear seu argumento de classe de e para os atributos da tabela do DynamoDB usando o argumento do esquema da tabela.

#### Código de esquema estático
<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();
```

## Atributos de projeto de tipos complexos
<a name="ddb-en-client-adv-features-nested-projection"></a>

Para os métodos `query()` e `scan()`, você pode especificar quais atributos você deseja que sejam retornados nos resultados usando chamadas de método como `addNestedAttributeToProject()` e `attributesToProject()`. A API do Cliente Aprimorado do DynamoDB converte os parâmetros de chamada do método Java em [expressões de projeção](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.ProjectionExpressions.html) antes do envio da solicitação.

O exemplo a seguir preenche a tabela `Person` com dois itens e, em seguida, executa três operações de verificação. 

A primeira verificação acessa todos os itens da tabela para comparar os resultados com as outras operações de verificação. 

A segunda verificação usa o método do construtor [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)) para retornar somente o valor do atributo `street`.

A terceira operação de varredura usa o método do construtor [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...)) para retornar os dados do atributo de primeiro nível, `hobbies`. O tipo do atributo de `hobbies` é uma lista. Para acessar itens individuais da lista, execute uma operação `get()` na lista.

```
        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
```

**nota**  
Se o método `attributesToProject()` seguir qualquer outro método do construtor que adiciona atributos que você deseja projetar, a lista de nomes de atributos fornecida ao `attributesToProject()` substitui todos os outros nomes de atributos.  
Uma verificação realizada com a instância `ScanEnhancedRequest` no trecho a seguir retorna somente dados de hobby.  

```
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]}
```
O trecho de código a seguir usa o método `attributesToProject()` primeiro. Essa ordenação preserva todos os outros atributos obrigatórios.  

```
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]}
```

## Usar tipos complexos em expressões
<a name="ddb-en-client-adv-features-nested-expressions"></a>

É possível usar tipos complexos em expressões, como expressões de filtro e expressões condicionais, usando operadores de desreferenciamento para navegar pela estrutura do tipo complexo. Para objetos e mapas, use `. (dot)` e para elementos da lista use `[n]` (colchetes ao redor do número de sequência do elemento). Não é possível se referir a elementos individuais de um conjunto, mas você pode usar a [função `contains`](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.OperatorsAndFunctions.html#Expressions.OperatorsAndFunctions.Functions).

O exemplo a seguir mostra duas expressões de filtro usadas em operações de varredura. As expressões de filtro especificam as condições de correspondência dos itens que você deseja nos resultados. O exemplo usa as classes `Person`, `Address` e `PhoneNumber` mostradas anteriormente.

```
    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");
    }
```

### Método auxiliar que preenche a tabela
<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);
    }
```

### Representação JSON de itens no banco de dados
<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"
  }
 ]
}
```

## Atualizar itens que contêm tipos complexos
<a name="ddb-en-client-adv-features-nested-updates"></a>

Para atualizar um item que contém tipos complexos, você tem duas abordagens básicas:
+ Abordagem 1: primeiro recupere o item (usando `getItem`), atualize o objeto e, depois, chame `DynamoDbTable#updateItem`.
+ Abordagem 2: não recupere o item, mas construa uma nova instância, defina as propriedades que você deseja atualizar e envie a instância para `DynamoDbTable#updateItem` definindo o valor apropriado de [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). Essa abordagem não exige que você busque o item antes de atualizá-lo.

Os exemplos mostrados nesta seção usam as classes `Person`, `Address` e `PhoneNumber` mostradas anteriormente.

### Abordagem de atualização 1: recuperar e, depois, atualizar
<a name="ddb-en-client-adv-features-nested-updates-retreive"></a>

Ao usar essa abordagem, você garante que nenhum dado seja perdido na atualização. A API do Cliente Aprimorado do DynamoDB recria o bean com os atributos do item salvo no DynamoDB, incluindo valores de tipos complexos. Depois, você precisa usar os getters e setters para atualizar o bean. A desvantagem dessa abordagem é o custo em que você incorre ao recuperar o item primeiro.

O exemplo a seguir demonstra que nenhum dado será perdido se você recuperar o item antes de atualizá-lo.

```
    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;
    }
```

### Abordagem de atualização 2: use uma enumeração `IgnoreNullsMode` sem recuperar o item primeiro
<a name="ddb-en-client-adv-features-nested-updates-nullmode"></a>

Para atualizar um item no DynamoDB, é possível fornecer um novo objeto que tenha somente as propriedades que você deseja atualizar e deixar os outros valores como nulos. Com essa abordagem, você precisa estar ciente de como os valores nulos no objeto são tratados pelo SDK e como controlar o comportamento.

Para especificar quais propriedades de valor nulo você deseja que o SDK ignore, forneça uma enumeração `IgnoreNullsMode` ao criar o [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). Como exemplo do uso de um dos valores enumerados, o trecho a seguir usa o modo `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"
    }
  }
*/
```

O Guia do desenvolvedor do Amazon DynamoDB contém mais informações sobre [expressões de atualização](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.UpdateExpressions.html).

#### Descrições das opções `IgnoreNullsMode`
<a name="ignore-nulls-mode-descriptions"></a>
+ `IgnoreNullsMode.SCALAR_ONLY`: use essa configuração para atualizar atributos escalares em qualquer nível. O SDK cria uma declaração de atualização que envia somente atributos escalares não nulos para o DynamoDB. O SDK ignora os atributos escalares de valor nulo de um bean ou mapa, mantendo o valor salvo no DynamoDB.

  Quando você atualiza um atributo escalar de map ou bean, o mapa já deve existir no DynamoDB. Se adicionar um mapa ou um bean ao objeto que ainda não existe para o objeto no DynamoDB, você receberá uma `DynamoDbException` com a mensagem *O caminho do documento fornecido na expressão de atualização é inválido para atualização*. Você deve usar o modo `MAPS_ONLY` para adicionar um bean ou um mapa ao DynamoDB antes de atualizar qualquer um de seus atributos.
+ `IgnoreNullsMode.MAPS_ONLY`: use essa configuração para adicionar ou substituir propriedades que são um bean ou um mapa. O SDK substitui ou adiciona qualquer mapa ou bean fornecido no objeto. Todos os beans ou mapas que são nulos no objeto são ignorados, mantendo o mapa que existe no DynamoDB.
+ `IgnoreNullsMode.DEFAULT`: com essa configuração, o SDK nunca ignora valores nulos. Os atributos escalares em qualquer nível que sejam nulos são atualizados para nulos. O SDK atualiza qualquer bean, mapa, lista ou propriedade de conjunto com valor nulo no objeto para nulo no DynamoDB. Quando você usa esse modo, ou não informa nenhum modo, já que ele é o padrão, é recomendável recuperar o item antes. Isso evita que valores existentes no DynamoDB sejam substituídos por nulo devido aos valores nulos presentes no objeto usado para a atualização, a menos que a sua intenção seja realmente definir esses valores como nulos.

Em todos os modos, se você fornecer um objeto `updateItem` que tenha uma lista ou conjunto não nulo, a lista ou o conjunto será salvo no DynamoDB. 

#### Por que os modos?
<a name="ddb-en-client-adv-features-nested-updates-nullmodes-why"></a>

Quando você fornece um objeto com um bean ou um mapa para o `updateItem` método, o SDK não sabe se deve usar os valores das propriedades no bean (ou os valores de entrada no mapa) para atualizar o item ou se o todo bean/map deve substituir o que foi salvo no DynamoDB.

Trabalhando com nosso exemplo anterior, que mostra primeiro a recuperação do item, vamos tentar atualizar o atributo `city` de `mainAddress` sem a recuperação.

```
/* 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'.
*/
```

Os dois exemplos a seguir mostram os usos dos valores `MAPS_ONLY` e `SCALAR_ONLY` enumerados. `MAPS_ONLY` adiciona um mapa e `SCALAR_ONLY` atualiza um mapa.

##### Exemplo de `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.
    }
```

Consulte na tabela a seguir quais valores nulos são ignorados em cada modo. Muitas vezes, você pode trabalhar com `SCALAR_ONLY` e `MAPS_ONLY`, exceto quando trabalha com beans ou mapas.


**Quais propriedades de valor nulo no objeto enviado para `updateItem` o SDK ignora em cada modo?**  

| Tipo de propriedade | no modo SCALAR\$1ONLY | no modo MAPS\$1ONLY | no modo DEFAULT | 
| --- | --- | --- | --- | 
| Escalar superior | Sim | Sim | Não | 
| Bean ou mapa | Sim | Sim | Não | 
| Valor escalar de uma entrada de bean ou mapa | Sim1 | Número2 | Não | 
| Listar ou definir | Sim | Sim | Não | 

1Isso pressupõe que o mapa já exista no DynamoDB. Qualquer valor escalar, seja nulo ou não, do bean ou mapa que você fornece no objeto para atualização exige que exista um caminho para o valor no DynamoDB. O SDK constrói um caminho para o atributo usando o operador de desreferenciação `. (dot)` antes de enviar a solicitação.

2Como você usa o modo `MAPS_ONLY` para substituir totalmente ou adicionar um bean ou mapa, todos os valores nulos no bean ou no mapa são retidos no mapa salvo no DynamoDB.

# Preservar objetos vazios com `@DynamoDbPreserveEmptyObject`
<a name="ddb-en-client-adv-features-empty"></a>

Se você salvar um bean no Amazon DynamoDB com objetos vazios e quiser que o SDK recrie os objetos vazios após a recuperação, anote o getter do bean interno com `@DynamoDbPreserveEmptyObject`.

Para ilustrar como a anotação funciona, o exemplo de código usa os dois beans a seguir.

## Exemplos de beans
<a name="ddb-en-client-adv-features-empty-ex1"></a>

A classe de dados a seguir contém dois campos `InnerBean`. O método getter, `getInnerBeanWithoutAnno()`, não é anotado com `@DynamoDbPreserveEmptyObject`. O método `getInnerBeanWithAnno()` é anotado.

```
@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();
    }
}
```

As instâncias da classe `InnerBean` a seguir são campos de `MyBean` e são inicializadas como objetos vazios no código de exemplo.

```
@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 + '\'' +
                '}';
    }
}
```

O exemplo de código a seguir salva um objeto `MyBean` com beans internos inicializados no DynamoDB e, em seguida, recupera o item. A saída registrada mostra que o `innerBeanWithoutAnno` não foi inicializado, mas `innerBeanWithAnno` foi criado.

```
    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;
    }
```

## Esquema estático alternativo
<a name="ddb-en-client-adv-features-empty-ex1-static"></a>

Você pode usar a seguinte versão `StaticTableSchema` dos esquemas de tabela no lugar das anotações nos beans.

```
    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();
    }
```

# Evitar salvar atributos nulos de objetos aninhados
<a name="ddb-en-client-adv-features-ignore-null"></a>

Você pode ignorar atributos nulos de objetos aninhados ao salvar um objeto de classe de dados no DynamoDB aplicando a anotação `@DynamoDbIgnoreNulls`. Por outro lado, atributos de nível superior com valores nulos nunca são salvos no banco de dados.

Para ilustrar como a anotação funciona, o exemplo de código usa os dois beans a seguir.

## Exemplos de beans
<a name="ddb-en-client-adv-features-ignore-null-ex1"></a>

A classe de dados a seguir contém dois campos `InnerBean`. O método getter, `getInnerBeanWithoutAnno()`, não é anotado. O método `getInnerBeanWithIgnoreNullsAnno()` é anotado com `@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();
    }
}
```

As instâncias da classe `InnerBean` a seguir são campos de `MyBean` e são usadas no código de exemplo a seguir.

```
@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();
    }
}
```

O exemplo de código a seguir cria um objeto `InnerBean` e define somente um de seus dois atributos com um valor. 

```
    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);
    }
```

Para visualizar os dados de nível baixo enviados ao DynamoDB, o código registra o mapa de atributos antes de salvar o objeto `MyBean`.

A saída registrada mostra que `innerBeanWithIgnoreNullsAnno` gera um atributo,

```
innerBeanWithIgnoreNullsAnno=AttributeValue(M={innerBeanFieldInteger=AttributeValue(N=200)})
```

A instância `innerBeanWithoutAnno` gera dois atributos. Um atributo tem um valor de 200 e o outro é um atributo de valor nulo.

```
innerBeanWithoutAnno=AttributeValue(M={innerBeanFieldInteger=AttributeValue(N=200), innerBeanFieldString=AttributeValue(NUL=true)})
```

## Representação JSON do mapa de atributo
<a name="ddb-en-client-adv-features-ignore-null-ex2"></a>

A representação JSON a seguir facilita a visualização dos dados salvos no DynamoDB.

```
{
  "id": {
    "S": "1"
  },
  "innerBeanWithIgnoreNullsAnno": {
    "M": {
      "innerBeanFieldInteger": {
        "N": "200"
      }
    }
  },
  "innerBeanWithoutAnno": {
    "M": {
      "innerBeanFieldInteger": {
        "N": "200"
      },
      "innerBeanFieldString": {
        "NULL": true
      }
    }
  }
}
```

## Esquema estático alternativo
<a name="ddb-en-client-adv-features-empty-ex1-static"></a>

Você pode usar a seguinte versão `StaticTableSchema` dos esquemas de tabela nas anotações da classe de dados no local.

```
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();
}
```

# Trabalhar com documentos JSON com a API de documentos aprimorados do DynamoDB
<a name="ddb-en-client-doc-api"></a>

A [API de documentos aprimorada](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/document/package-summary.html) para foi AWS SDK for Java 2.x projetada para funcionar com dados orientados a documentos que não têm um esquema fixo. No entanto, ela também permite que você use classes personalizadas para mapear atributos individuais.

 A API de documentos aprimorada é a sucessora da [API de documentos](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/dynamodbv2/document/DynamoDB.html) da AWS SDK para Java v1.x.

**Contents**
+ [Começar a usar a API de documentos aprimorados](ddb-en-client-doc-api-steps.md)
  + [Criar um `DocumentTableSchema` e uma `DynamoDbTable`](ddb-en-client-doc-api-steps.md#ddb-en-client-doc-api-steps-createschema)
+ [Criar documentos aprimorados](ddb-en-client-doc-api-steps-create-ed.md)
  + [Criar a partir de uma cadeia de caracteres JSON](ddb-en-client-doc-api-steps-create-ed.md#ddb-en-client-doc-api-steps-create-ed-fromJson)
  + [Criar a partir de elementos individuais](ddb-en-client-doc-api-steps-create-ed.md#ddb-en-client-doc-api-steps-create-ed-fromparts)
+ [Executar operações de CRUD](ddb-en-client-doc-api-steps-use.md)
+ [Acessar atributos do documento aprimorado como objetos personalizados](ddb-en-client-doc-api-convert.md)
+ [Usar um `EnhancedDocument` sem o DynamoDB](ddb-en-client-doc-api-standalone.md)

# Começar a usar a API de documentos aprimorados
<a name="ddb-en-client-doc-api-steps"></a>

A API de Documento Aprimorado exige as mesmas [dependências](ddb-en-client-getting-started.md#ddb-en-client-gs-dep) necessárias para a API do Cliente Aprimorado do DynamoDB. Ela também requer uma [instância `DynamoDbEnhancedClient`](ddb-en-client-getting-started-dynamodbTable.md#ddb-en-client-getting-started-dynamodbTable-eclient), conforme mostrado no início deste tópico.

Como a API de documentos aprimorada foi lançada com a versão 2.20.3 do AWS SDK for Java 2.x, você precisa dessa versão ou superior.

## Criar um `DocumentTableSchema` e uma `DynamoDbTable`
<a name="ddb-en-client-doc-api-steps-createschema"></a>

Para invocar comandos em uma tabela do DynamoDB usando a Enhanced Document API, associe a tabela a um objeto de recurso < > do lado do [DynamoDbTablecliente EnhancedDocument](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/DynamoDbTable.html). 

O método `table()` do cliente aprimorado cria uma instância `DynamoDbTable<EnhancedDocument>` e exige parâmetros para o nome da tabela do DynamoDB e uma `DocumentTableSchema`. 

O construtor de um [DocumentTableSchema](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/document/DocumentTableSchema.html)requer uma chave de índice primária e um ou mais provedores de conversão de atributos. O método `AttributeConverterProvider.defaultProvider()` fornece conversores para [tipos padrão](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/internal/converter/attribute/package-summary.html). Ele deve ser especificado mesmo se você fornecer um provedor de conversão de atributos personalizado. Você pode adicionar uma chave de índice secundária opcional ao construtor.

O trecho de código a seguir mostra o código que gera a representação do lado do cliente de uma tabela `person` do DynamoDB que armazena objetos `EnhancedDocument` sem esquema.

```
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.
```

Veja a seguir a representação JSON de um objeto `person` usado em toda esta seção.

### Objeto 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"
    }
  ]
}
```

# Criar documentos aprimorados
<a name="ddb-en-client-doc-api-steps-create-ed"></a>

Um `[EnhancedDocument](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/document/EnhancedDocument.html)` representa um objeto do tipo documento que tem uma estrutura complexa com atributos aninhados. Um `EnhancedDocument` requer atributos de nível superior que correspondam aos atributos da chave primária especificados para o `DocumentTableSchema`. O conteúdo restante é arbitrário e pode consistir em atributos de nível superior e também em atributos profundamente aninhados.

Você cria uma instância `EnhancedDocument` usando um construtor que fornece várias maneiras de adicionar elementos.

## Criar a partir de uma cadeia de caracteres JSON
<a name="ddb-en-client-doc-api-steps-create-ed-fromJson"></a>

Com uma cadeia de caracteres JSON, você pode criar um `EnhancedDocument` com uma chamada do método. O trecho a seguir cria um `EnhancedDocument` a partir de uma cadeia de caracteres JSON retornada pelo método auxiliar `jsonPerson()`. O método `jsonPerson()` retorna a versão da cadeia de caracteres JSON do [objeto person](ddb-en-client-doc-api-steps.md#ddb-en-client-doc-api-steps-createschema-obj) mostrado anteriormente.

```
EnhancedDocument document = 
        EnhancedDocument.builder()
                        .json( jsonPerson() )
                        .build());
```

## Criar a partir de elementos individuais
<a name="ddb-en-client-doc-api-steps-create-ed-fromparts"></a>

Como alternativa, você pode criar uma instância `EnhancedDocument` a partir de componentes individuais usando métodos seguros de tipo do construtor.

O exemplo a seguir cria um documento aprimorado `person` semelhante ao documento aprimorado criado a partir da cadeia de caracteres JSON no exemplo anterior.

```
        /* 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();
```

### Métodos auxiliares
<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"));

    }
```

# Executar operações de CRUD
<a name="ddb-en-client-doc-api-steps-use"></a>

Depois que definir uma instância `EnhancedDocument`, você poderá salvá-la em uma tabela do DynamoDB. O trecho de código a seguir usa o [personDocument](ddb-en-client-doc-api-steps-create-ed.md#ddb-en-client-doc-api-steps-create-ed-fromparts) que foi criado a partir de elementos individuais.

```
documentDynamoDbTable.putItem(personDocument);
```

Depois de ler uma instância de documento aprimorado a partir do DynamoDB, você pode extrair os valores dos atributos individuais usando getters, conforme mostrado no trecho de código a seguir, que acessam os dados salvos do `personDocument`. Como alternativa, você pode extrair o conteúdo completo em uma cadeia de caracteres JSON, conforme mostrado na última parte do código de exemplo.

```
        // 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`as instâncias podem ser usadas com qualquer método de `[DynamoDbTable](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/DynamoDbTable.html)` ou [DynamoDbEnhancedClient](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/DynamoDbEnhancedClient.html)no lugar de classes de dados mapeadas.

# Acessar atributos do documento aprimorado como objetos personalizados
<a name="ddb-en-client-doc-api-convert"></a>

Além de fornecer uma API para ler e gravar atributos com estruturas sem esquemas, a API de Documento Aprimorado permite converter atributos de e para instâncias de classes personalizadas.

A API de Documento Aprimorado usa `AttributeConverterProvider`s e `AttributeConverter`s que foram mostrados na seção de [conversão de atributos de controle](ddb-en-client-adv-features-conversion.md) como parte da API do Cliente Aprimorado do DynamoDB.

No exemplo a seguir, usamos um `CustomAttributeConverterProvider` com sua classe `AddressConverter` aninhada para converter objetos `Address`. 

Este exemplo mostra que você pode misturar dados de classes e também dados de estruturas que são criadas conforme necessário. Esse exemplo também mostra que classes personalizadas podem ser usadas em qualquer nível de uma estrutura aninhada. Os objetos `Address` neste exemplo são valores usados em um mapa.

```
    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'}
```

## Código `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;
        }
    }
}
```

## Classe `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;
                  }
                  }
```

## Método auxiliar que fornece endereços
<a name="ddb-en-client-doc-api-convert-helper"></a>

O método auxiliar a seguir fornece o mapa que usa instâncias `Address` personalizadas para valores em vez de instâncias `Map<String, String>` genéricas para valores.

```
    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);
    }
```

# Usar um `EnhancedDocument` sem o DynamoDB
<a name="ddb-en-client-doc-api-standalone"></a>

Embora você geralmente use uma instância de um `EnhancedDocument` para ler e gravar itens do tipo documento do DynamoDB, ela também pode ser usada independentemente do DynamoDB. 

Você pode usar `EnhancedDocuments` pela sua capacidade de converter desde cadeias de caracteres JSON ou objetos personalizados a mapas de nível baixo de `AttributeValues`, conforme mostrado no exemplo a seguir.

```
    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'}
   */
```

**nota**  
Ao usar um documento aprimorado independente de uma tabela do DynamoDB, defina explicitamente os provedores de conversão de atributos no construtor.  
Por outro lado, o esquema da tabela de documentos fornece os provedores de conversão quando um documento aprimorado é usado com uma tabela do DynamoDB.

# Usar extensões para personalizar as operações do Cliente Aprimorado do DynamoDB
<a name="ddb-en-client-extensions"></a>

A API do Cliente Aprimorado do DynamoDB fornece suporte a extensões de complemento que fornecem funcionalidades além das operações de mapeamento. As extensões usam dois métodos de hook para modificar dados durante as operações de leitura e gravação:
+ `beforeWrite()`: modifica uma operação de gravação antes que ela aconteça
+ `afterRead()`: modifica os resultados de uma operação de leitura depois que ela acontece

Algumas operações (como atualizações de itens) realizam uma gravação e depois uma leitura, então os dois métodos de hook são chamados.

## Como as extensões são carregadas
<a name="ddb-en-client-extensions-loading"></a>

As extensões são carregadas na ordem em que você especifica no compilador do cliente aprimorado. A ordem de carregamento pode ser importante porque uma extensão pode atuar em valores que foram transformados por uma extensão anterior.

Por padrão, o cliente aprimorado carrega duas extensões:
+ `[VersionedRecordExtension](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/extensions/VersionedRecordExtension.html)`: proporciona um bloqueio positivo
+ `[AtomicCounterExtension](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/extensions/AtomicCounterExtension.html)`: incrementa automaticamente os atributos do contador

Você pode substituir o comportamento padrão com o compilador de cliente aprimorado e carregar qualquer extensão. Você também pode especificar nenhuma se não quiser as extensões padrão.

**Importante**  
Se você carregar suas próprias extensões, o cliente aprimorado não carregará nenhuma extensão padrão. Se você quiser o comportamento fornecido por uma extensão padrão, precisará adicioná-la explicitamente à lista de extensões.

O exemplo a seguir mostra como carregar uma extensão personalizada chamada `verifyChecksumExtension` depois de `VersionedRecordExtension`. A `AtomicCounterExtension` não está carregada neste exemplo.

```
DynamoDbEnhancedClientExtension versionedRecordExtension = VersionedRecordExtension.builder().build();

DynamoDbEnhancedClient enhancedClient = 
    DynamoDbEnhancedClient.builder()
                          .dynamoDbClient(dynamoDbClient)
                          .extensions(versionedRecordExtension, verifyChecksumExtension)
                          .build();
```

## Detalhes e configuração da extensão disponível
<a name="ddb-en-client-extensions-details"></a>

As seções a seguir fornecem informações detalhadas sobre cada extensão disponível no SDK.

### Implementar um bloqueio positivo com o `VersionedRecordExtension`
<a name="ddb-en-client-extensions-VRE"></a>

A extensão `VersionedRecordExtension` fornece bloqueio positivo incrementando e rastreando um número de versão do item à medida que os itens são gravados no banco de dados. É adicionada uma condição a cada operação de gravação que faz com que ela falhe caso o número de versão do item armazenado não corresponda ao valor que a aplicação leu por último.

#### Configuração
<a name="ddb-en-client-extensions-VRE-conf"></a>

Para especificar qual atributo usar para rastrear o número da versão do item, marque um atributo numérico no esquema da tabela.

O trecho a seguir especifica que o atributo `version` deve conter o número da versão do item.

```
    @DynamoDbVersionAttribute
    public Integer getVersion() {...};
    public void setVersion(Integer version) {...};
```

A abordagem equivalente do esquema de tabela estática é mostrada no trecho a seguir.

```
    .addAttribute(Integer.class, a -> a.name("version")
                                       .getter(Customer::getVersion)
                                       .setter(Customer::setVersion)
                                        // Apply the 'version' tag to the attribute.
                                       .tags(VersionedRecordExtension.AttributeTags.versionAttribute())
```

#### Como funciona
<a name="ddb-en-client-extensions-VRE-how-it-works"></a>

O bloqueio positivo com a `VersionedRecordExtension` tem o seguinte impacto sobre estes métodos `DynamoDbEnhancedClient` e `DynamoDbTable`:

**`putItem`**  
Novos itens recebem um valor de versão inicial de 0. Isso pode ser configurado com `@DynamoDbVersionAttribute(startAt = X)`.

**`updateItem`**  
Se você recuperar um item, atualizar uma ou mais das suas propriedades e tentar salvar as alterações, a operação será bem-sucedida somente se o número de versão no lado do cliente e no lado do servidor corresponder.  
Se for bem-sucedida, o número da versão é incrementado automaticamente em 1. Isso pode ser configurado com `@DynamoDbVersionAttribute(incrementBy = X)`.

**`deleteItem`**  
A anotação `DynamoDbVersionAttribute` não tem efeito. Você deve adicionar uma expressão de condição manualmente ao excluir um item.  
O exemplo a seguir adiciona uma expressão condicional para garantir que o item excluído seja o que foi lido. No exemplo a seguir, `recordVersion` é o atributo do bean anotado com `@DynamoDbVersionAttribute`.  

```
// 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`: esse método tem o mesmo comportamento de `putItem`.
+ `addUpdateItem`: esse método tem o mesmo comportamento de `updateItem`.
+ `addDeleteItem`: esse método tem o mesmo comportamento de `deleteItem`.

**`batchWriteItem`**  
+ `addPutItem`: esse método tem o mesmo comportamento de `putItem`.
+ `addDeleteItem`: esse método tem o mesmo comportamento de `deleteItem`.

**nota**  
As tabelas globais do DynamoDB usam uma [reconciliação do tipo “o último a gravar vence”](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/V2globaltables_HowItWorks.html#V2globaltables_HowItWorks.consistency-modes) entre as atualizações simultâneas. Com ela, o DynamoDB faz o melhor esforço para determinar o último a gravar. Se você usa tabelas globais, essa política de “o último a gravar vence” significa que as estratégias de bloqueio podem não funcionar conforme o esperado, pois todas as réplicas acabarão por convergir com base na última gravação determinada pelo DynamoDB. 

#### Como desabilitar
<a name="ddb-en-client-extensions-VRE-how-to-disable"></a>

Para desabilitar o bloqueio positivo, não use a anotação `@DynamoDbVersionAttribute`.

### Implementar contadores com a `AtomicCounterExtension`
<a name="ddb-en-client-extensions-ACE"></a>

A extensão `AtomicCounterExtension` incrementa um atributo numérico marcado sempre que um registro é gravado no banco de dados. É possível especificar valores de início e de incremento. Se nenhum valor for especificado, o valor inicial será definido como 0 e o valor do atributo será incrementado em 1.

#### Configuração
<a name="ddb-en-client-extensions-ACE-conf"></a>

Para especificar qual atributo é um contador, marque um atributo do tipo `Long` no esquema da tabela.

O trecho a seguir mostra o uso dos valores padrão de início e de incremento para o atributo `counter`.

```
    @DynamoDbAtomicCounter
    public Long getCounter() {...};
    public void setCounter(Long counter) {...};
```

A abordagem do esquema de tabela estática é mostrada no trecho a seguir. A extensão do contador atômico usa um valor inicial de 10 e incrementa o valor em 5 cada vez que o registro é gravado.

```
    .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))
```

### Adicionar carimbos de data e hora com a `AutoGeneratedTimestampRecordExtension`
<a name="ddb-en-client-extensions-AGTE"></a>

A extensão `AutoGeneratedTimestampRecordExtension` atualiza automaticamente os atributos marcados do tipo `[Instant](https://docs.oracle.com/javase/8/docs/api/java/time/Instant.html)` com um carimbo de data e hora atual sempre que o item é gravado com sucesso no banco de dados. Essa extensão não é carregada por padrão.

#### Configuração
<a name="ddb-en-client-extensions-AGTE-conf"></a>

Para especificar qual atributo atualizar com o carimbo de data/hora atual, marque o atributo `Instant` no esquema da tabela.

O atributo `lastUpdate` é o alvo do comportamento da extensão no trecho a seguir. Observe a exigência de que o atributo seja um tipo `Instant`.

```
    @DynamoDbAutoGeneratedTimestampAttribute
    public Instant getLastUpdate() {...}
    public void setLastUpdate(Instant lastUpdate) {...}
```

A abordagem equivalente do esquema de tabela estática é mostrada no trecho a seguir.

```
     .addAttribute(Instant.class, a -> a.name("lastUpdate")
                                        .getter(Customer::getLastUpdate)
                                        .setter(Customer::setLastUpdate)
                                        // Applying the 'autoGeneratedTimestamp' tag to the attribute.
                                        .tags(AutoGeneratedTimestampRecordExtension.AttributeTags.autoGeneratedTimestampAttribute())
```

### Gere um UUID com o AutoGeneratedUuidExtension
<a name="ddb-en-client-extensions-AGUE"></a>

A extensão `AutoGeneratedUuidExtension` gera um UUID (Identificador Único Universal) exclusivo para um atributo quando um novo registro é gravado no banco de dados. Usa o método Java JDK [UUID.randomUUID()](https://docs.oracle.com/javase/8/docs/api/java/util/UUID.html#randomUUID--) e se aplica aos atributos do tipo `java.lang.String`. Essa extensão não é carregada por padrão.

#### Configuração
<a name="ddb-en-client-extensions-AGUE-conf"></a>

O atributo `uniqueId` é o alvo do comportamento da extensão no trecho a seguir.

```
    @AutoGeneratedUuidExtension
    public String getUniqueId() {...}
    public void setUniqueId(String uniqueId) {...}
```

A abordagem equivalente do esquema de tabela estática é mostrada no trecho a seguir.

```
     .addAttribute(String.class, a -> a.name("uniqueId")
                                        .getter(Customer::getUniqueId)
                                        .setter(Customer::setUniqueId)
                                        // Applying the 'autoGeneratedUuid' tag to the attribute.
                                        .tags(AutoGeneratedUuidExtension.AttributeTags.autoGeneratedUuidAttribute())
```

Se quiser que a extensão preencha o UUID somente para métodos `putItem` e não para métodos `updateItem`, adicione a anotação de [comportamento de atualização](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/mapper/UpdateBehavior.html) conforme mostrado no trecho a seguir.

```
    @AutoGeneratedUuidExtension
    @DynamoDbUpdateBehavior(UpdateBehavior.WRITE_IF_NOT_EXISTS)
    public String getUniqueId() {...}
    public void setUniqueId(String uniqueId) {...}
```

Se você usar a abordagem de esquema de tabela estática, use o código equivalente a seguir.

```
     .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))
```

# Exemplo de extensão personalizada
<a name="ddb-en-client-extensions-custom"></a>

É possível criar extensões personalizadas implementando a interface `DynamoDbEnhancedClientExtension`. A classe de extensão personalizada a seguir mostra um método `beforeWrite()` que usa uma expressão de atualização para definir um atributo `registrationDate` caso o item no banco de dados ainda não tenha um.

```
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();
    }
}
```

# Usar a API do cliente avançado do DynamoDB de forma assíncrona
<a name="ddb-en-client-async"></a>

Se seu aplicativo exigir chamadas assíncronas e sem bloqueio para o DynamoDB, você poderá usar o [DynamoDbEnhancedAsyncClient](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/DynamoDbEnhancedAsyncClient.html). Ele é semelhante à implementação síncrona, mas com as seguintes diferenças principais:

1. Ao criar o `DynamoDbEnhancedAsyncClient`, é necessário usar a versão assíncrona do cliente padrão, `DynamoDbAsyncClient`, conforme mostrado no trecho a seguir.

   ```
    DynamoDbEnhancedAsyncClient enhancedClient = 
        DynamoDbEnhancedAsyncClient.builder()
                                   .dynamoDbClient(dynamoDbAsyncClient)
                                   .build();
   ```

1. Os métodos que retornam um único objeto de dados retornam um `CompletableFuture` do resultado em vez de somente o resultado. Entretanto, seu aplicativo pode fazer outro trabalho sem precisar bloquear o resultado. O trecho a seguir mostra o método `getItem()` assíncrono. 

   ```
   CompletableFuture<Customer> result = customerDynamoDbTable.getItem(customer);
   // Perform other work here.
   return result.join();   // Now block and wait for the result.
   ```

1. Métodos que retornam listas paginadas de resultados retornam um [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) em vez de um [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) que o `DynamoDbEnhanceClient` síncrono retorna para os mesmos métodos. Seu aplicativo pode então inscrever um manipulador nesse publicador para lidar com os resultados de forma assíncrona, sem precisar bloquear.

   ```
   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.
   ```

   Para obter um exemplo mais completo de como trabalhar com a `SdkPublisher API`, consulte [o exemplo](ddb-en-client-use-multirecord.md#ddb-en-client-use-multirecord-scan-async) na seção que discute o método `scan()` assíncrono deste guia.

# Anotações de classes de dados
<a name="ddb-en-client-anno-index"></a>

A tabela a seguir lista as anotações que podem ser usadas em classes de dados e fornece links para informações e exemplos neste guia. A tabela é classificada em ordem alfabética crescente pelo nome da anotação.


**Anotações de classe de dados usadas neste guia**  

| Nome da anotação | A anotação se aplica a1 | O que ela faz | Onde ela é mostrada neste guia | 
| --- | --- | --- | --- | 
| DynamoDbAtomicCounter | atributo2 | Incrementa um atributo numérico marcado sempre que um registro é gravado no banco de dados. | [Introdução e discussão.](ddb-en-client-extensions.md#ddb-en-client-extensions-ACE) | 
| DynamoDbAttribute | atributo | Define ou renomeia uma propriedade de bean que é mapeada para um atributo de tabela do DynamoDB. |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/pt_br/sdk-for-java/latest/developer-guide/ddb-en-client-anno-index.html)  | 
| DynamoDbAutoGeneratedTimestampAttribute | atributo | Atualiza um atributo marcado com um carimbo de data/hora atual toda vez que o item é gravado com sucesso no banco de dados | [Introdução e discussão](ddb-en-client-extensions.md#ddb-en-client-extensions-AGTE). | 
| DynamoDbAutoGeneratedUuid | atributo | Gere um UUID (Identificador Único Universal) exclusivo para um atributo quando um novo registro é gravado no banco de dados. | [Introdução e discussão.](ddb-en-client-extensions.md#ddb-en-client-extensions-AGUE) | 
| DynamoDbBean | classe | Marca uma classe de dados como mapeável para um esquema de tabela. | Primeiro uso na [classe Customer](ddb-en-client-gs-tableschema.md#ddb-en-client-gs-tableschema-anno-bean-cust) na seção Conceitos básicos. Vários usos aparecem no guia. | 
| DynamoDbConvertedBy | atributo | Associa um AttributeConverter personalizado ao atributo anotado. | [Discussão inicial e exemplo.](ddb-en-client-adv-features-conversion.md#ddb-en-client-adv-features-conversion-single) | 
| DynamoDbFlatten | atributo | Nivela todos os atributos de uma classe de dados separada do DynamoDB e os adiciona como atributos de nível superior ao registro que é lido e gravado no banco de dados.  |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/pt_br/sdk-for-java/latest/developer-guide/ddb-en-client-anno-index.html)  | 
| DynamoDbIgnore | atributo |  Faz com que o atributo permaneça não mapeado.  |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/pt_br/sdk-for-java/latest/developer-guide/ddb-en-client-anno-index.html)  | 
| DynamoDbIgnoreNulls | atributo | Impede o salvamento de atributos nulos de objetos aninhados do DynamoDb. | [Discussão e exemplos.](ddb-en-client-adv-features-ignore-null.md) | 
| DynamoDbImmutable | classe |  Marca uma classe de dados imutável como mapeável para um esquema de tabela.  |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/pt_br/sdk-for-java/latest/developer-guide/ddb-en-client-anno-index.html)  | 
| DynamoDbPartitionKey | atributo |  Marca um atributo como a chave de partição primária (chave de hash) da tabela do DynamoDb.  |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/pt_br/sdk-for-java/latest/developer-guide/ddb-en-client-anno-index.html)  | 
| DynamoDbPreserveEmptyObject | atributo |  Especifica que, se nenhum dado estiver presente para o objeto mapeado para o atributo anotado, o objeto deverá ser inicializado com todos os campos nulos.  | [Discussão e exemplos.](ddb-en-client-adv-features-empty.md) | 
| DynamoDbSecondaryPartitionKey | atributo |  Marca um atributo como uma chave de partição para um índice secundário global.  |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/pt_br/sdk-for-java/latest/developer-guide/ddb-en-client-anno-index.html)  | 
| DynamoDbSecondarySortKey | atributo |  Marca um atributo como uma chave de classificação opcional para um índice secundário global ou local.  |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/pt_br/sdk-for-java/latest/developer-guide/ddb-en-client-anno-index.html)  | 
| DynamoDbSortKey | atributo |  Marca um atributo como a chave de classificação primária opcional (chave de intervalo).  |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/pt_br/sdk-for-java/latest/developer-guide/ddb-en-client-anno-index.html)  | 
| DynamoDbUpdateBehavior | atributo |  Especifica o comportamento quando esse atributo é atualizado como parte de uma operação de atualização, como UpdateItem.  | [Introdução e exemplo.](ddb-en-client-adv-features-upd-behavior.md) | 
| DynamoDbVersionAttribute | atributo | Incrementa o número da versão de um item. | [Introdução e discussão.](ddb-en-client-extensions.md#ddb-en-client-extensions-VRE) | 

1Você pode aplicar anotações no nível de atributo ao getter ou ao setter, mas não a ambos. Este guia mostra anotações sobre getters.

2O termo `property` normalmente é usado para um valor encapsulado em uma classe de dados JavaBean. No entanto, no lugar desse termo, este guia usa o termo `attribute`, para ser consistente com a terminologia usada pelo DynamoDB.

# Trabalhe com de Amazon EC2
<a name="examples-ec2"></a>

Esta seção apresenta exemplos de como programar o [Amazon EC2](https://docs.aws.amazon.com/ec2/) usando o AWS SDK para Java 2.x.

**Topics**
+ [Gerenciar Amazon EC2 instâncias](examples-ec2-instances.md)
+ [Zonas Regiões da AWS de uso e disponibilidade](examples-ec2-regions-zones.md)
+ [Trabalho com grupos de segurança no Amazon EC2](examples-ec2-security-groups.md)
+ [Trabalhar com metadados da instância do Amazon EC2](examples-ec2-IMDS.md)

# Gerenciar Amazon EC2 instâncias
<a name="examples-ec2-instances"></a>

## Criar uma instância do
<a name="create-an-instance"></a>

Crie uma nova Amazon EC2 instância chamando o [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))método do [Ec2Client](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/ec2/Ec2Client.html), fornecendo a ela uma [imagem de [RunInstancesRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/ec2/model/RunInstancesRequest.html)máquina da Amazon (AMI)](https://docs.aws.amazon.com//AWSEC2/latest/UserGuide/AMIs.html) a ser usada e um tipo de [instância](https://docs.aws.amazon.com//AWSEC2/latest/UserGuide/instance-types.html).

 **Importações** 

```
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;
```

 **Código** 

```
   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 "";
    }
```

Veja o [exemplo completo](https://github.com/awsdocs/aws-doc-sdk-examples/blob/ac748d8ef99cd17e297cb74fe13aa671e2679088/javav2/example_code/ec2/src/main/java/com/example/ec2/CreateInstance.java) em GitHub.

## Iniciar uma instância
<a name="start-an-instance"></a>

Para iniciar uma Amazon EC2 instância, chame o [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))método do Ec2Client, fornecendo a ele um [StartInstancesRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/ec2/model/StartInstancesRequest.html)contendo o ID da instância a ser iniciada.

 **Importações** 

```
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;
```

 **Código** 

```
    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);
    }
```

Veja o [exemplo completo](https://github.com/awsdocs/aws-doc-sdk-examples/blob/ac748d8ef99cd17e297cb74fe13aa671e2679088/javav2/example_code/ec2/src/main/java/com/example/ec2/StartStopInstance.java) em GitHub.

## Interromper uma instância
<a name="stop-an-instance"></a>

Para interromper uma Amazon EC2 instância, chame o [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))método do Ec2Client, fornecendo a ele um [StopInstancesRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/ec2/model/StopInstancesRequest.html)contendo o ID da instância a ser interrompida.

 **Importações** 

```
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;
```

 **Código** 

```
    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);
    }
```

Veja o [exemplo completo](https://github.com/awsdocs/aws-doc-sdk-examples/blob/ac748d8ef99cd17e297cb74fe13aa671e2679088/javav2/example_code/ec2/src/main/java/com/example/ec2/StartStopInstance.java) em GitHub.

## Reinicializar uma instância
<a name="reboot-an-instance"></a>

Para reinicializar uma Amazon EC2 instância, chame o [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))método do Ec2Client, fornecendo a ele um [RebootInstancesRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/ec2/model/RebootInstancesRequest.html)contendo o ID da instância a ser reinicializada.

 **Importações** 

```
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;
```

 **Código** 

```
    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);
     }
  }
```

Veja o [exemplo completo](https://github.com/awsdocs/aws-doc-sdk-examples/blob/ac748d8ef99cd17e297cb74fe13aa671e2679088/javav2/example_code/ec2/src/main/java/com/example/ec2/RebootInstance.java) em GitHub.

## Descrever instâncias
<a name="describe-instances"></a>

Para listar suas instâncias, crie um [DescribeInstancesRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/ec2/model/DescribeInstancesRequest.html)e chame o método do 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)) Ele retornará um [DescribeInstancesResponse](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/ec2/model/DescribeInstancesResponse.html)objeto que você pode usar para listar as Amazon EC2 instâncias da sua conta e região.

As instâncias são agrupadas por *reserva*. Cada reserva corresponde à chamada a `startInstances` que iniciou a instância. Para listar as instâncias, você deve primeiro chamar o método `reservations` da classe `DescribeInstancesResponse` e chamar `instances` em cada objeto [Reservation](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/ec2/model/Reservation.html) retornado.

 **Importações** 

```
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;
```

 **Código** 

```
    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);
        }
    }
```

Os resultados são paginados; você pode obter mais resultados passando o valor retornado do método `nextToken` do objeto de resultado para o método `nextToken` do objeto de uma solicitação nova e usando o objeto da nova solicitação na próxima chamada para `describeInstances`.

Veja o [exemplo completo](https://github.com/awsdocs/aws-doc-sdk-examples/blob/ac748d8ef99cd17e297cb74fe13aa671e2679088/javav2/example_code/ec2/src/main/java/com/example/ec2/DescribeInstances.java) em GitHub.

## Monitorar uma instância
<a name="monitor-an-instance"></a>

Você pode monitorar vários aspectos de suas Amazon EC2 instâncias, como utilização da CPU e da rede, memória disponível e espaço em disco restante. Para saber mais sobre o monitoramento de instâncias, consulte [Monitoramento Amazon EC2](https://docs.aws.amazon.com//AWSEC2/latest/UserGuide/monitoring_ec2.html) no Guia Amazon EC2 do usuário para instâncias Linux.

Para começar a monitorar uma instância, você deve criar uma [MonitorInstancesRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/ec2/model/MonitorInstancesRequest.html)com o ID da instância a ser monitorada e passá-la para o método do 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))

 **Importações** 

```
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;
```

 **Código** 

```
    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);
    }
```

Veja o [exemplo completo](https://github.com/awsdocs/aws-doc-sdk-examples/blob/ac748d8ef99cd17e297cb74fe13aa671e2679088/javav2/example_code/ec2/src/main/java/com/example/ec2/MonitorInstance.java) em GitHub.

## Interromper o monitoramento de instâncias
<a name="stop-instance-monitoring"></a>

Para parar de monitorar uma instância, crie um [UnmonitorInstancesRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/ec2/model/UnmonitorInstancesRequest.html)com o ID da instância para interromper o monitoramento e passe-o para o método do 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))

 **Importações** 

```
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;
```

 **Código** 

```
    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);
    }
```

Veja o [exemplo completo](https://github.com/awsdocs/aws-doc-sdk-examples/blob/ac748d8ef99cd17e297cb74fe13aa671e2679088/javav2/example_code/ec2/src/main/java/com/example/ec2/MonitorInstance.java) em GitHub.

## Mais informações
<a name="more-information"></a>
+  [RunInstances](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_RunInstances.html)na Referência da Amazon EC2 API
+  [DescribeInstances](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeInstances.html)na Referência da Amazon EC2 API
+  [StartInstances](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_StartInstances.html)na Referência da Amazon EC2 API
+  [StopInstances](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_StopInstances.html)na Referência da Amazon EC2 API
+  [RebootInstances](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_RebootInstances.html)na Referência da Amazon EC2 API
+  [MonitorInstances](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_MonitorInstances.html)na Referência da Amazon EC2 API
+  [UnmonitorInstances](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_UnmonitorInstances.html)na Referência da Amazon EC2 API

# Zonas Regiões da AWS de uso e disponibilidade
<a name="examples-ec2-regions-zones"></a>

## Descrever regiões
<a name="describe-regions"></a>

Para listar as regiões disponíveis para a conta, chame o método `describeRegions` do Ec2Client. Ele retorna um [DescribeRegionsResponse](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/ec2/model/DescribeRegionsResponse.html). Chame o método `regions` do objeto retornado para obter uma lista de objetos [Region](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/ec2/model/Region.html) que representam cada região.

 **Importações** 

```
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;
```

 **Código** 

```
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);
    }
}
```

Veja o [exemplo completo](https://github.com/awsdocs/aws-doc-sdk-examples/blob/7486a1a092aa8e16a21698ef26f9d524fef62e55/javav2/example_code/ec2/src/main/java/com/example/ec2/DescribeRegionsAndZones.java) em GitHub.

## Descrever zonas de disponibilidade
<a name="describe-availability-zones"></a>

Para listar cada zona de disponibilidade disponível para a conta, chame o método `describeAvailabilityZones` do Ec2Client. Ele retorna um [DescribeAvailabilityZonesResponse](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/ec2/model/DescribeAvailabilityZonesResponse.html). Chame seu `availabilityZones` método para obter uma lista de [AvailabilityZone](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/ec2/model/AvailabilityZone.html)objetos que representam cada zona de disponibilidade.

 **Importações** 

```
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;
```

 **Código** 

Criar o Ec2Client.

```
        Ec2AsyncClient ec2AsyncClient = Ec2AsyncClient.builder()
            .region(Region.US_EAST_1)
            .build();
```

Em seguida, chame describeAvailabilityZones () e recupere os resultados.

```
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);
    }
}
```

Veja o [exemplo completo](https://github.com/awsdocs/aws-doc-sdk-examples/blob/7486a1a092aa8e16a21698ef26f9d524fef62e55/javav2/example_code/ec2/src/main/java/com/example/ec2/DescribeRegionsAndZones.java) em GitHub.

## Descrever contas
<a name="describe-accounts"></a>

Para listar informações EC2 relacionadas à sua conta, chame o método do Ec2Client. `describeAccountAttributes` Esse método retorna um objeto [DescribeAccountAttributesResponse](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/ec2/model/DescribeAccountAttributesResponse.html). Invoque esse `accountAttributes` método de objetos para obter uma lista de [AccountAttribute](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/ec2/model/AccountAttribute.html)objetos. É possível iterar a lista para recuperar um objeto `AccountAttribute`.

Você pode obter os valores dos atributos da sua conta invocando o método `attributeValues` do objeto `AccountAttribute`. Esse método retorna uma lista de [AccountAttributeValue](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/ec2/model/AccountAttributeValue.html)objetos. É possível percorrer essa segunda lista para exibir o valor dos atributos (veja o exemplo de código a seguir).

 **Importações** 

```
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;
```

 **Código** 

```
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()));
                });
            }
        });
    }
}
```

Veja o [exemplo completo](https://github.com/awsdocs/aws-doc-sdk-examples/blob/7486a1a092aa8e16a21698ef26f9d524fef62e55/javav2/example_code/ec2/src/main/java/com/example/ec2/DescribeAccount.java) em GitHub.

## Mais informações
<a name="more-information"></a>
+  [Regiões e zonas de disponibilidade](https://docs.aws.amazon.com//AWSEC2/latest/UserGuide/using-regions-availability-zones.html) no Guia Amazon EC2 do usuário para instâncias Linux
+  [DescribeRegions](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeRegions.html)na Referência da Amazon EC2 API
+  [DescribeAvailabilityZones](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeAvailabilityZones.html)na Referência da Amazon EC2 API

# Trabalho com grupos de segurança no Amazon EC2
<a name="examples-ec2-security-groups"></a>

## Criar um grupo de segurança
<a name="create-a-security-group"></a>

Para criar um grupo de segurança, chame o método `createSecurityGroup` do Ec2Client com um [CreateSecurityGroupRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/ec2/model/CreateSecurityGroupRequest.html) que contenha o nome da chave.

 **Importações** 

```
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;
```

 **Código da** 

```
            CreateSecurityGroupRequest createRequest = CreateSecurityGroupRequest.builder()
                .groupName(groupName)
                .description(groupDesc)
                .vpcId(vpcId)
                .build();

            CreateSecurityGroupResponse resp= ec2.createSecurityGroup(createRequest);
```

Veja o [exemplo completo](https://github.com/awsdocs/aws-doc-sdk-examples/blob/0b1785e42949ebf959eaa0f0da4dc2a48f92ea25/javav2/example_code/ec2/src/main/java/com/example/ec2/CreateSecurityGroup.java) no GitHub.

## Configurar um grupo de segurança
<a name="configure-a-security-group"></a>

Um grupo de segurança pode controlar os tráfegos de entrada e saída para as instâncias do Amazon EC2.

Para adicionar regras de entrada ao grupo de segurança, use o método `authorizeSecurityGroupIngress` do Ec2Client, fornecendo o nome do grupo de segurança e as regras de acesso ([IpPermission](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/ec2/model/IpPermission.html)) que você deseja atribuir a ele dentro de um objeto [AuthorizeSecurityGroupIngressRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/ec2/model/AuthorizeSecurityGroupIngressRequest.html). O exemplo a seguir mostra como adicionar permissões de IP a um grupo de segurança.

 **Importações** 

```
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;
```

 **Código da** 

Primeiro, crie um Ec2Client

```
        Region region = Region.US_WEST_2;
        Ec2Client ec2 = Ec2Client.builder()
                .region(region)
                .build();
```

Em seguida, use o método `authorizeSecurityGroupIngress` do Ec2Client,

```
            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 "";
    }
```

Para adicionar uma regra de saída ao grupo de segurança, forneça dados semelhantes em um [AuthorizeSecurityGroupEgressRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/ec2/model/AuthorizeSecurityGroupEgressRequest.html) ao método `authorizeSecurityGroupEgress` do Ec2Client.

Veja o [exemplo completo](https://github.com/awsdocs/aws-doc-sdk-examples/blob/0b1785e42949ebf959eaa0f0da4dc2a48f92ea25/javav2/example_code/ec2/src/main/java/com/example/ec2/CreateSecurityGroup.java) no GitHub.

## Descrever grupos de segurança
<a name="describe-security-groups"></a>

Para descrever os grupos de segurança ou obter informações sobre eles, chame o método `describeSecurityGroups` do Ec2Client. Ele retorna um [DescribeSecurityGroupsResponse](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/ec2/model/DescribeSecurityGroupsResponse.html) que pode ser usado para acessar a lista de grupos de segurança chamando o método `securityGroups`, que retorna uma lista de objetos [SecurityGroup](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/ec2/model/SecurityGroup.html).

 **Importações** 

```
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;
```

 **Código da** 

```
     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);
        }
    }
```

Veja o [exemplo completo](https://github.com/awsdocs/aws-doc-sdk-examples/blob/0b1785e42949ebf959eaa0f0da4dc2a48f92ea25/javav2/example_code/ec2/src/main/java/com/example/ec2/DescribeSecurityGroups.java) no GitHub.

## Exclua um grupo de segurança
<a name="delete-a-security-group"></a>

Para excluir um grupo de segurança, chame o método `deleteSecurityGroup` do Ec2Client, passando um [DeleteSecurityGroupRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/ec2/model/DeleteSecurityGroupRequest.html) que contenha o ID do grupo de segurança a ser excluído.

 **Importações** 

```
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;
```

 **Código da** 

```
    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);
        }
     }
```

Veja o [exemplo completo](https://github.com/awsdocs/aws-doc-sdk-examples/blob/0b1785e42949ebf959eaa0f0da4dc2a48f92ea25/javav2/example_code/ec2/src/main/java/com/example/ec2/DeleteSecurityGroup.java) no GitHub.

## Mais informações
<a name="more-information"></a>
+  [Grupos de segurança do Amazon EC2](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-security-groups.html) no Guia do Usuário Amazon EC2 para Instâncias do Linux
+  [Autorizar tráfego de entrada para suas instâncias Linux](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/authorizing-access-to-an-instance.html) no Guia do usuário do Amazon EC2 para instâncias Linux
+  [CreateSecurityGroup](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_CreateSecurityGroup.html), na Referência de API do Amazon EC2
+  [DescribeSecurityGroups](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeSecurityGroups.html), na Referência de API do Amazon EC2
+  [DeleteSecurityGroup](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DeleteSecurityGroup.html) na Referência de API do Amazon EC2
+  [AuthorizeSecurityGroupIngress](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_AuthorizeSecurityGroupIngress.html) na Referência de API do Amazon EC2

# Trabalhar com metadados da instância do Amazon EC2
<a name="examples-ec2-IMDS"></a>

Um cliente Java SDK para o Amazon EC2 Instance Metadata Service (cliente de metadados) permite que seus aplicativos acessem metadados em sua instância EC2 local. O cliente de metadados trabalha com a instância local do [IMDSv2](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/configuring-instance-metadata-service.html)(Instance Metadata Service v2) e usa solicitações orientadas à sessão. 

Duas classes de cliente estão disponíveis no SDK. O `[Ec2MetadataClient](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/imds/Ec2MetadataClient.html)` síncrono serve para operações de bloqueio e o [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) é para casos de uso assíncronos e sem bloqueio. 

## Conceitos básicos
<a name="examples-ec2-IMDS-getstarted"></a>

Para usar o cliente de metadados, adicione o artefato `imds` Maven ao seu projeto. Você também precisa de classes para um `[SdkHttpClient](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/http/SdkHttpClient.html)` (ou um `[SdkAsyncHttpClient](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/http/async/SdkAsyncHttpClient.html)` para a variante assíncrona) no caminho de classe. 

O XML do Maven a seguir mostra trechos de dependência para usar o síncrono [UrlConnectionHttpClient](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/http/urlconnection/UrlConnectionHttpClient.html)junto com a dependência para clientes de metadados.

```
<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>
```

Pesquise no [repositório central do Maven](https://central.sonatype.com/artifact/software.amazon.awssdk/bom) a versão mais recente do artefato `bom`.

Para usar um cliente HTTP assíncrono, substitua o trecho de dependência do artefato `url-connection-client`. Por exemplo, o trecho a seguir traz a [NettyNioAsyncHttpClient](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/http/nio/netty/NettyNioAsyncHttpClient.html)implementação.

```
    <dependency>
        <groupId>software.amazon.awssdk</groupId>
        <artifactId>netty-nio-client</artifactId>
    </dependency>
```

## Usar o cliente de metadados
<a name="examples-ec2-IMDS-use"></a>

### Instanciar um cliente de metadados
<a name="examples-ec2-IMDS-use-create"></a>

Você pode instanciar uma instância de um `Ec2MetadataClient` síncrono quando somente uma implementação da interface `SdkHttpClient` está presente no caminho de classe. Para fazer isso, chame o método estático `Ec2MetadataClient#create()`, conforme mostrado no trecho a seguir. 

```
Ec2MetadataClient client = Ec2MetadataClient.create(); // 'Ec2MetadataAsyncClient#create' is the asynchronous version.
```

Se seu aplicativo tiver várias implementações da interface `SdkHttpClient` ou `SdkHttpAsyncClient`, você deverá especificar uma implementação para o cliente de metadados usar, conforme mostrado na seção [Cliente HTTP configurável](#examples-ec2-IMDS-features-http). 

**nota**  
Para a maioria dos clientes de serviços, como o Amazon S3, o SDK for Java adiciona automaticamente implementações da interface `SdkHttpClient` ou `SdkHttpAsyncClient`. Se seu cliente de metadados usar a mesma implementação, o `Ec2MetadataClient#create()` funcionará. Se você precisar de uma implementação diferente, deverá especificá-la ao criar o cliente de metadados.

### Envie solicitações
<a name="examples-ec2-IMDS-use-req"></a>

Para recuperar os metadados da instância, instancie a classe `EC2MetadataClient` e chame o método `get` com um parâmetro de caminho que especifica a [categoria de metadados da instância](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instancedata-data-categories.html).

O exemplo a seguir imprime o valor associado à chave `ami-id` no console.

```
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.
```

Se o caminho não for válido, o método `get` gerará uma exceção. 

Reutilize a mesma instância do cliente para várias solicitações, mas chame `close` no cliente quando não for mais necessário liberar recursos. Depois que o método de fechamento é chamado, a instância do cliente não pode mais ser usada.

### Analisar respostas
<a name="examples-ec2-IMDS-use-pares"></a>

Os metadados da instância EC2 podem ser gerados em formatos diferentes. Texto sem formatação e JSON são os formatos mais usados. Os clientes de metadados oferecem formas de trabalhar com esses formatos. 

Como mostra o exemplo a seguir, use o método `asString` para obter os dados como uma string Java. Você também pode usar o método `asList` para separar uma resposta de texto sem formatação que retorna várias linhas. 

```
Ec2MetadataClient client = Ec2MetadataClient.create();
Ec2MetadataResponse response = client.get("/latest/meta-data/");
String fullResponse = response.asString();
List<String> splits = response.asList();
```

Se a resposta estiver em JSON, use o método `Ec2MetadataResponse#asDocument` para analisar a resposta JSON em uma instância de [Documento](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/core/document/Document.html), conforme mostrado no trecho de código a seguir.

```
Document fullResponse = response.asDocument();
```

Uma exceção será lançada se o formato dos metadados não estiver em JSON. Se a resposta for analisada com sucesso, você poderá usar a [API do documento](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/core/document/package-summary.html) para inspecionar a resposta com mais detalhes. Consulte o [gráfico de categorias de metadados](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instancedata-data-categories.html) da instância para saber quais categorias de metadados fornecem respostas em formato JSON.

## Configurar um cliente de metadados
<a name="examples-ec2-IMDS-config"></a>

### Novas tentativas
<a name="examples-ec2-IMDS-config-retries"></a>

Você pode configurar um cliente de metadados com um mecanismo de repetição. Se você fizer isso, o cliente poderá repetir automaticamente as solicitações que falharem por motivos inesperados. Por padrão, o cliente tenta novamente três vezes em uma solicitação com falha, com um tempo de recuo exponencial entre as tentativas.

Se seu caso de uso exigir um mecanismo de repetição diferente, você poderá personalizar o cliente usando o método `retryPolicy` em seu construtor. Por exemplo, o exemplo a seguir mostra um cliente síncrono configurado com um atraso fixo de dois segundos entre as tentativas e cinco tentativas de repetição.

```
BackoffStrategy fixedBackoffStrategy = FixedDelayBackoffStrategy.create(Duration.ofSeconds(2));
Ec2MetadataClient client =
    Ec2MetadataClient.builder()
                     .retryPolicy(retryPolicyBuilder -> retryPolicyBuilder.numRetries(5)
                                                                           .backoffStrategy(fixedBackoffStrategy))
                     .build();
```

Há várias [BackoffStrategies](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/core/retry/backoff/package-summary.html)que você pode usar com um cliente de metadados.

Você também pode desativar totalmente o mecanismo de repetição, como mostra o trecho a seguir.

```
Ec2MetadataClient client =
    Ec2MetadataClient.builder()
                    .retryPolicy(Ec2MetadataRetryPolicy.none())
                    .build();
```

O uso do `Ec2MetadataRetryPolicy#none()` desativa a política de repetição padrão para que o cliente de metadados não tente fazer novas tentativas.

### Versão IP
<a name="examples-ec2-IMDS-config-ipversion"></a>

Por padrão, um cliente de metadados usa o IPV4 endpoint em. `http://169.254.169.254` Para alterar o cliente para usar a IPV6 versão, use o `endpoint` método `endpointMode` ou o do construtor. Uma exceção ocorre se os dois métodos forem chamados no construtor.

Os exemplos a seguir mostram as duas IPV6 opções.

```
Ec2MetadataClient client =
    Ec2MetadataClient.builder()
                     .endpointMode(EndpointMode.IPV6)
                     .build();
```

```
Ec2MetadataClient client =
    Ec2MetadataClient.builder()
                     .endpoint(URI.create("http://[fd00:ec2::254]"))
                     .build();
```

## Recursos principais do
<a name="examples-ec2-IMDS-features"></a>

### Cliente assíncrono
<a name="examples-ec2-IMDS-features-async"></a>

Para usar a versão sem bloqueio do cliente, instancie uma instância da classe `Ec2MetadataAsyncClient`. O código no exemplo a seguir cria um cliente assíncrono com configurações padrão e usa o método `get` para recuperar o valor da chave `ami-id`.

```
Ec2MetadataAsyncClient asyncClient = Ec2MetadataAsyncClient.create();
CompletableFuture<Ec2MetadataResponse> response = asyncClient.get("/latest/meta-data/ami-id");
```

O `java.util.concurrent.CompletableFuture` retornado pelo método `get` é concluído quando a resposta retorna. O exemplo a seguir imprime os metadados `ami-id` no console.

```
response.thenAccept(metadata -> System.out.println(metadata.asString()));
```

### Cliente HTTP configurável
<a name="examples-ec2-IMDS-features-http"></a>

O construtor de cada cliente de metadados tem um método `httpClient` que você pode usar para fornecer um cliente HTTP personalizado. 

O exemplo a seguir mostra o código para uma instância personalizada do `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.
```

O exemplo a seguir mostra o código de uma instância personalizada do `NettyNioAsyncHttpClient` com um cliente de metadados assíncrono.

```
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.
```

O tópico [Configure clientes HTTP no AWS SDK for Java 2.x](http-configuration.md) deste guia fornece detalhes sobre como configurar os clientes HTTP que estão disponíveis no SDK para Java.

### Armazenamento em cache de tokens
<a name="examples-ec2-IMDS-features-token"></a>

Como os metadados usados pelos clientes IMDSv2, todas as solicitações são associadas a uma sessão. Uma sessão é definida por um token que tem uma expiração, que o cliente de metadados gerencia para você. Cada solicitação de metadados reutiliza automaticamente o token até que ele expire. 

Por padrão, um token dura seis horas (21.600 segundos). Recomendamos que você mantenha o time-to-live valor padrão, a menos que seu caso de uso específico exija configuração avançada. 

Se necessário, configure a duração usando o método `tokenTtl` do construtor. Por exemplo, o código no trecho a seguir cria um cliente com duração de sessão de cinco minutos. 

```
Ec2MetadataClient client =
    Ec2MetadataClient.builder()
                     .tokenTtl(Duration.ofMinutes(5))
                     .build();
```

Se você omitir a chamada do método `tokenTtl` no construtor, a duração padrão de 21.600 será usada em vez disso. 

# Trabalhe com IAM
<a name="examples-iam"></a>

Esta seção fornece exemplos de programação AWS Identity and Access Management (IAM) usando o AWS SDK para Java 2.x.

 AWS Identity and Access Management (IAM) permite que você controle com segurança o acesso a AWS serviços e recursos para seus usuários. Usando IAM, você pode criar e gerenciar AWS usuários e grupos e usar permissões para permitir e negar seu acesso aos AWS recursos. Para obter um guia completo IAM, visite o [Guia IAM do usuário](https://docs.aws.amazon.com//IAM/latest/UserGuide/introduction.html).

Os exemplos a seguir incluem somente o código necessário para demonstrar cada técnica. O [código de exemplo completo está disponível em GitHub](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/javav2). A partir daí, você pode fazer download de um único arquivo de origem ou clonar o repositório de maneira local para obter todos os exemplos para compilação e execução.

**Topics**
+ [Gerenciar chaves de acesso IAM](examples-iam-access-keys.md)
+ [Gerenciar usuários do IAM](examples-iam-users.md)
+ [Criar políticas do IAM](feature-iam-policy-builder.md)
+ [Trabalhar com políticas do IAM](examples-iam-policies.md)
+ [Trabalhe com certificados de IAM servidor](examples-iam-server-certificates.md)

# Gerenciar chaves de acesso IAM
<a name="examples-iam-access-keys"></a>

## Criar uma chave de acesso
<a name="create-an-access-key"></a>

Para criar uma chave de acesso do IAM, chame o método `createAccessKey` do `IamClient’s` com um objeto [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).

**nota**  
Você deve definir a região como **AWS\$1GLOBAL** para chamadas do `IamClient` para trabalhar, porque o IAM é um serviço global.

 **Importações** 

```
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;
```

 **Código da** 

```
    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 "";
    }
```

Veja o [exemplo completo](https://github.com/awsdocs/aws-doc-sdk-examples/blob/f807d60010caf3d14fe4cd0801b842fb8e9511ca/javav2/example_code/iam/src/main/java/com/example/iam/CreateAccessKey.java) no GitHub.

## Listar chaves de acesso
<a name="list-access-keys"></a>

Para listar as chaves de acesso de determinado usuário, crie um objeto [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) que contenha o nome de usuário para o qual listar as chaves e passe-o ao método `listAccessKeys` do `IamClient’s`.

**nota**  
Se você não fornecer um nome de usuário para `listAccessKeys`, ele tentará listar chaves de acesso associadas à Conta da AWS que assinou a solicitação.

 **Importações** 

```
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;
```

 **Código da** 

```
    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);
        }
    }
```

Os resultados de `listAccessKeys` são paginados (com um máximo de 100 registros por chamada). Você pode chamar `isTruncated` no objeto [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) retornado para ver se a consulta retornou menos resultados do que os disponíveis. Se esse for o caso, chame `marker` no `ListAccessKeysResponse` e use-o ao criar uma nova solicitação. Use essa nova solicitação na próxima invocação de `listAccessKeys`.

Veja o [exemplo completo](https://github.com/awsdocs/aws-doc-sdk-examples/blob/f807d60010caf3d14fe4cd0801b842fb8e9511ca/javav2/example_code/iam/src/main/java/com/example/iam/ListAccessKeys.java) no GitHub.

## Recuperar a hora do uso mais recente de uma chave de acesso
<a name="retrieve-an-access-key-s-last-used-time"></a>

Para obter a hora em que uma chave de acesso foi usada pela última vez, chame o método `getAccessKeyLastUsed` do `IamClient’s` com o ID da chave de acesso, que pode ser passado usando um objeto [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).

Depois disso, é possível usar o objeto [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) retornado para recuperar a hora em que a chave foi usada mais recentemente.

 **Importações** 

```
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;
```

 **Código da** 

```
    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");
    }
```

Veja o [exemplo completo](https://github.com/awsdocs/aws-doc-sdk-examples/blob/f807d60010caf3d14fe4cd0801b842fb8e9511ca/javav2/example_code/iam/src/main/java/com/example/iam/AccessKeyLastUsed.java) no GitHub.

## Ativar ou desativar chaves de acesso
<a name="iam-access-keys-update"></a>

Você pode ativar ou desativar uma chave de acesso criando um objeto [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), fornecendo o ID de chave de acesso, opcionalmente, o nome do usuário e o [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) desejado e, então, passando o objeto de solicitação para o método `updateAccessKey` do `IamClient’s`.

 **Importações** 

```
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;
```

 **Código da** 

```
       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);
        }
    }
```

Veja o [exemplo completo](https://github.com/awsdocs/aws-doc-sdk-examples/blob/f807d60010caf3d14fe4cd0801b842fb8e9511ca/javav2/example_code/iam/src/main/java/com/example/iam/UpdateAccessKey.java) no GitHub.

## Excluir uma chave de acesso
<a name="delete-an-access-key"></a>

Para excluir permanentemente uma chave de acesso, chame o método `deleteKey` do `IamClient’s`, fornecendo [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) que contenha o ID e o nome de usuário da chave de acesso.

**nota**  
Depois de excluída, uma chave não poderá mais ser recuperada ou usada. Para desativar temporariamente uma chave de maneira que ela possa ser reativada mais tarde, use o método [`updateAccessKey`](#iam-access-keys-update).

 **Importações** 

```
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;
```

 **Código da** 

```
    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);
        }
    }
```

Veja o [exemplo completo](https://github.com/awsdocs/aws-doc-sdk-examples/blob/f807d60010caf3d14fe4cd0801b842fb8e9511ca/javav2/example_code/iam/src/main/java/com/example/iam/DeleteAccessKey.java) no GitHub.

## Mais informações
<a name="more-information"></a>
+  [CreateAccessKey](https://docs.aws.amazon.com/IAM/latest/APIReference/API_CreateAccessKey.html) na Referência de API IAM
+  [ListAccessKeys](https://docs.aws.amazon.com/IAM/latest/APIReference/API_ListAccessKeys.html) na referência de API IAM
+  [GetAccessKeyLastUsed](https://docs.aws.amazon.com/IAM/latest/APIReference/API_GetAccessKeyLastUsed.html) na referência de API IAM
+  [UpdateAccessKey](https://docs.aws.amazon.com/IAM/latest/APIReference/API_UpdateAccessKey.html) na Referência de API IAM
+  [DeleteAccessKey](https://docs.aws.amazon.com/IAM/latest/APIReference/API_DeleteAccessKey.html) na Referência de API IAM

# Gerenciar usuários do IAM
<a name="examples-iam-users"></a>

## Criar um usuário
<a name="creating-a-user"></a>

Crie um usuário do IAM fornecendo o nome de usuário para o método `createUser` do IamClient, usando um objeto [CreateUserRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/iam/model/CreateUserRequest.html) que contém o nome do usuário.

 **Importações** 

```
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;
```

 **Código da** 

```
    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 "";
    }
```

Veja o [exemplo completo](https://github.com/awsdocs/aws-doc-sdk-examples/blob/cf25559da654a7b74bec039c0ab9397dc5951dd4/javav2/example_code/iam/src/main/java/com/example/iam/CreateUser.java) no GitHub.

## Listar usuários
<a name="listing-users"></a>

Para listar os usuários do IAM da conta, crie um [ListUsersRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/iam/model/ListUsersRequest.html) e passe para o método `listUsers` do IamClient. Você pode recuperar a lista de usuários chamando `users` no objeto [ListUsersResponse](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/iam/model/ListUsersResponse.html) retornado.

A lista de usuários retornados por `listUsers` é paginada. Você pode verificar se há mais resultados a serem recuperados chamando o método `isTruncated` do objeto de resposta. Se ele retornar `true`, chame o método `marker()` do objeto de resposta. Use o valor do marcador para criar um novo objeto de solicitação. Em seguida, chame o método `listUsers` novamente com a nova solicitação.

 **Importações** 

```
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;
```

 **Código da** 

```
    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);
        }
    }
```

Veja o [exemplo completo](https://github.com/awsdocs/aws-doc-sdk-examples/blob/cf25559da654a7b74bec039c0ab9397dc5951dd4/javav2/example_code/iam/src/main/java/com/example/iam/ListUsers.java) no GitHub.

## Atualizar um usuário
<a name="updating-a-user"></a>

Para atualizar um usuário, chame o método `updateUser` do objeto de IamClient, que utiliza um objeto [UpdateUserRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/iam/model/UpdateUserRequest.html) que pode ser usado por você para alterar o *nome* ou o *caminho* do usuário.

 **Importações** 

```
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;
```

 **Código da** 

```
    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);
        }
      }
```

Veja o [exemplo completo](https://github.com/awsdocs/aws-doc-sdk-examples/blob/cf25559da654a7b74bec039c0ab9397dc5951dd4/javav2/example_code/iam/src/main/java/com/example/iam/UpdateUser.java) no GitHub.

## Excluir um usuário
<a name="deleting-a-user"></a>

Para excluir um usuário, chame a requisição `deleteUser` do IamClient com um objeto [UpdateUserRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/iam/model/UpdateUserRequest.html) definido com o nome de usuário a ser excluído.

 **Importações** 

```
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;
```

 **Código da** 

```
    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);
        }
    }
```

Veja o [exemplo completo](https://github.com/awsdocs/aws-doc-sdk-examples/blob/cf25559da654a7b74bec039c0ab9397dc5951dd4/javav2/example_code/iam/src/main/java/com/example/iam/DeleteUser.java) no GitHub.

## Mais informações
<a name="more-information"></a>
+  [Usuários IAM](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_users.html) no Guia do Usuário IAM
+  [Gerenciando usuários IAM](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_users_manage.html) no Guia do usuário IAM
+  [CreateUser](https://docs.aws.amazon.com/IAM/latest/APIReference/API_CreateUser.html) na Referência de API IAM
+  [ListUsers](https://docs.aws.amazon.com/IAM/latest/APIReference/API_ListUsers.html) na referência da API IAM
+  [UpdateUser](https://docs.aws.amazon.com/IAM/latest/APIReference/API_UpdateUser.html) na Referência da API IAM
+  [DeleteUser](https://docs.aws.amazon.com/IAM/latest/APIReference/API_DeleteUser.html) na Referência da API IAM

# Crie políticas do IAM com o AWS SDK for Java 2.x
<a name="feature-iam-policy-builder"></a>

A [API IAM Policy Builder](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/policybuilder/iam/package-summary.html) é uma biblioteca que você pode usar para criar [políticas do IAM](https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html) em Java e carregá-las no AWS Identity and Access Management (IAM). 

Em vez de criar uma política do IAM montando manualmente uma cadeia de caracteres JSON ou lendo um arquivo, a API fornece uma abordagem orientada a objetos do lado do cliente para gerar a cadeia de caracteres JSON. Quando você lê uma política do IAM existente no formato JSON, a API a converte em uma [IamPolicy](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/policybuilder/iam/IamPolicy.html)instância para manipulação.

A API de criação de política do IAM ficou disponível com a versão 2.20.105 do SDK, então use essa versão ou uma versão posterior em seu arquivo de compilação do Maven. O número da versão mais recente do SDK está [listado na central do Maven](https://central.sonatype.com/artifact/software.amazon.awssdk/iam-policy-builder).

O trecho a seguir mostra um bloco de dependência de exemplo para um arquivo Maven `pom.xml`. Isso permite que você use a API de criação de política do IAM em seu projeto. 

```
<dependency>
    <groupId>software.amazon.awssdk</groupId>
    <artifactId>iam-policy-builder</artifactId>
    <version>2.27.21</version>
</dependency>
```

## Criar uma `IamPolicy`
<a name="iam-policy-builder-create"></a>

Esta seção mostra vários exemplos de como criar políticas usando a API de criação de política do IAM.

Em cada um dos exemplos a seguir, comece com o `[IamPolicy.Builder](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/policybuilder/iam/IamPolicy.Builder.html)` e adicione uma ou mais instruções usando o método `addStatement`. Seguindo esse padrão, o [IamStatement.Builder](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/policybuilder/iam/IamStatement.Builder.html) tem métodos para adicionar o efeito, as ações, os recursos e as condições à declaração.

### Exemplo: criar uma política com base em um período
<a name="iam-policy-builder-create-ex-time-based"></a>

O exemplo a seguir cria uma política baseada em identidade que permite a ação `GetItem` do Amazon DynamoDB entre dois instantes.

```
    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());
    }
```

#### Saída JSON
<a name="iam-builder-ex-json-date"></a>

A última instrução no exemplo anterior retorna a seguinte cadeia de caracteres JSON. 

Leia mais sobre esse [exemplo](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_examples_aws-dates.html) no *Guia do usuário do 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"
            }
        }
    }
}
```

------

### Exemplo: especificar várias condições
<a name="iam-policy-builder-create-ex-multi-conditions"></a>

Este exemplo mostra como você pode criar uma política baseada em identidade que permita o acesso a atributos específicos do DynamoDB. A política contém duas condições.

```
    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());
    }
```

#### Saída JSON
<a name="iam-builder-ex-json-multi-cond"></a>

A última instrução no exemplo anterior retorna a seguinte cadeia de caracteres JSON. 

Leia mais sobre esse [exemplo](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_examples_dynamodb_attributes.html) no *Guia do usuário do 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"
            }
        }
    }
}
```

------

### Exemplo: especificar entidades principais
<a name="iam-policy-builder-create-ex-principals"></a>

O exemplo a seguir mostra como criar uma política baseada em recursos que negue acesso a um bucket para todas as entidades principais, exceto àquelas especificados na condição.

```
    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());
    }
```

#### Saída JSON
<a name="iam-policy-builder-create-json-ex-principals"></a>

A última instrução no exemplo anterior retorna a seguinte cadeia de caracteres JSON. 

Leia mais sobre esse [exemplo](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements_principal.html#principal-anonymous) no *Guia do usuário do 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"
      }
    }
  }
}
```

------

### Exemplo: permitir o acesso entre contas
<a name="iam-policy-builder-create-ex-cross-account"></a>

O exemplo a seguir mostra como permitir que outra pessoa Conta da AWS faça upload de objetos para o seu bucket, mantendo o controle total do proprietário dos objetos enviados. 

```
    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());
    }
```

#### Saída JSON
<a name="iam-policy-builder-create-ex-json-cross-account"></a>

A última instrução no exemplo anterior retorna a seguinte cadeia de caracteres JSON. 

Leia mais sobre esse [exemplo](https://docs.aws.amazon.com/AmazonS3/latest/userguide/example-bucket-policies.html#example-bucket-policies-acl-2) no *Guia do usuário do 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"
      }
    }
  }
}
```

------

## Usar um `IamPolicy` com o IAM
<a name="iam-policy-builder-work-with-service"></a>

Depois de criar uma instância `IamPolicy`, você usará um [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) para trabalhar com o serviço IAM. 

O exemplo a seguir cria uma política que permite que uma [identidade do IAM](https://docs.aws.amazon.com/IAM/latest/UserGuide/id.html) grave itens em uma tabela do DynamoDB na conta especificada com o parâmetro `accountID`. Em seguida, a política é enviada para o IAM como uma cadeia de caracteres JSON.

```
    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());
    }
```

O próximo exemplo se baseia no exemplo anterior. O código baixa a política e a usa como base para uma nova política, copiando e alterando a instrução. A nova política é então carregada.

```
    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>

Os exemplos anteriores usam um argumento `IamClient` criado conforme mostrado no trecho a seguir.

```
IamClient iam = IamClient.builder().region(Region.AWS_GLOBAL).build();
```

### Políticas em JSON
<a name="iam-policy-builder-work-with-serivce-json"></a>

Os exemplos retornam as seguintes cadeias de caracteres 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"
  }
}
```

# Trabalhar com políticas do IAM
<a name="examples-iam-policies"></a>

## Criar uma política
<a name="create-a-policy"></a>

Para criar uma nova política, forneça o nome da política e um documento de política formatado em JSON em um [CreatePolicyRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/iam/model/CreatePolicyRequest.html) para o método `createPolicy` do IamClient.

 **Importações** 

```
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;
```

 **Código da** 

```
    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 "" ;
    }
```

Veja o [exemplo completo](https://github.com/awsdocs/aws-doc-sdk-examples/blob/e41bacfd5e671e7ef1a9f73e972540dc6a434664/javav2/example_code/iam/src/main/java/com/example/iam/CreatePolicy.java) no GitHub.

## Obter uma política
<a name="get-a-policy"></a>

Para recuperar uma política existente, chame o método `getPolicy` do IamClient fornecendo o ARN da política em um objeto [GetPolicyRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/iam/model/GetPolicyRequest.html).

 **Importações** 

```
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;
```

 **Código da** 

```
    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);
        }
    }
```

Veja o [exemplo completo](https://github.com/awsdocs/aws-doc-sdk-examples/blob/cf25559da654a7b74bec039c0ab9397dc5951dd4/javav2/example_code/iam/src/main/java/com/example/iam/GetPolicy.java) no GitHub.

## Anexar uma política de função
<a name="attach-a-role-policy"></a>

Você pode anexar uma política a uma [função](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles.html) IAM chamando o método `attachRolePolicy` do IamClient, fornecendo o nome da função e o ARN da política em um [AttachRolePolicyRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/iam/model/AttachRolePolicyRequest.html).

 **Importações** 

```
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;
```

 **Código da** 

```
    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");
    }
```

Veja o [exemplo completo](https://github.com/awsdocs/aws-doc-sdk-examples/blob/cf25559da654a7b74bec039c0ab9397dc5951dd4/javav2/example_code/iam/src/main/java/com/example/iam/AttachRolePolicy.java) no GitHub.

## Listar políticas de função anexadas
<a name="list-attached-role-policies"></a>

Liste políticas anexadas em uma função chamando o método `listAttachedRolePolicies` do IamClient. Ele utiliza um objeto [ListAttachedRolePoliciesRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/iam/model/ListAttachedRolePoliciesRequest.html) que contém o nome da função para listar as políticas.

Chame `getAttachedPolicies` no objeto [ListAttachedRolePoliciesResponse](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/iam/model/ListAttachedRolePoliciesResponse.html) retornado para obter a lista de políticas anexadas. Os resultados podem estar truncados; se o método `ListAttachedRolePoliciesResponse` do objeto `isTruncated` retornar `true`, chame o método `ListAttachedRolePoliciesResponse` do objeto `marker`. Use o marcador retornado para criar uma nova solicitação e use-o para chamar `listAttachedRolePolicies` novamente a fim de obter o próximo lote de resultados.

 **Importações** 

```
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;
```

 **Código da** 

```
    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");
    }
```

Veja o [exemplo completo](https://github.com/awsdocs/aws-doc-sdk-examples/blob/cf25559da654a7b74bec039c0ab9397dc5951dd4/javav2/example_code/iam/src/main/java/com/example/iam/AttachRolePolicy.java) no GitHub.

## Desanexar uma política de função
<a name="detach-a-role-policy"></a>

Para desanexar uma política de uma função, chame o método `detachRolePolicy` do IamClient fornecendo o nome da função e o ARN da política em um [DetachRolePolicyRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/iam/model/DetachRolePolicyRequest.html).

 **Importações** 

```
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;
```

 **Código da** 

```
    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);
        }
    }
```

Veja o [exemplo completo](https://github.com/awsdocs/aws-doc-sdk-examples/blob/cf25559da654a7b74bec039c0ab9397dc5951dd4/javav2/example_code/iam/src/main/java/com/example/iam/DetachRolePolicy.java) no GitHub.

## Mais informações
<a name="more-information"></a>
+  [Visão geral das políticas IAM](https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html) no Guia do usuário IAM.
+ [Referência da política do IAM da AWS](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies.html) no Guia do usuário do IAM.
+  [CreatePolicy](https://docs.aws.amazon.com/IAM/latest/APIReference/API_CreatePolicy.html) na Referência de API IAM
+  [GetPolicy](https://docs.aws.amazon.com/IAM/latest/APIReference/API_GetPolicy.html) na Referência de API IAM
+  [AttachRolePolicy](https://docs.aws.amazon.com/IAM/latest/APIReference/API_AttachRolePolicy.html) na referência da API IAM
+  [ListAttachedRolePolicies](https://docs.aws.amazon.com/IAM/latest/APIReference/API_ListAttachedRolePolicies.html) na referência da API IAM
+  [DetachRolePolicy](https://docs.aws.amazon.com/IAM/latest/APIReference/API_DetachRolePolicy.html) na referência da API IAM

# Trabalhe com certificados de IAM servidor
<a name="examples-iam-server-certificates"></a>

Para habilitar conexões HTTPS com seu site ou aplicativo AWS, você precisa de um *certificado de SSL/TLS servidor*. Você pode usar um certificado de servidor fornecido por AWS Certificate Manager ou obtido de um provedor externo.

Recomendamos que você use ACM para provisionar, gerenciar e implantar seus certificados de servidor. Com ACM você pode solicitar um certificado, implantá-lo em seus AWS recursos e deixar que você ACM gerencie as renovações de certificados. Os certificados fornecidos pela ACM são gratuitos. Para obter mais informações sobre ACM, consulte o [Guia AWS Certificate Manager do usuário](https://docs.aws.amazon.com/acm/latest/userguide/acm-overview.html).

## Obter um certificado do servidor
<a name="get-a-server-certificate"></a>

Você pode recuperar um certificado de servidor chamando o `getServerCertificate` método IamClient's, passando-o a [GetServerCertificateRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/iam/model/GetServerCertificateRequest.html)com o nome do certificado.

 **Importações** 

```
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;
```

 **Código** 

```
    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);
        }
    }
```

Veja o [exemplo completo](https://github.com/awsdocs/aws-doc-sdk-examples/blob/0b1785e42949ebf959eaa0f0da4dc2a48f92ea25/javav2/example_code/iam/src/main/java/com/example/iam/GetServerCertificate.java) em GitHub.

## Listar certificados do servidor
<a name="list-server-certificates"></a>

Para listar seus certificados de servidor, chame o `listServerCertificates` método IamClient's com [ListServerCertificatesRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/iam/model/ListServerCertificatesRequest.html)a. Ele retorna um [ListServerCertificatesResponse](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/iam/model/ListServerCertificatesResponse.html).

Chame o `serverCertificateMetadataList` método do `ListServerCertificateResponse` objeto retornado para obter uma lista de [ServerCertificateMetadata](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/iam/model/ServerCertificateMetadata.html)objetos que você pode usar para obter informações sobre cada certificado.

Os resultados podem estar truncados; se o método `ListServerCertificateResponse` do objeto `isTruncated` retornar `true`, chame o método `ListServerCertificatesResponse` do objeto `marker` e use o marcador para criar uma solicitação. Use a nova solicitação para chamar `listServerCertificates` novamente a fim de obter o próximo lote de resultados.

 **Importações** 

```
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;
```

 **Código** 

```
    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);
        }
    }
```

Veja o [exemplo completo](https://github.com/awsdocs/aws-doc-sdk-examples/blob/0b1785e42949ebf959eaa0f0da4dc2a48f92ea25/javav2/example_code/iam/src/main/java/com/example/iam/ListServerCertificates.java) em GitHub.

## Atualizar um certificado do servidor
<a name="update-a-server-certificate"></a>

Você pode atualizar o nome ou o caminho de um certificado de servidor chamando IamClient o `updateServerCertificate` método s. É necessário um [UpdateServerCertificateRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/iam/model/UpdateServerCertificateRequest.html)objeto definido com o nome atual do certificado do servidor e um novo nome ou novo caminho para ser usado.

 **Importações** 

```
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;
```

 **Código** 

```
    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);
        }
     }
```

Veja o [exemplo completo](https://github.com/awsdocs/aws-doc-sdk-examples/blob/0b1785e42949ebf959eaa0f0da4dc2a48f92ea25/javav2/example_code/iam/src/main/java/com/example/iam/UpdateServerCertificate.java) em GitHub.

## Excluir um certificado do servidor
<a name="delete-a-server-certificate"></a>

Para excluir um certificado de servidor, chame o `deleteServerCertificate` método IamClient's [DeleteServerCertificateRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/iam/model/DeleteServerCertificateRequest.html)contendo o nome do certificado.

 **Importações** 

```
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;
```

 **Código** 

```
    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);
        }
    }
```

Veja o [exemplo completo](https://github.com/awsdocs/aws-doc-sdk-examples/blob/0b1785e42949ebf959eaa0f0da4dc2a48f92ea25/javav2/example_code/iam/src/main/java/com/example/iam/DeleteServerCertificate.java) em GitHub.

## Mais informações
<a name="more-information"></a>
+  [Trabalhando com certificados de servidor](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_server-certs.html) no Guia IAM do usuário
+  [GetServerCertificate](https://docs.aws.amazon.com/IAM/latest/APIReference/API_GetServerCertificate.html)na Referência da IAM API
+  [ListServerCertificates](https://docs.aws.amazon.com/IAM/latest/APIReference/API_ListServerCertificates.html)na Referência da IAM API
+  [UpdateServerCertificate](https://docs.aws.amazon.com/IAM/latest/APIReference/API_UpdateServerCertificate.html)na Referência da IAM API
+  [DeleteServerCertificate](https://docs.aws.amazon.com/IAM/latest/APIReference/API_DeleteServerCertificate.html)na Referência da IAM API
+  [AWS Certificate Manager Guia do usuário](https://docs.aws.amazon.com/acm/latest/userguide/) 

# Trabalhe com de Kinesis
<a name="examples-kinesis"></a>

Esta seção apresenta exemplos de como programar o [Amazon Kinesis](https://docs.aws.amazon.com/kinesis/) usando o AWS SDK para Java 2.x.

Consulte mais informações sobre o Kinesis no [Guia do desenvolvedor do Amazon Kinesis](https://docs.aws.amazon.com/streams/latest/dev/introduction.html).

Os exemplos a seguir incluem somente o código necessário para demonstrar cada técnica. O [código de exemplo completo está disponível no GitHub](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/javav2). A partir daí, você pode fazer download de um único arquivo de origem ou clonar o repositório de maneira local para obter todos os exemplos para compilação e execução.

**Topics**
+ [Assine Amazon Kinesis Data Streams](examples-kinesis-stream.md)

# Assine Amazon Kinesis Data Streams
<a name="examples-kinesis-stream"></a>

Os exemplos a seguir mostram como recuperar e processar dados do fluxo de dados Amazon Kinesis usando o método `subscribeToShard`. O Kinesis Data Streams agora emprega o recurso "fanout" aprimorado uma API de recuperação de dados HTTP/2 de baixa latência, o que facilita para desenvolvedores executar vários aplicativos de alto desempenho e baixa latência no mesmo fluxo de dados do Kinesis.

## Configuração
<a name="set-up"></a>

Primeiro, crie um cliente do Kinesis assíncrono e um objeto [SubscribeToShardRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/kinesis/model/SubscribeToShardRequest.html). Esses objetos são usados em cada um dos exemplos a seguir para se inscrever em eventos do Kinesis.

 **Importações** 

```
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;
```

 **Código da** 

```
        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();
```

## Usar a interface do construtor
<a name="use-the-builder-interface"></a>

Você pode usar o método `builder` para simplificar a criação de [SubscribeToShardResponseHandler](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/kinesis/model/SubscribeToShardResponseHandler.html).

Usando o construtor, você pode definir cada retorno de chamada do ciclo de vida com um método de chamada em vez de implementar a interface completa.

 **Código da** 

```
    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);
    }
```

Para ter mais controle do publicador, você pode usar o método `publisherTransformer` para personalizar o publicador.

 **Código da** 

```
    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);
    }
```

Veja o [exemplo completo](https://github.com/awsdocs/aws-doc-sdk-examples/blob/ac748d8ef99cd17e297cb74fe13aa671e2679088/javav2/example_code/kinesis/src/main/java/com/example/kinesis/KinesisStreamEx.java) no GitHub.

## Usar um manipulador de respostas personalizado
<a name="use-a-custom-response-handler"></a>

Para ter o controle total do assinante e do publicador, implemente a interface `SubscribeToShardResponseHandler`.

Neste exemplo, você implementa o método `onEventStream`, que permite o acesso total ao editor. Isso demonstra como transformar o editor em registros de eventos para impressão pelo assinante.

 **Código da** 

```
    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);
    }
```

Veja o [exemplo completo](https://github.com/awsdocs/aws-doc-sdk-examples/blob/ac748d8ef99cd17e297cb74fe13aa671e2679088/javav2/example_code/kinesis/src/main/java/com/example/kinesis/KinesisStreamEx.java) no GitHub.

## Usar a interface do visitante
<a name="use-the-visitor-interface"></a>

Você pode usar um objeto [Visitante](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/kinesis/model/SubscribeToShardResponseHandler.Visitor.html) para se inscrever em eventos específicos que tenha interesse em assistir.

 **Código da** 

```
    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);
    }
```

Veja o [exemplo completo](https://github.com/awsdocs/aws-doc-sdk-examples/blob/ac748d8ef99cd17e297cb74fe13aa671e2679088/javav2/example_code/kinesis/src/main/java/com/example/kinesis/KinesisStreamEx.java) no GitHub.

## Usar um assinante personalizado
<a name="use-a-custom-subscriber"></a>

Você também pode implementar seu próprio assinante personalizado para se inscrever no streaming.

Este trecho de código mostra um exemplo de assinante.

 **Código da** 

```
    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");
        }
    }
```

Você pode passar o assinante personalizado para o método `subscribe`, conforme mostrado no trecho de código a seguir.

 **Código da** 

```
    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);
    }
```

Veja o [exemplo completo](https://github.com/awsdocs/aws-doc-sdk-examples/blob/ac748d8ef99cd17e297cb74fe13aa671e2679088/javav2/example_code/kinesis/src/main/java/com/example/kinesis/KinesisStreamEx.java) no GitHub.

## Gravar registros de dados em um fluxo de dados Kinesis
<a name="write-data-records-into-a-kinesis-data-stream"></a>

Você pode usar o objeto [KinesisClient](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/kinesis/KinesisClient.html) para gravar registros de dados em um fluxo de dados do Kinesis usando o método `putRecords`. Para chamar esse método com êxito, crie um objeto [PutRecordsRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/kinesis/model/PutRecordsRequest.html) . Passe o nome do fluxo de dados para o método `streamName`. Além disso, passe os dados usando o método `putRecords` (como mostrado no exemplo de código a seguir).

 **Importações** 

```
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;
```

No exemplo de código Java a seguir, observe que o objeto **StockTrade** é usado como os dados que serão gravado no fluxo de dados do Kinesis. Antes de executar o exemplo, certifique-se de que você criou o fluxo de dados.

 **Código da** 

```
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);
        }
    }
}
```

Veja o [exemplo completo](https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/javav2/example_code/kinesis/src/main/java/com/example/kinesis/StockTradesWriter.java) no GitHub.

## Usar uma biblioteca de terceiros
<a name="use-a-third-party-library"></a>

Você pode usar outras bibliotecas de terceiros em vez de implementar um assinante personalizado. Este exemplo demonstra como usar a implementação RxJava, mas você pode usar qualquer biblioteca que implemente interfaces de streams reativos. Consulte a [página wiki do RxJava no GitHub](https://github.com/ReactiveX/RxJava/wiki) para obter mais informações sobre essa biblioteca.

Para usar a biblioteca, adicione-a como uma dependência. Se estiver usando o Maven, o exemplo mostra o trecho POM a ser usado.

 **Entrada POM** 

```
<dependency>
 <groupId>io.reactivex.rxjava2</groupId>
 <artifactId>rxjava</artifactId>
 <version>2.2.21</version>
</dependency>
```

 **Importações** 

```
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;
```

Este exemplo usa RxJava no método do ciclo de vida `onEventStream`. Assim, você tem acesso total ao editor, que pode ser usado para criar um Rx Flowable.

 **Código da** 

```
        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();
```

Você também pode usar o método `publisherTransformer` com o editor `Flowable`. Você deve adaptar o editor `Flowable` para um *SdkPublisher*, conforme mostrado no exemplo a seguir.

 **Código da** 

```
        SubscribeToShardResponseHandler responseHandler = SubscribeToShardResponseHandler
            .builder()
            .onError(t -> System.err.println("Error during stream - " + t.getMessage()))
            .publisherTransformer(p -> SdkPublisher.adapt(Flowable.fromPublisher(p).limit(100)))
            .build();
```

Veja o [exemplo completo](https://github.com/awsdocs/aws-doc-sdk-examples/blob/main/javav2/example_code/kinesis/src/main/java/com/example/kinesis/KinesisStreamRxJavaEx.java) no GitHub.

## Mais informações
<a name="more-information"></a>
+  [SubscribeToShardEvent](https://docs.aws.amazon.com/kinesis/latest/APIReference/API_SubscribeToShardEvent.html) na referência da API Amazon Kinesis
+  [SubscribeToShard](https://docs.aws.amazon.com/kinesis/latest/APIReference/API_SubscribeToShard.html) na Referência da API Amazon Kinesis

# Invocar, listar e excluir funções AWS Lambda
<a name="examples-lambda"></a>

Esta seção fornece exemplos de programação com o cliente Lambda de serviço usando o AWS SDK para Java 2.x.

**Topics**
+ [Invocar uma função do Lambda](#invoke-function)
+ [Listar funções do Lambda](#list-function)
+ [Excluir uma função do Lambda](#delete-function)

## Invocar uma função do Lambda
<a name="invoke-function"></a>

Você pode invocar uma Lambda função criando um [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)objeto e invocando seu `invoke` método. Crie um [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)objeto para especificar informações adicionais, como o nome da função e a carga a ser passada para a Lambda função. Os nomes das funções aparecem como *arn:aws:lambda:us-east- 1:123456789012:function:*. HelloFunction É possível recuperar o valor examinando a função no Console de gerenciamento da AWS.

Para passar dados de carga útil para uma função, crie um objeto [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) que contenha informações. Por exemplo, no exemplo de código a seguir, observe os dados JSON passados para a função do Lambda .

 **Importações** 

```
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;
```

 **Código** 

O exemplo de código a seguir demonstra como invocar uma Lambda função.

```
    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);
        }
    }
```

Veja o [exemplo completo](https://github.com/awsdocs/aws-doc-sdk-examples/blob/f807d60010caf3d14fe4cd0801b842fb8e9511ca/javav2/example_code/lambda/src/main/java/com/example/lambda/LambdaInvoke.java) em GitHub.

## Listar funções do Lambda
<a name="list-function"></a>

Crie um objeto `[Lambda Client](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/lambda/LambdaClient.html)` e invoque seu método `listFunctions`. Esse método retorna um objeto [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). É possível invocar o método `functions` desse objeto para retornar uma lista de objetos [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). É possível percorrer a lista para recuperar informações sobre as funções. Por exemplo, o exemplo de código Java a seguir mostra como obter cada nome de função.

 **Importações** 

```
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;
```

 **Código** 

O exemplo de código Java a seguir demonstra como recuperar uma lista de nomes de função do .

```
    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);
        }
    }
```

Veja o [exemplo completo](https://github.com/awsdocs/aws-doc-sdk-examples/blob/f807d60010caf3d14fe4cd0801b842fb8e9511ca/javav2/example_code/lambda/src/main/java/com/example/lambda/ListLambdaFunctions.java) em GitHub.

## Excluir uma função do Lambda
<a name="delete-function"></a>

Crie um objeto [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) e invoque seu método `deleteFunction`. Crie um objeto [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) e passe-o para o método `deleteFunction`. Esse objeto contém informações como o nome da função a ser excluída. Os nomes das funções aparecem como *arn:aws:lambda:us-east- 1:123456789012:function:*. HelloFunction É possível recuperar o valor examinando a função no Console de gerenciamento da AWS.

 **Importações** 

```
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;
```

 **Código** 

O código Java a seguir demonstra como excluir uma Lambda função.

```
    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);
        }
    }
```

Veja o [exemplo completo](https://github.com/awsdocs/aws-doc-sdk-examples/blob/f807d60010caf3d14fe4cd0801b842fb8e9511ca/javav2/example_code/lambda/src/main/java/com/example/lambda/DeleteFunction.java) em GitHub.

# Trabalhar com o Amazon S3
<a name="examples-s3"></a>

Esta seção fornece informações básicas para trabalhar com o Amazon S3 usando o AWS SDK for Java 2.x. Esta seção complementa os [exemplos do Java v2 do Amazon S3](java_s3_code_examples.md) apresentados na seção *Exemplos de código* deste guia.

## Clientes S3 no AWS SDK for Java 2.x
<a name="s3-clients"></a>

 AWS SDK for Java 2.x Ele fornece diferentes tipos de clientes S3. A tabela a seguir mostra as diferenças e pode ajudar você a decidir o que é melhor para seus casos de uso.


**Diferentes tipos de clientes do Amazon S3**  

| Cliente do S3 | Descrição breve | Quando usar | Limitação/desvantagem | 
| --- | --- | --- | --- | 
|  **AWS Cliente S3 baseado em CRT** Interface: [S3 AsyncClient](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/s3/S3AsyncClient.html) Construtor: [S3 CrtAsyncClientBuilder](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/pt_br/sdk-for-java/latest/developer-guide/examples-s3.html) Consulte [Use um cliente S3 de alto desempenho: cliente S3 baseado em AWS CRT](crt-based-s3-client.md).  |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/pt_br/sdk-for-java/latest/developer-guide/examples-s3.html)  |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/pt_br/sdk-for-java/latest/developer-guide/examples-s3.html)  | 
|  **Cliente assíncrono do S3 baseado em Java *com* várias partes habilitadas** Interface: [S3 AsyncClient](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/s3/S3AsyncClient.html) Construtor: [S3 AsyncClientBuilder](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/pt_br/sdk-for-java/latest/developer-guide/examples-s3.html) Consulte [Configurar o cliente assíncrono do S3 baseado em Java para usar transferências paralelas](s3-async-client-multipart.md).  |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/pt_br/sdk-for-java/latest/developer-guide/examples-s3.html)  | Menos desempenho do que o cliente S3 AWS baseado em CRT. | 
|  **Cliente assíncrono do S3 baseado em Java *sem* várias partes habilitadas** Interface: [S3 AsyncClient](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/s3/S3AsyncClient.html) Construtor: [S3 AsyncClientBuilder](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/pt_br/sdk-for-java/latest/developer-guide/examples-s3.html)  |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/pt_br/sdk-for-java/latest/developer-guide/examples-s3.html)  |  Sem otimização do desempenho.  | 
|  **Cliente síncrono do S3 baseado em Java** Interface: [S3Client](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/s3/S3Client.html) Construtor: [S3 ClientBuilder](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/pt_br/sdk-for-java/latest/developer-guide/examples-s3.html)  |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/pt_br/sdk-for-java/latest/developer-guide/examples-s3.html)  |  Sem otimização do desempenho.  | 

**nota**  
A partir da versão 2.18.x, o AWS SDK for Java 2.x usa [endereçamento no estilo hospedado virtual ao incluir uma substituição de](https://docs.aws.amazon.com/AmazonS3/latest/userguide/VirtualHosting.html#virtual-hosted-style-access) endpoint. Isso se aplica desde que o nome do bucket seja um rótulo DNS válido.   
Chame o método [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) com `true` no seu construtor de clientes para forçar o cliente a usar o endereçamento no estilo de caminho para os buckets.  
O exemplo a seguir mostra um cliente de serviço configurado com uma substituição de endpoint e usando o endereçamento no estilo de caminho.  

```
S3Client client = S3Client.builder()
                          .region(Region.US_WEST_2)
                          .endpointOverride(URI.create("https://s3.us-west-2.amazonaws.com"))
                          .forcePathStyle(true)
                          .build();
```

**Topics**
+ [Clientes do S3 no SDK](#s3-clients)
+ [Fazer upload de fluxos para o S3](best-practices-s3-uploads.md)
+ [Pré-assinado URLs](examples-s3-presign.md)
+ [Acesso entre regiões](s3-cross-region.md)
+ [Proteção da integridade de dados com somas de verificação](s3-checksums.md)
+ [Usar um cliente do S3 de alta performance](crt-based-s3-client.md)
+ [Configuração de suporte de transferência paralela](s3-async-client-multipart.md)
+ [Transferir arquivos e diretórios](transfer-manager.md)
+ [Notificações de eventos do S3](examples-s3-event-notifications.md)

# Fazendo upload de streams para o Amazon S3 usando o AWS SDK for Java 2.x
<a name="best-practices-s3-uploads"></a>

Quando você usa um fluxo para fazer upload de conteúdo para o S3 usando [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)) ou [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)), é utilizada uma classe de fábrica `RequestBody` para a API síncrona a fim de fornecer o fluxo. Para a API assíncrona, `AsyncRequestBody` é a classe de fábrica equivalente.

## Quais métodos fazem upload de fluxos?
<a name="s3-stream-upload-methods"></a>

Para a API síncrona, é possível usar os seguintes métodos de fábrica `RequestBody` para fornecer o fluxo:
+ `[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` tem o método de fábrica `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)`

Para a API assíncrona, é possível usar os seguintes métodos de fábrica de `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)`
  + Você usa o AsyncRequestBodyFromInputStreamConfiguration .Builder para fornecer o fluxo
+ `[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)`
  + O resultado `[BlockingInputStreamAsyncRequestBody](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/core/async/BlockingInputStreamAsyncRequestBody.html)` contém o método `writeInputStream(InputStream inputStream)` que você pode usar para fornecer o fluxo

## Realizar o upload
<a name="s3-upload-stream-perform"></a>

### Se você sabe o tamanho do fluxo
<a name="s3-stream-upload-supply-content-length"></a>

Como você pode ver na assinatura dos métodos mostrados anteriormente, a maioria deles aceita um parâmetro de tamanho do conteúdo. 

Se você souber o tamanho do conteúdo em bytes, forneça o valor exato:

```
// 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));
```

**Atenção**  
 Ao fazer upload de um fluxo de entrada, se o tamanho do conteúdo especificado não corresponder à contagem real de bytes, poderá ocorrer:  
Objetos truncados se o comprimento especificado for muito pequeno
Falha nos uploads ou conexões interrompidas se o tamanho especificado for muito grande

### Se você não sabe o tamanho do fluxo
<a name="s3-stream-upload-unknown-length"></a>

#### Usar a API síncrona
<a name="s3-upload-unknown-sync-client"></a>

Use o`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;
}
```

Como o SDK armazena em buffer todo o fluxo na memória para calcular a duração do conteúdo, podem ocorrer problemas de memória com fluxos grandes. Se você precisar fazer upload de fluxos grandes com o cliente síncrono, considere usar a API de várias partes:

##### Faça upload de um fluxo usando a API do cliente síncrono e a API de várias partes
<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;
}
```

**nota**  
Para a maioria dos casos de uso, recomendamos usar a API do cliente assíncrono para fluxos de tamanho desconhecido. Essa abordagem permite fazer transferências paralelas e oferece uma interface de programação mais simples, porque o SDK gerencia a segmentação do fluxo em fragmentos de várias partes caso o fluxo seja grande.   
Tanto o cliente assíncrono do S3 padrão com várias partes habilitadas quanto o cliente do S3 baseado no AWS CRT implementam essa abordagem. Mostramos exemplos dessa abordagem na seção a seguir.

#### Usar a API assíncrona
<a name="s3-stream-upload-unknown-async-client"></a>

Você pode fornecer `null` para o argumento `contentLength` do `fromInputStream(InputStream inputStream, Long contentLength, ExecutorService executor)`

**Example usando o cliente AWS assíncrono baseado em CRT:**  

```
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 usar o cliente assíncrono padrão com a opção de várias partes ativada.**  

```
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;
}
```

# Trabalhe com Amazon S3 pré-assinados URLs
<a name="examples-s3-presign"></a>

Os pré-assinados URLs fornecem acesso temporário a objetos privados do S3 sem exigir que os usuários tenham AWS credenciais ou permissões. 

Por exemplo, vamos supor que Alice tenha acesso a um objeto do S3 e queira compartilhar temporariamente o acesso a esse objeto com Bob. A Alice pode gerar uma solicitação GET pré-assinada para compartilhar com o Bob, para que ele possa baixar o objeto sem exigir acesso às credenciais da Alice. Você pode gerar solicitações pré-assinadas URLs para HTTP GET e HTTP PUT.

## Gere um URL pré-assinado para um objeto e baixe-o (solicitação GET).
<a name="get-presignedobject"></a>

O exemplo a seguir consiste em duas partes.
+ Parte 1: A Alice gera o URL pré-assinado de um objeto.
+ Parte 2: O Bob baixa o objeto usando o URL pré-assinado.

### Parte 1: Gerar o URL
<a name="get-presigned-object-part1"></a>

A Alice já tem um objeto em um bucket do S3. Ela usa o código a seguir para gerar uma string de URL que o Bob pode usar em uma solicitação GET subsequente.

#### Importações
<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();
        }
    }
```

### Parte 2: Baixar o objeto
<a name="get-presigned-object-part2"></a>

O Bob usa uma das três opções de código a seguir para baixar o objeto. Como alternativa, ele pode usar um navegador para realizar a solicitação GET.

#### Usar o JDK `HttpURLConnection` (desde a 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();
    }
```

#### Usar o JDK `HttpClient` (desde a 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();
    }
```

#### Usar `SdkHttpClient` do SDK para Java
<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();
    }
```

Veja o [exemplo completo](https://github.com/awsdocs/aws-doc-sdk-examples/blob/d73001daea05266eaa9e074ccb71b9383832369a/javav2/example_code/s3/src/main/java/com/example/s3/GeneratePresignedGetUrlAndRetrieve.java) e [faça o teste](https://github.com/awsdocs/aws-doc-sdk-examples/blob/d73001daea05266eaa9e074ccb71b9383832369a/javav2/example_code/s3/src/test/java/com/example/s3/presignurl/GeneratePresignedGetUrlTests.java) GitHub.

## Gerar um URL pré-assinado para um upload e, depois, fazer upload de um arquivo (solicitação PUT)
<a name="put-presignedobject"></a>

O exemplo a seguir consiste em duas partes.
+ Parte 1: A Alice gera o URL pré-assinado para fazer upload de um objeto.
+ Parte 2: O Bob faz upload de um arquivo usando o URL pré-assinado.

### Parte 1: Gerar o URL
<a name="put-presigned-object-part1"></a>

A Alice já tem um bucket do S3. Ela usa o código a seguir para gerar uma string de URL que o Bob pode usar em uma solicitação PUT subsequente.

#### Importações
<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();
        }
    }
```

### Parte 2: Fazer upload de um objeto de arquivo
<a name="put-presigned-object-part2"></a>

O Bob usa uma das três opções de código a seguir para fazer upload de um arquivo.

#### Usar o JDK `HttpURLConnection` (desde a 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);
        }
    }
```

#### Usar o JDK `HttpClient` (desde a 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);
        }
    }
```

#### Usar `SdkHttpClient` do SDK para Java
<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);
        }
    }
```

Veja o [exemplo completo](https://github.com/awsdocs/aws-doc-sdk-examples/blob/d73001daea05266eaa9e074ccb71b9383832369a/javav2/example_code/s3/src/main/java/com/example/s3/GeneratePresignedUrlAndPutFileWithMetadata.java) e [faça o teste](https://github.com/awsdocs/aws-doc-sdk-examples/blob/d73001daea05266eaa9e074ccb71b9383832369a/javav2/example_code/s3/src/test/java/com/example/s3/presignurl/GeneratePresignedPutUrlTests.java) GitHub.

# Acesso entre regiões para o Amazon S3
<a name="s3-cross-region"></a>

Quando você trabalha com os buckets do Amazon Simple Storage Service (Amazon S3), você geralmente conhece a Região da AWS do bucket. A região com a qual você trabalha é determinada quando você cria o cliente do S3. 

No entanto, às vezes você pode precisar trabalhar com um bucket específico, mas não sabe se ele está localizado na mesma região definida para o cliente do S3. 

Em vez de fazer mais chamadas para determinar a região do bucket, você pode usar o SDK para permitir o acesso aos buckets do S3 entre diferentes regiões.

## Configuração
<a name="s3-cross-region-setup"></a>

O suporte para acesso entre regiões foi disponibilizado com a versão `2.20.111` do SDK. Use essa versão ou uma versão posterior em seu arquivo de compilação do Maven para a dependência do `s3`, conforme mostrado no trecho a seguir.

```
<dependency>
  <groupId>software.amazon.awssdk</groupId>
  <artifactId>s3</artifactId>
  <version>2.27.21</version>
</dependency>
```

Em seguida, ao criar seu cliente do S3, habilite o acesso entre regiões conforme mostrado no trecho. O acesso não está habilitado por padrão.

```
S3AsyncClient client = S3AsyncClient.builder()
                                    .crossRegionAccessEnabled(true)
                                    .build();
```

## Como o SDK fornece acesso entre regiões
<a name="s3-cross-region-routing"></a>

Quando você faz referência a um bucket existente em uma solicitação, como ao usar o método `putObject`, o SDK inicia uma solicitação para a região configurada para o cliente. 

Se o bucket não existir nessa região específica, a resposta de erro incluirá a região real em que o bucket reside. Em seguida, o SDK usa a região correta em uma segunda solicitação:

Para otimizar futuras solicitações para o mesmo bucket, o SDK armazena em cache no cliente esse mapeamento de região.

## Considerações
<a name="s3-cross-region-considerations"></a>

Ao habilitar o acesso ao bucket entre regiões, saiba que a primeira chamada de API pode resultar em maior latência se o bucket não estiver na região configurada do cliente. No entanto, as chamadas subsequentes se beneficiam das informações da região em cache, resultando em melhor desempenho.

Quando você ativa o acesso entre regiões, o acesso ao bucket não é afetado. O usuário deve estar autorizado a acessar o bucket em qualquer região em que ele resida.

# Proteção da integridade de dados com somas de verificação
<a name="s3-checksums"></a>

O Amazon Simple Storage Service (Amazon S3) oferece a capacidade de especificar uma soma de verificação ao fazer upload de um objeto. Quando você especifica uma soma de verificação, ela é armazenada com o objeto e pode ser validada quando o objeto é baixado.

As somas de verificação fornecem uma camada adicional de integridade de dados quando você transfere arquivos. Com somas de verificação, você pode verificar a consistência de dados confirmando que o arquivo recebido corresponde ao arquivo original. Consulte mais informações sobre as somas de verificação no Amazon S3 no [Guia do usuário do Amazon Simple Storage Service](https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html), incluindo os [algoritmos compatíveis](https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html#using-additional-checksums).

Você tem a flexibilidade de escolher o algoritmo mais adequado às suas necessidades e deixar que o SDK calcule a soma de verificação. Como alternativa, você pode fornecer um valor de soma de verificação pré-computado usando um dos algoritmos compatíveis. 

**nota**  
A partir da versão 2.30.0 do AWS SDK for Java 2.x, o SDK fornece proteções de integridade padrão calculando automaticamente uma soma de verificação `CRC32` para uploads. O SDK calcula essa soma de verificação se você não fornecer um valor de soma de verificação pré-calculado ou se não especificar um algoritmo que o SDK deva usar para calcular uma soma de verificação.   
O SDK também fornece configurações globais para proteções de integridade de dados que você pode definir externamente, sobre as quais você pode ler no Guia de referência de [ferramentas AWS SDKs e ferramentas](https://docs.aws.amazon.com/sdkref/latest/guide/feature-dataintegrity.html).

Discutimos somas de verificação em duas fases de solicitação: upload de um objeto e download de um objeto. 

## Fazer upload de um objeto
<a name="use-service-S3-checksum-upload"></a>

Quando você faz upload de um objeto com o método `putObject` e fornece um algoritmo de soma de verificação, o SDK calcula a soma de verificação para o algoritmo especificado.

O trecho de código a seguir mostra uma solicitação para fazer upload de um objeto com uma soma de verificação `SHA256`. Quando o SDK envia a solicitação, ele calcula a soma de verificação `SHA256` e carrega o objeto. O Amazon S3 valida a integridade do conteúdo calculando a soma de verificação e comparando-a com a soma de verificação fornecida pelo SDK. Depois, o Amazon S3 armazena a soma de verificação com o objeto.

```
public void putObjectWithChecksum() {
        s3Client.putObject(b -> b
                .bucket(bucketName)
                .key(key)
                .checksumAlgorithm(ChecksumAlgorithm.SHA256),
            RequestBody.fromString("This is a test"));
}
```

Se você não fornecer um algoritmo de soma de verificação na solicitação, o comportamento da soma de verificação varia conforme a versão do SDK utilizado, conforme mostrado na tabela a seguir.

**Comportamento da soma de verificação quando nenhum algoritmo de soma de verificação é fornecido**


| Versão do Java SDK | Comportamento da soma de verificação | 
| --- | --- | 
| anterior à versão 2.30.0 | O SDK não calcula automaticamente uma soma de verificação baseada em CRC e a fornece na solicitação. | 
| 2.30.0 ou posterior | O SDK usa o algoritmo `CRC32` para calcular a soma de verificação e a fornece na solicitação. O Amazon S3 valida a integridade da transferência computando sua própria soma de verificação `CRC32` e a compara com a soma de verificação fornecida pelo SDK. Se as somas de verificação corresponderem, a soma de verificação será salva com o objeto. | 

### Usar um valor de soma de verificação pré-calculado
<a name="use-service-S3-checksum-upload-pre"></a>

Um valor de soma de verificação pré-calculado fornecido com a solicitação desabilita a computação automática pelo SDK e, em vez disso, usa o valor fornecido.

O exemplo a seguir mostra uma solicitação com uma soma de SHA256 verificação pré-calculada.

```
    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)));
    }
```

Se o Amazon S3 determinar que o valor da soma de verificação está incorreto para o algoritmo especificado, o serviço retornará uma resposta de erro.

### Carregamentos fracionados
<a name="use-service-S3-checksum-upload-multi"></a>

Você também pode usar somas de verificação com carregamentos fracionados.

 O SDK para Java 2.x fornece duas opções para usar somas de verificação com carregamentos fracionados. A primeira opção usa o `S3TransferManager`.

O exemplo de gerenciador de transferência a seguir especifica o SHA1 algoritmo para o upload.

```
    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();
    }
```

Se você não fornecer um algoritmo de soma de verificação ao usar o gerenciador de transferências para uploads, o SDK calculará automaticamente a soma de verificação com base no algoritmo `CRC32`. O SDK executa esse cálculo para todas as versões do SDK.

A segunda opção usa a [API `S3Client`](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/s3/S3Client.html) (ou a [API `S3AsyncClient`](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/s3/S3AsyncClient.html)) para executar o carregamento fracionado. Se você especificar uma soma de verificação com essa abordagem, deverá indicar o algoritmo a ser usado no início do carregamento. Você também deve especificar o algoritmo para a solicitação de cada parte e fornecer a soma de verificação calculada para cada parte após o carregamento.

```
    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()));
    }
```

O [código para os exemplos e [testes](https://github.com/awsdocs/aws-doc-sdk-examples/blob/main/javav2/example_code/s3/src/test/java/com/example/s3/PerformMultiPartUploadTests.java) completos](https://github.com/awsdocs/aws-doc-sdk-examples/blob/main/javav2/example_code/s3/src/main/java/com/example/s3/PerformMultiPartUpload.java) está no repositório GitHub de exemplos de código.

## Fazer download de um objeto
<a name="use-service-S3-checksum-download"></a>

Quando você usa o método [getObject](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/s3/S3Client.html#getObject(software.amazon.awssdk.services.s3.model.GetObjectRequest)) para baixar um objeto, o SDK valida automaticamente a soma de verificação  quando o método `checksumMode` do compilador do `GetObjectRequest` está definido como `ChecksumMode.ENABLED`. 

A solicitação no trecho a seguir direciona o SDK a validar a soma de verificação na resposta calculando a soma de verificação e comparando os valores.

```
    public GetObjectResponse getObjectWithChecksum() {
        return s3Client.getObject(b -> b
                        .bucket(bucketName)
                        .key(key)
                        .checksumMode(ChecksumMode.ENABLED))
                .response();
    }
```

**nota**  
Se o objeto não tiver sido carregado com uma soma de verificação, nenhuma validação ocorrerá. 

## Outras opções de cálculo da soma de verificação
<a name="S3-checsum-calculation-options"></a>

**nota**  
Para verificar a integridade dos dados transmitidos e identificar quaisquer erros de transmissão, recomendamos que os usuários mantenham as configurações padrão do SDK para as opções de cálculo da soma de verificação. Por padrão, o SDK adiciona essa verificação importante para muitas operações do S3, incluindo `PutObject` e `GetObject`.

No entanto, se o uso do Amazon S3 exigir uma validação mínima da soma de verificação, você poderá desativar muitas verificações alterando as configurações padrão. 

### Desative o cálculo automático da soma de verificação, a menos que seja necessário
<a name="S3-minimize-checksum-calc-global"></a>

É possível desativar o cálculo automático da soma de verificação pelo SDK para operações compatíveis, por exemplo e `PutObject` e `GetObject`. No entanto, algumas operações do S3 exigem um cálculo de soma de verificação. E não é possível desativá-lo nessas operações.

O SDK fornece configurações separadas para o cálculo de uma soma de verificação para a carga útil de uma solicitação e para a carga útil de uma resposta.

A lista a seguir descreve as configurações que você pode usar para minimizar os cálculos de soma de verificação nos diferentes escopos.
+ **Escopo de todos os aplicativos** — Ao alterar as configurações nas variáveis de ambiente ou em um perfil nos `credentials` arquivos AWS `config` compartilhados, todos os aplicativos podem usar essas configurações. Essas configurações afetam todos os clientes de serviço em todos os aplicativos do AWS SDK, a menos que sejam substituídas no escopo do aplicativo ou do cliente de serviço.
  + Adicione as configurações em um perfil:

    ```
    [default]
    request_checksum_calculation = WHEN_REQUIRED
    response_checksum_validation = WHEN_REQUIRED
    ```
  + Adicione variáveis de ambiente:

    ```
    AWS_REQUEST_CHECKSUM_CALCULATION=WHEN_REQUIRED
    AWS_RESPONSE_CHECKSUM_VALIDATION=WHEN_REQUIRED
    ```
+ **Escopo atual da aplicação**: é possível definir a propriedade do sistema Java `aws.requestChecksumCalculation` como `WHEN_REQUIRED` para limitar o cálculo da soma de verificação. A propriedade do sistema correspondente para respostas é `aws.responseChecksumValidation`.

  Essas configurações afetam todos os clientes de serviço do SDK em todas as aplicações, a menos que sejam substituídas durante a criação do cliente de serviço.

  Defina a propriedade do sistema no início da aplicação:

  ```
  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.
      }
  }
  ```
+ **Escopo de cliente de serviço único do S3**: é possível configurar um único cliente de serviço do S3 para calcular a quantidade mínima de somas de verificação usando os métodos do compilador:

  ```
  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. 
      }
  // ...
  }
  ```

### Use o `LegacyMd5Plugin` para simplificar a MD5 compatibilidade
<a name="S3-checksum-legacy-md5"></a>

Junto com o lançamento do comportamento de CRC32 soma de verificação com a versão 2.30.0, o SDK parou de calcular MD5 somas de verificação nas operações necessárias.

Se precisar de um comportamento de MD5 soma de verificação legado para operações do S3, você pode usar o`LegacyMd5Plugin`, que foi lançado com a versão 2.31.32 do SDK.

Isso `LegacyMd5Plugin` é particularmente útil quando você precisa manter a compatibilidade com aplicativos que dependem do comportamento antigo da MD5 soma de verificação, especialmente ao trabalhar com provedores de armazenamento de terceiros compatíveis com S3, como aqueles usados com conectores de sistema de arquivos S3A (Apache Spark, Iceberg).

Para usar o `LegacyMd5Plugin`, adicione-o ao compilador de clientes do 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();
```

Se você quiser adicionar somas de MD5 verificação às operações que exigem somas de verificação e não adicionar somas de verificação padrão do SDK para operações que oferecem suporte a somas de verificação, mas não são obrigatórias, você pode ativar as opções e como. `ClientBuilder` `requestChecksumCalculation` `responseChecksumValidation` `WHEN_REQUIRED` Isso adicionará somas de verificação padrão do SDK somente às operações que as exigem:

```
// 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();
```

Essa configuração é particularmente útil ao trabalhar com sistemas de armazenamento de terceiros compatíveis com S3 que podem não suportar totalmente os algoritmos de soma de verificação mais recentes, mas ainda exigem somas de MD5 verificação para determinadas operações.

# Use um cliente S3 de alto desempenho: cliente S3 baseado em AWS CRT
<a name="crt-based-s3-client"></a>

O cliente S3 AWS baseado em CRT, construído com base no [AWS Common Runtime (CRT), é um cliente assíncrono](https://docs.aws.amazon.com/sdkref/latest/guide/common-runtime.html) S3 alternativo. Ele transfere objetos de e para o Amazon Simple Storage Service (Amazon S3) com desempenho e confiabilidade aprimorados usando automaticamente a [API de upload de várias partes](https://docs.aws.amazon.com/AmazonS3/latest/userguide/mpuoverview.html) e as [buscas de intervalo de bytes](https://docs.aws.amazon.com/AmazonS3/latest/userguide/optimizing-performance-guidelines.html#optimizing-performance-guidelines-get-range) do Amazon S3. 

O cliente S3 AWS baseado em CRT melhora a confiabilidade da transferência caso haja uma falha na rede. A confiabilidade é aprimorada ao realizar novas tentativas de partes individuais com falha em uma transferência de arquivos sem reiniciar a transferência desde o início.

Além disso, o cliente S3 AWS baseado em CRT oferece pool de conexões aprimorado e balanceamento de carga do Sistema de Nomes de Domínio (DNS), o que também melhora a taxa de transferência.

Você pode usar o cliente S3 AWS baseado em CRT no lugar do cliente assíncrono S3 padrão do SDK e aproveitar imediatamente sua taxa de transferência aprimorada.

**Importante**  
Atualmente, o cliente S3 AWS baseado em CRT não oferece suporte à [coleta de métricas do SDK](metrics.md) no nível do cliente nem no nível da solicitação.

**AWS Componentes baseados em CRT no SDK**

O cliente *S3 AWS * baseado em CRT, descrito neste tópico, e o cliente *HTTP AWS * baseado em CRT são componentes diferentes no SDK. 

O **cliente S3 AWS baseado em CRT** é uma implementação da AsyncClient interface [S3](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/s3/S3AsyncClient.html) e é usado para trabalhar com o serviço Amazon S3. Ele é uma alternativa à implementação da interface `S3AsyncClient` baseada em Java e oferece vários benefícios.

O [cliente HTTP AWS baseado em CRT](http-configuration-crt.md) é uma implementação da [SdkAsyncHttpClient](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/http/async/SdkAsyncHttpClient.html)interface e é usado para comunicação HTTP geral. Essa é uma alternativa à implementação da interface `SdkAsyncHttpClient` do Netty e oferece várias vantagens.

Embora ambos os componentes usem bibliotecas do [AWS Common Runtime](https://docs.aws.amazon.com/sdkref/latest/guide/common-runtime.html), o cliente S3 AWS baseado em CRT usa a [biblioteca aws-c-s 3 e oferece suporte aos recursos](https://github.com/awslabs/aws-c-s3) da API de upload de [várias partes do S3](https://docs.aws.amazon.com/AmazonS3/latest/userguide/mpuoverview.html). Como o cliente HTTP AWS baseado em CRT é destinado ao uso geral, ele não oferece suporte aos recursos da API de upload de várias partes do S3.

## Adicione dependências para usar o cliente S3 baseado em AWS CRT
<a name="crt-based-s3-client-depend"></a>

Para usar o cliente S3 AWS baseado em CRT, adicione as duas dependências a seguir ao seu arquivo de projeto Maven. O exemplo mostra as versões mínimas a serem usadas. Pesquisar no repositório central do Maven as versões mais recentes dos artefatos [s3](https://central.sonatype.com/artifact/software.amazon.awssdk/s3) e [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>
```

## Crie uma instância do cliente S3 AWS baseado em CRT
<a name="crt-based-s3-client-create"></a>

 Crie uma instância do cliente S3 AWS baseado em CRT com as configurações padrão, conforme mostrado no trecho de código a seguir.

```
S3AsyncClient s3AsyncClient = S3AsyncClient.crtCreate();
```

Para configurar o cliente, use o AWS CRT Client Builder. Você pode alternar do cliente assíncrono S3 padrão para o cliente AWS baseado em CRT alterando o método builder.

```
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();
```

**nota**  
Algumas das configurações no construtor padrão podem não ser suportadas atualmente no construtor de clientes CRT da AWS . Obtenha o construtor padrão chamando `S3AsyncClient#builder()`.

## Use o cliente AWS S3 baseado em CRT
<a name="crt-based-s3-client-use"></a>

Use o cliente S3 AWS baseado em CRT para chamar as operações de API do Amazon S3. O exemplo a seguir demonstra as [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))operações [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))e disponíveis por meio do AWS SDK para Java.

```
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();
```

## Upload de fluxos de tamanho desconhecido
<a name="crt-stream-unknown-size"></a>

Uma vantagem significativa do cliente S3 AWS AWS baseado em CRT é sua capacidade de lidar com fluxos de entrada de tamanho desconhecido com eficiência. Isso é útil principalmente quando você precisa carregar dados de uma origem em que o tamanho total não pode ser determinado com antecedência.

```
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;
}
```

Esse recurso ajuda a evitar problemas comuns com os carregamentos tradicionais, nos quais uma especificação incorreta do tamanho do conteúdo pode resultar em objetos truncados ou em uploads malsucedidos.

## Limitações de configuração
<a name="crt-based-s3-client-limitations"></a>

O cliente S3 AWS baseado em CRT e o cliente assíncrono S3 baseado em Java [fornecem recursos comparáveis](examples-s3.md#s3-clients), com o cliente S3 baseado em CRT oferecendo uma vantagem de desempenho. AWS No entanto, o cliente S3 AWS baseado em CRT não tem as configurações que o cliente assíncrono S3 baseado em Java tem. Essas configurações incluem:
+ *Configuração no nível de cliente:* tempo limite de tentativa de chamada de API, interceptores de execução de compressão, publicadores de métricas, atributos de execução personalizados, opções avançadas personalizadas, serviço de executor programado personalizado, cabeçalhos personalizados
+ *Configuração em nível de solicitação:* assinantes personalizados, tempo limite de tentativa de chamada de API

Consulte uma lista completa das diferenças de configuração na referência da API.


| Cliente assíncrono do S3 baseado em Java | AWS Cliente S3 baseado em CRT | 
| --- | --- | 
| Configurações no nível do cliente[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/pt_br/sdk-for-java/latest/developer-guide/crt-based-s3-client.html)Configurações no nível de solicitação[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/pt_br/sdk-for-java/latest/developer-guide/crt-based-s3-client.html) | Configurações no nível do cliente[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/pt_br/sdk-for-java/latest/developer-guide/crt-based-s3-client.html)Configurações no nível de solicitação[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/pt_br/sdk-for-java/latest/developer-guide/crt-based-s3-client.html) | 

# Configurar o cliente assíncrono do S3 baseado em Java para usar transferências paralelas
<a name="s3-async-client-multipart"></a>

Desde a versão 2.27.5, o cliente assíncrono do S3 padrão baseado em Java permite transferências paralelas automáticas (uploads e downloads de várias partes). Você configura o suporte para transferências paralelas ao criar o cliente assíncrono do S3 baseado em Java. 

Esta seção mostra como habilitar transferências paralelas e como personalizar a configuração.

## Crie uma instância de `S3AsyncClient`
<a name="s3-async-client-multipart-create"></a>

Quando você cria uma instância `S3AsyncClient` sem chamar nenhum dos métodos `multipart*` no [construtor](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/s3/S3AsyncClientBuilder.html), as transferências paralelas não são habilitadas. Cada uma das declarações a seguir cria um cliente assíncrono do S3 baseado em Java sem suporte para uploads e downloads de várias partes.

### Criar *sem suporte* a várias partes
<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();
```

### Criar *com suporte* a várias partes
<a name="s3-async-client-mp-on"></a>

Para habilitar transferências paralelas com configurações padrão, chame o `multipartEnabled` no compilador e transmita `true` conforme mostrado no exemplo a seguir.

**Example**  

```
S3AsyncClient s3AsyncClient2 = S3AsyncClient.builder()
        .multipartEnabled(true)
        .build();
```

O valor padrão é 8 MiB para as configurações `thresholdInBytes` e `minimumPartSizeInBytes`.

Se você personalizar as configurações de várias partes, as transferências paralelas serão ativadas automaticamente, conforme mostrado a seguir.

**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();
```

## Upload de fluxos de tamanho desconhecido
<a name="java-async-client-stream-unknown-size"></a>

O cliente assíncrono do S3 baseado em Java com várias partes habilitadas pode lidar com eficiência com fluxos de entrada em que o tamanho total não é conhecido com antecedência:

```
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;
}
```

Essa abordagem evita problemas que podem ocorrer ao especificar manualmente um tamanho de conteúdo incorreto, como objetos truncados ou uploads malsucedidos.

# Transfira arquivos e diretórios com o Gerenciador de transferências do Amazon S3
<a name="transfer-manager"></a>

O gerenciador de transferências do S3 é um utilitário de transferência de arquivos de alto nível e de código aberto para o AWS SDK for Java 2.x. Use-o para transferir arquivos e diretórios de e para o Amazon Simple Storage Service (Amazon S3). 

Quando criado com base no [cliente do S3 com base no AWS CRT](crt-based-s3-client.md) ou no [cliente assíncrono do S3 baseado em Java padrão com várias partes habilitadas](s3-async-client-multipart.md), o Gerenciador de Transferências do S3 pode aproveitar as melhorias de desempenho, como a [API de upload de várias partes](https://docs.aws.amazon.com/AmazonS3/latest/userguide/mpuoverview.html) e [buscas por intervalo de bytes](https://docs.aws.amazon.com/AmazonS3/latest/userguide/optimizing-performance-guidelines.html#optimizing-performance-guidelines-get-range). 

Com o gerenciador de transferências do S3, você também pode monitorar o progresso de uma transferência em tempo real e pausar a transferência para execução posterior.

## Conceitos básicos
<a name="transfer-manager-prerequisites"></a>

### Adicionar dependências ao seu arquivo de compilação
<a name="transfer-manager-add-dependency"></a>

Para usar o Gerenciador de Transferências do S3 com desempenho aprimorado em várias partes, configure o arquivo de compilação com as dependências necessárias.

------
#### [ 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 [Versão mais recente](https://central.sonatype.com/artifact/software.amazon.awssdk/bom). 2[Versão mais recente](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 [Versão mais recente](https://central.sonatype.com/artifact/software.amazon.awssdk/bom).

------

### Criar uma instância do gerenciador de transferências do S3
<a name="transfer-manager-create"></a>

Para habilitar a transferência paralela, você deve transmitir um cliente S3 AWS baseado em CRT OU um cliente assíncrono S3 baseado em Java com multipartes habilitado. Os exemplos a seguir mostra como configurar um gerenciador de transferências do S3 com configurações personalizadas. 

------
#### [ 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 ]

Se a dependência `aws-crt` não estiver incluída no arquivo de compilação, o Gerenciador de Transferências do S3 será criado com base no cliente assíncrono do S3 baseado em Java padrão usado no SDK para Java 2.x. 

**Configuração personalizada do cliente do S3: requer a ativação de várias partes**

```
        S3AsyncClient s3AsyncClient = S3AsyncClient.builder()
                .multipartEnabled(true)
                .credentialsProvider(DefaultCredentialsProvider.create())
                .region(Region.US_EAST_1)
                .build();

        S3TransferManager transferManager = S3TransferManager.builder()
                .s3Client(s3AsyncClient)
                .build();
```

**Sem configuração do cliente do S3: suporte de várias partes ativado automaticamente**

```
S3TransferManager transferManager = S3TransferManager.create();
```

------

## Carregar um arquivo em um bucket do S3
<a name="transfer-manager-upload"></a>

O exemplo a seguir mostra um exemplo de upload de arquivo junto com o uso opcional de um [LoggingTransferListener](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/transfer/s3/progress/LoggingTransferListener.html), que registra o progresso do upload.

Para carregar um arquivo para o Amazon S3 usando o gerenciador de transferências do S3, passe um objeto [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) para o método [uploadFile](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/transfer/s3/S3TransferManager.html#uploadFile(software.amazon.awssdk.transfer.s3.model.UploadFileRequest)) do `S3TransferManager`.

O [FileUpload](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/transfer/s3/model/FileUpload.html)objeto retornado do `uploadFile` método representa o processo de upload. Depois que a solicitação for concluída, o [CompletedFileUpload](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/transfer/s3/model/CompletedFileUpload.html)objeto conterá informações sobre o upload.

```
    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!
        */
    }
```

### Importações
<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;
```

## Baixar um arquivo de um bucket do S3
<a name="transfer-manager-download"></a>

O exemplo a seguir mostra um exemplo de download junto com o uso opcional de um [LoggingTransferListener](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/transfer/s3/progress/LoggingTransferListener.html), que registra o progresso do download.

Para baixar um objeto de um bucket do S3 usando o S3 Transfer Manager, crie um [DownloadFileRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/transfer/s3/model/DownloadFileRequest.html)objeto e passe-o para o método [downloadFile](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/transfer/s3/S3TransferManager.html#downloadFile(software.amazon.awssdk.transfer.s3.model.DownloadFileRequest)).

O [FileDownload](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/transfer/s3/model/FileDownload.html)objeto retornado pelo `downloadFile` método `S3TransferManager`'s representa a transferência do arquivo. Após a conclusão do download, ele [CompletedFileDownload](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/transfer/s3/model/CompletedFileDownload.html)contém acesso às informações sobre o download.

```
    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!
        */
    }
```

### Importações
<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;
```

## Adicionar um objeto a um bucket do Amazon S3
<a name="transfer-manager-copy"></a>

O exemplo a seguir mostra como copiar um objeto com o gerenciador de transferência do S3.

Para começar a cópia de um objeto de um bucket do S3 para outro bucket, crie uma [CopyObjectRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/s3/model/CopyObjectRequest.html)instância básica.

Em seguida, envolva o básico `CopyObjectRequest` em um [CopyRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/transfer/s3/model/CopyRequest.html)que possa ser usado pelo S3 Transfer Manager. 

O objeto `Copy` retornado pelo método `copy` do `S3TransferManager` representa o processo de cópia. Depois que o processo de cópia for concluído, o [CompletedCopy](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/transfer/s3/model/CompletedCopy.html)objeto conterá detalhes sobre a resposta.

```
    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();
    }
```

**nota**  
Para realizar uma cópia entre regiões com o S3 Transfer Manager, habilite `crossRegionAccessEnabled` no construtor de clientes S3 AWS baseado em CRT, conforme mostrado no trecho a seguir.  

```
S3AsyncClient s3AsyncClient = S3AsyncClient.crtBuilder()
                .crossRegionAccessEnabled(true)
                .build();

S3TransferManager transferManager = S3TransferManager.builder()
                .s3Client(s3AsyncClient)
                .build();
```

### Importações
<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;
```

## Carregamento de um diretório local para um bucket do S3
<a name="transfer-manager-upload_directory"></a>

O exemplo a seguir demonstra como fazer upload de um diretório local para o S3.

Comece chamando o método [uploadDirectory](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/transfer/s3/S3TransferManager.html#uploadDirectory(software.amazon.awssdk.transfer.s3.model.UploadDirectoryRequest)) da `S3TransferManager` instância, passando um. [UploadDirectoryRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/transfer/s3/model/UploadDirectoryRequest.html)

O [DirectoryUpload](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/transfer/s3/model/DirectoryUpload.html)objeto representa o processo de upload, que gera um [CompletedDirectoryUpload](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/transfer/s3/model/CompletedDirectoryUpload.html)quando a solicitação é concluída. O objeto `CompleteDirectoryUpload` contém informações sobre os resultados da transferência, incluindo quais arquivos falharam na transferência.

```
    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();
    }
```

### Importações
<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;
```

## Baixar objetos do bucket do S3 para um diretório local
<a name="transfer-manager-download_directory"></a>

É possível baixar os objetos em um bucket do S3 para um diretório local, conforme mostrado no exemplo a seguir.

Para baixar os objetos em um bucket do S3 para um diretório local, comece chamando o método [DownloadDirectory](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/transfer/s3/S3TransferManager.html#downloadDirectory(software.amazon.awssdk.transfer.s3.model.DownloadDirectoryRequest)) do Transfer Manager, passando um. [DownloadDirectoryRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/transfer/s3/model/DownloadDirectoryRequest.html)

O [DirectoryDownload](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/transfer/s3/model/DirectoryDownload.html)objeto representa o processo de download, que gera um [CompletedDirectoryDownload](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/transfer/s3/model/CompletedDirectoryDownload.html)quando a solicitação é concluída. O objeto `CompleteDirectoryDownload` contém informações sobre os resultados da transferência, incluindo quais arquivos falharam na transferência.

```
    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();
    }
```

### Importações
<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;
```

## Ver exemplos completos
<a name="transfer-manager-example-location"></a>

[GitHub contém o código completo](https://github.com/awsdocs/aws-doc-sdk-examples/tree/d73001daea05266eaa9e074ccb71b9383832369a/javav2/example_code/s3/src/main/java/com/example/s3/transfermanager) de todos os exemplos desta página.

# Trabalhar com Notificações de Eventos do S3
<a name="examples-s3-event-notifications"></a>

O Amazon S3 pode enviar notificações quando determinados eventos acontecerem para ajudar você a monitorar a atividade nos buckets. O Guia do usuário do Amazon S3 fornece informações sobre as [notificações que um bucket pode enviar](https://docs.aws.amazon.com/AmazonS3/latest/userguide/EventNotifications.html#notification-how-to-overview). 

É possível configurar um bucket para enviar eventos a quatro destinos possíveis usando o SDK para Java: 
+ Tópicos do Amazon Simple Notification Service
+ Filas do Amazon Simple Queue Service
+ AWS Lambda funções
+ Amazon EventBridge

Ao configurar um bucket para o qual enviar eventos EventBridge, você pode configurar uma EventBridge regra para distribuir o mesmo evento para vários destinos. Ao configurar o bucket para enviar diretamente a um dos três primeiros destinos, somente um tipo de destino pode ser especificado para cada evento.

Na próxima seção, você verá como configurar um bucket usando o SDK for Java para enviar notificações de eventos do S3 de duas maneiras: diretamente para uma fila do Amazon SQS e para. EventBridge

A última seção mostra como usar a API de Notificações de Eventos do S3 para trabalhar com notificações de uma forma orientada a objetos.

## Configurar um bucket para enviar diretamente a um destino
<a name="s3-event-conf-bucket-direct"></a>

O exemplo a seguir configura um bucket para enviar notificações quando eventos de *criação de objetos* ou eventos de *marcação de objetos* ocorrem em um bucket.

```
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)
    );
}
```

O código mostrado acima configura uma fila para receber dois tipos de eventos. Convenientemente, o método `queueConfigurations` permite que você defina vários destinos de fila, se necessário. Além disso, no método `notificationConfiguration`, você pode definir destinos adicionais, como um ou mais tópicos do Amazon SNS ou uma ou mais funções do Lambda. O trecho a seguir mostra um exemplo com duas filas e três tipos de destinos.

```
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)
        );
```

O GitHub repositório de exemplos de código contém o [exemplo completo](https://github.com/awsdocs/aws-doc-sdk-examples/blob/main/javav2/example_code/s3/src/main/java/com/example/s3/ProcessS3EventNotification.java) para enviar notificações de eventos do S3 diretamente para uma fila.

## Configurar um bucket para enviar para EventBridge
<a name="s3-event-conf-bucket-eventbridge"></a>

O exemplo a seguir configura um bucket para o qual enviar EventBridge notificações.

```
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());
```

Ao configurar um bucket para o qual enviar eventos EventBridge, basta indicar o EventBridge destino, não os tipos de eventos nem o destino final para o qual o envio EventBridge será enviado. Você configura os destinos finais e os tipos de eventos usando o EventBridge cliente do Java SDK.

O código a seguir mostra como configurar EventBridge para distribuir eventos *criados por objetos* para um tópico e uma fila.

```
   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;
    }
```

Para trabalhar com EventBridge seu código Java, adicione uma dependência do `eventbridge` artefato ao seu arquivo `pom.xml` Maven.

```
<dependency>
    <groupId>software.amazon.awssdk</groupId>
    <artifactId>eventbridge</artifactId>
</dependency>
```

O GitHub repositório de exemplos de código contém o [exemplo completo](https://github.com/awsdocs/aws-doc-sdk-examples/blob/main/javav2/example_code/s3/src/main/java/com/example/s3/PutBucketS3EventNotificationEventBridge.java) para enviar notificações de eventos do S3 para EventBridge e depois para um tópico e uma fila.

## Usar a API de Notificações de Eventos do S3 para processar eventos
<a name="s3-event-notification-read"></a>

Depois que um destino recebe eventos de notificação do S3, você pode processá-los de forma orientada a objetos usando a API de Notificações de Eventos do S3. Você pode usar a API de notificações de eventos do S3 para trabalhar com notificações de eventos que são enviadas diretamente para um destino (conforme mostrado no [primeiro exemplo](#s3-event-conf-bucket-direct)), mas não com notificações roteadas. EventBridge As notificações de eventos do S3 enviadas por buckets EventBridge contêm uma [estrutura diferente](https://docs.aws.amazon.com/AmazonS3/latest/userguide/ev-events.html#ev-events-list) que a API de notificações de eventos do S3 não processa atualmente.

### Adicionar dependência
<a name="s3-event-notifications-dep"></a>

A API de Notificações de Eventos do S3 foi lançada com a versão 2.25.11 do SDK para Java 2.x.

Para usar a API de Notificações de Eventos do S3, adicione o elemento de dependência necessário ao `pom.xml` do Maven, conforme mostrado no trecho a seguir.

```
<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 [Versão mais recente](https://central.sonatype.com/artifact/software.amazon.awssdk/bom).

### Usar a classe `S3EventNotification`
<a name="s3-event-notifications-use"></a>

#### Criar uma instância do `S3EventNotification` com base em uma string JSON
<a name="s3-event-notifications-use-from-json"></a>

Para converter uma string JSON em um objeto `S3EventNotification`, use os métodos estáticos da classe `S3EventNotification`, conforme mostrado no exemplo a seguir.

```
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();                                                                                                   
    }
}
```

Neste exemplo, o método `fromJson` converte a string JSON em um objeto `S3EventNotification`. Os campos ausentes na string JSON resultarão em valores `null` nos campos do objeto Java correspondentes e os campos extras no JSON serão ignorados.

Outros APIs para um registro de notificação de eventos podem ser encontrados na referência da API para`[S3EventNotificationRecord](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/eventnotifications/s3/model/S3EventNotificationRecord.html)`.

#### Converter uma instância `S3EventNotification` em uma string JSON
<a name="s3-event-notifications-use-to-json"></a>

Use o método `toJson` (ou `toJsonPretty`) para converter um objeto `S3EventNotification` em uma string JSON, conforme mostrado no exemplo a seguir.

```
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);
    }
}
```

Os campos para `GlacierEventData`, `ReplicationEventData`, `IntelligentTieringEventData` e `LifecycleEventData` serão excluídos do JSON se forem `null`. Outros campos `null` serão serializados como `null`.

Veja a seguir um exemplo de saída do método `toJsonPretty` para um evento de marcação de objetos do S3.

```
{
  "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
      }
    }
  } ]
}
```

Um [exemplo completo](https://github.com/awsdocs/aws-doc-sdk-examples/blob/75c3daadf750406156fc87fa30ee499a206b4a36/javav2/example_code/s3/src/main/java/com/example/s3/ProcessS3EventNotification.java#L117) está disponível em GitHub que mostra como usar a API para trabalhar com notificações recebidas por uma fila do Amazon SQS.

## Processe eventos do S3 no Lambda com bibliotecas Java: e AWS SDK for Java 2.x `aws-lambda-java-events`
<a name="s3-event-notif-processing-options"></a>

Em vez de usar o SDK for Java 2.x para processar notificações de eventos do Amazon S3 em uma função Lambda, você pode usar a biblioteca na versão 3.x.x. `[aws-lambda-java-events](https://github.com/aws/aws-lambda-java-libs/tree/main/aws-lambda-java-events)` AWS mantém a `aws-lambda-java-events` biblioteca de forma independente e tem seus próprios requisitos de dependência. A biblioteca `aws-lambda-java-events` funciona somente com eventos do S3 nas funções do Lambda, enquanto o SDK para Java 2.x funciona com eventos do S3 nas funções do Lambda, Amazon SNS e Amazon SQS.

Ambas as abordagens modelam a carga útil de notificação de eventos JSON de forma orientada a objetos e similares. APIs A tabela a seguir mostra as diferenças notáveis entre o uso das duas abordagens.


****  

|  | AWS SDK para Java | aws-lambda-java-events biblioteca | 
| --- | --- | --- | 
| Nomeação do pacote |  `software.amazon.awssdk.eventnotifications.s3.model.S3EventNotification`  | com.amazonaws.services.lambda.runtime.events.models.s3.S3EventNotification | 
| Parâmetro RequestHandler |  Escreva a implementação `RequestHandler` da função do Lambda para receber uma string 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>  | Escreva a implementação RequestHandler da função do Lambda para receber um objeto 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> | 
| Dependências do 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>  | 

# Trabalhe com de Amazon Simple Notification Service
<a name="examples-simple-notification-service"></a>

Com o Amazon Simple Notification Service, é possível enviar facilmente mensagens de notificação em tempo real dos aplicativos aos assinantes em vários canais de comunicação. Este tópico descreve como executar algumas das funções básicas do Amazon SNS.

## Criar um tópico
<a name="sns-create-topic"></a>

Um **tópico** é um agrupamento lógico de canais de comunicação que define para quais sistemas enviar uma mensagem, por exemplo, espalhando uma mensagem do AWS Lambda e um webhook HTTP. Você envia mensagens para o Amazon SNS, e elas são distribuídas para os canais definidos no tópico. Isso disponibiliza as mensagens para os assinantes.

Para criar um tópico, primeiro compile um objeto [CreateTopicRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/sns/model/CreateTopicRequest.html) com o nome do conjunto de tópicos usando o método `name()` no compilador. Envie o objeto de solicitação para o Amazon SNS usando o método `createTopic()` do [SnsClient](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/sns/SnsClient.html). É possível capturar o resultado dessa solicitação como um objeto [CreateTopicResponse](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/sns/model/CreateTopicResponse.html), conforme demonstrado no trecho de código a seguir.

 **Importações** 

```
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;
```

 **Código da** 

```
    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 "";
    }
```

Veja o [exemplo completo](https://github.com/awsdocs/aws-doc-sdk-examples/blob/da520cb4436f8567a90b6f73f77232fd590a50bf/javav2/example_code/sns/src/main/java/com/example/sns/CreateTopic.java) no GitHub.

## Listar seus tópicos do Amazon SNS
<a name="sns-crelistate-topics"></a>

Para recuperar uma lista dos tópicos existentes do Amazon SNS, compile um objeto [ListTopicsRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/sns/model/ListTopicsRequest.html). Envie o objeto de solicitação para o Amazon SNS usando o método `listTopics()` do `SnsClient`. É possível capturar o resultado dessa solicitação como um objeto [ListTopicsResponse](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/sns/model/ListTopicsResponse.html).

O trecho de código a seguir imprime o código de status HTTP da solicitação e uma lista de nomes de recurso da Amazon (ARNs) para os tópicos do Amazon SNS.

 **Importações** 

```
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;
```

 **Código da** 

```
    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);
        }
    }
```

Veja o [exemplo completo](https://github.com/awsdocs/aws-doc-sdk-examples/blob/da520cb4436f8567a90b6f73f77232fd590a50bf/javav2/example_code/sns/src/main/java/com/example/sns/ListTopics.java) no GitHub.

## Inscrever um endpoint em um tópico
<a name="sns-subscribe-endpoint-topic"></a>

Depois de criar um tópico, é possível configurar quais canais de comunicação serão endpoints para esse tópico. As mensagens são distribuídas para esses endpoints após o Amazon SNS recebê-las.

Para configurar um canal de comunicação como um endpoint para um tópico, inscreva esse endpoint no tópico. Para iniciar, compile um objeto [SubscribeRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/sns/model/SubscribeRequest.html). Especifique o canal de comunicação (por exemplo, `lambda` ou `email`) como `protocol()`. Defina o `endpoint()` como o local de saída relevante (por exemplo, o ARN de uma função do Lambda ou um endereço de e-mail) e defina o ARN do tópico ao qual você deseja se inscrever como `topicArn()`. Envie o objeto de solicitação para o Amazon SNS usando o método `subscribe()` do `SnsClient`. É possível capturar o resultado dessa solicitação como um objeto [SubscribeResponse](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/sns/model/SubscribeResponse.html).

O trecho de código a seguir mostra como inscrever um endereço de e-mail em um tópico.

 **Importações** 

```
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;
```

 **Código da** 

```
    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);
        }
    }
```

Veja o [exemplo completo](https://github.com/awsdocs/aws-doc-sdk-examples/blob/da520cb4436f8567a90b6f73f77232fd590a50bf/javav2/example_code/sns/src/main/java/com/example/sns/SubscribeEmail.java) no GitHub.

## Publicar uma mensagem em um tópico
<a name="sns-publish-message-topic"></a>

Depois de ter um tópico e um ou mais endpoints configurados para ele, será possível publicar uma mensagem nele. Para iniciar, compile um objeto [PublishRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/sns/model/PublishRequest.html). Especifique a `message()` a ser enviada e o ARN do tópico (`topicArn()`) para o qual enviá-la. Envie o objeto de solicitação para o Amazon SNS usando o método `publish()` do `SnsClient`. É possível capturar o resultado dessa solicitação como um objeto [PublishResponse](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/sns/model/PublishResponse.html).

 **Importações** 

```
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;
```

 **Código da** 

```
    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);
         }
    }
```

Veja o [exemplo completo](https://github.com/awsdocs/aws-doc-sdk-examples/blob/da520cb4436f8567a90b6f73f77232fd590a50bf/javav2/example_code/sns/src/main/java/com/example/sns/PublishTopic.java) no GitHub.

## Cancelar a inscrição de um endpoint de um tópico
<a name="sns-unsubscribe-endpoint-topic"></a>

Você pode remover os canais de comunicação configurados como endpoints de um tópico. Depois de fazer isso, o tópico em si continua a existir e distribuir mensagens para quaisquer endpoints finais configurados para esse tópico.

Para remover um canal de comunicação como um endpoint de um tópico, cancele a inscrição desse endpoint do tópico. Para começar, compile um objeto [UnsubscribeRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/sns/model/UnsubscribeRequest.html) e defina o ARN do tópico do qual você deseja cancelar a inscrição como o `subscriptionArn()`. Envie o objeto de solicitação para o SNS usando o método `unsubscribe()` do `SnsClient`. É possível capturar o resultado dessa solicitação como um objeto [UnsubscribeResponse](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/sns/model/UnsubscribeResponse.html).

 **Importações** 

```
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;
```

 **Código da** 

```
    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);
        }
    }
```

Veja o [exemplo completo](https://github.com/awsdocs/aws-doc-sdk-examples/blob/da520cb4436f8567a90b6f73f77232fd590a50bf/javav2/example_code/sns/src/main/java/com/example/sns/Unsubscribe.java) no GitHub.

## Excluir um tópico
<a name="sns-delete-topic"></a>

Para excluir um tópico do Amazon SNS, primeiro compile um objeto [DeleteTopicRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/sns/model/DeleteTopicRequest.html) com o ARN do tópico definido como o método `topicArn()` no compilador. Envie o objeto de solicitação para o Amazon SNS usando o método `deleteTopic()` do `SnsClient`. É possível capturar o resultado dessa solicitação como um objeto [DeleteTopicResponse](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/sns/model/DeleteTopicResponse.html), conforme demonstrado no trecho de código a seguir.

 **Importações** 

```
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;
```

 **Código da** 

```
    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);
        }
    }
```

Veja o [exemplo completo](https://github.com/awsdocs/aws-doc-sdk-examples/blob/da520cb4436f8567a90b6f73f77232fd590a50bf/javav2/example_code/sns/src/main/java/com/example/sns/DeleteTopic.java) no GitHub.

Para obter mais informações, consulte o [Guia do desenvolvedor do Amazon Simple Notification Service](https://docs.aws.amazon.com/sns/latest/dg/).

# Trabalhe com de Amazon Simple Queue Service
<a name="examples-sqs"></a>

Esta seção apresenta exemplos de como programar o [Amazon Simple Queue Service](https://docs.aws.amazon.com/sqs/) usando o AWS SDK para Java 2.x.

Os exemplos a seguir incluem somente o código necessário para demonstrar cada técnica. O [código de exemplo completo está disponível no GitHub](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/javav2). A partir daí, você pode fazer download de um único arquivo de origem ou clonar o repositório de maneira local para obter todos os exemplos para compilação e execução.

**Topics**
+ [Usar o agrupamento em lotes automático de solicitações](sqs-auto-batch.md)
+ [Operações de fila](examples-sqs-message-queues.md)
+ [Operações de mensagens](examples-sqs-messages.md)

# Use o agrupamento automático de solicitações para o Amazon SQS com o AWS SDK for Java 2.x
<a name="sqs-auto-batch"></a>

A API de agrupamento em lotes automáticos de solicitações para Amazon SQS é uma biblioteca de alto nível que fornece uma maneira eficiente de agrupar e armazenar solicitações em buffer para operações do SQS. Ao usar a API de agrupamento em lotes, você reduz o número de solicitações para o SQS, o que melhora o throughput e minimiza os custos. 

Como os métodos da API em lote correspondem aos métodos `[SqsAsyncClient](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/sqs/SqsAsyncClient.html)`: `sendMessage`, `changeMessageVisibility`, `deleteMessage`, `receiveMessage`, você pode usar a API em lote como uma substituição imediata com o mínimo de alterações. 

Este tópico fornece uma visão geral de como configurar e trabalhar com a API de agrupamento em lotes automático de solicitações para o Amazon SQS.

## Confira os pré-requisitos
<a name="sqs-auto-batch-requirements"></a>

Você precisa usar a versão *2.28.0* ou posterior do SDK para Java 2.x para ter acesso à API de agrupamento em lotes. O `pom.xml` do Maven deve conter pelo menos os elementos a seguir.

```
<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 [Versão mais recente](https://central.sonatype.com/artifact/software.amazon.awssdk/bom)

## Criar um gerenciador de lotes
<a name="sqs-auto-batch-create"></a>

A API automática de envio em lote de solicitações é implementada pela [SqsAsyncBatchManager](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/sqs/batchmanager/SqsAsyncBatchManager.html)interface. É possível criar uma instância do gerente de duas maneiras.

### Configuração padrão usando `SqsAsyncClient`
<a name="sqs-batch-manager-create-default"></a>

A maneira mais simples de criar um gerenciador de lotes é chamar o método de `batchManager` fábrica em uma [SqsAsyncClient](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/sqs/SqsAsyncClient.html)instância existente. A abordagem simples é mostrada no trecho a seguir. 

```
SqsAsyncClient asyncClient = SqsAsyncClient.create();
SqsAsyncBatchManager sqsAsyncBatchManager = asyncClient.batchManager();
```

Quando você usa essa abordagem, a instância `SqsAsyncBatchManager` usa os valores padrão que são mostrados na tabela na seção [Substituir configurações para `SqsAsyncBatchManager`](#sqs-auto-batch-config-settings). Além disso, a instância `SqsAsyncBatchManager` usa o `ExecutorService` da instância `SqsAsyncClient` da qual foi criada.

### Configuração personalizada usando `SqsAsyncBatchManager.Builder`
<a name="sqs-batch-manager-create-custom"></a>

Para casos de uso mais avançados, você pode personalizar o gerenciador de lotes usando o [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). Ao usar essa abordagem para criar uma instância `SqsAsyncBatchManager`, você pode ajustar o comportamento do agrupamento em lotes. O trecho a seguir mostra um exemplo de como usar o compilador para personalizar o comportamento em lote.

```
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();
```

Ao usar essa abordagem, é possível ajustar as configurações do objeto `BatchOverrideConfiguration` que são mostradas na tabela na seção [Substituir configurações para `SqsAsyncBatchManager`](#sqs-auto-batch-config-settings). Você também pode fornecer uma personalização [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) para o gerenciador de lotes usando essa abordagem.

## Enviar mensagens
<a name="sqs-auto-batch-send"></a>

Para enviar mensagens com o gerenciador de lotes, use o método `[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))`. O SDK armazena as solicitações em buffer e as envia em lote quando os valores `maxBatchSize` ou `sendRequestFrequency` são atingidos.

O exemplo a seguir mostra uma solicitação `sendMessage` imediatamente seguida por outra solicitação. Nesse caso, o SDK envia as duas mensagens em um único lote.

```
// 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();
```

## Alterar o tempo limite de visibilidade de mensagens
<a name="sqs-auto-batch-change-vis"></a>

É possível alterar o tempo limite de visibilidade das mensagens em um lote usando o método [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)). O SDK armazena as solicitações em buffer e as envia em lote quando os valores `maxBatchSize` ou `sendRequestFrequency` são atingidos.

O exemplo a seguir mostra como chamar o método `changeMessageVisibility`.

```
CompletableFuture<ChangeMessageVisibilityResponse> futureOne =
    sqsAsyncBatchManager.changeMessageVisibility(r -> 
        r.receiptHandle("receiptHandle")
         .queueUrl("queue"));
ChangeMessageVisibilityResponse response = futureOne.join();
```

## Exclua mensagens
<a name="sqs-auto-batch-delete"></a>

É possível excluir mensagens em um lote usando o método [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)). O SDK armazena as solicitações em buffer e as envia em lote quando os valores `maxBatchSize` ou `sendRequestFrequency` são atingidos.

O exemplo a seguir mostra como é possível chamar o método `deleteMessage`.

```
CompletableFuture<DeleteMessageResponse> futureOne = 
    sqsAsyncBatchManager.deleteMessage(r -> 
        r.receiptHandle("receiptHandle")
         .queueUrl("queue"));
DeleteMessageResponse response = futureOne.join();
```

## Receber mensagens
<a name="sqs-auto-batch-receive"></a>

### Usar configurações padrão
<a name="sqs-auto-batch-receive-default-settings"></a>

Quando você pesquisa o método `[SqsAsyncBatchManager\$1receiveMessage](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/sqs/batchmanager/SqsAsyncBatchManager.html#receiveMessage(java.util.function.Consumer))` na aplicação, o gerenciador de lotes busca mensagens do buffer interno, que o SDK atualiza automaticamente em segundo plano.

O exemplo a seguir mostra como chamar o método `receiveMessage`.

```
CompletableFuture<ReceiveMessageResponse> responseFuture = 
    sqsAsyncBatchManager.receiveMessage(r -> r.queueUrl("queueUrl"));
```

### Usar configurações personalizadas
<a name="sqs-auto-batch-receive-custom-settings"></a>

Se quiser personalizar ainda mais a solicitação, por exemplo, definindo tempos de espera personalizados e especificando o número de mensagens a serem recuperadas, você poderá personalizar a solicitação conforme mostrado no exemplo a seguir.

```
CompletableFuture<ReceiveMessageResponse> response = 
    sqsAsyncBatchManager.receiveMessage(r -> 
        r.queueUrl("queueUrl")
         .waitTimeSeconds(5)
         .visibilityTimeout(20));
```

**nota**  
Se você chamar `receiveMessage` com um `[ReceiveMessageRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/sqs/model/ReceiveMessageRequest.html)` que inclua qualquer um dos parâmetros a seguir, o SDK ignorará o gerenciador de lotes e enviará uma solicitação `receiveMessage` assíncrona regular:  
`messageAttributeNames`
`messageSystemAttributeNames`
`messageSystemAttributeNamesWithStrings`
`overrideConfiguration`

## Substituir configurações para `SqsAsyncBatchManager`
<a name="sqs-auto-batch-config-settings"></a>

É possível ajustar as seguintes configurações ao criar uma instância `SqsAsyncBatchManager`. A lista de configurações a seguir está disponível no [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).


| Configuração | Description | Valor padrão  | 
| --- | --- | --- | 
| maxBatchSize | Número máximo de solicitações por lote para cada SendMessageBatchRequest, ChangeMessageVisibilityBatchRequest ou DeleteMessageBatchRequest. O valor máximo é 10. | 10 | 
| sendRequestFrequency |  Tempo antes do envio de um lote, a menos que `maxBatchSize` seja atingido antes. Valores mais altos podem reduzir as solicitações, mas aumentar a latência.  | 200 ms | 
| receiveMessageVisibilityTimeout | Tempo limite de visibilidade para mensagens. Se não especificado, o padrão da fila será usado. | Padrão da fila | 
| receiveMessageMinWaitDuration | Tempo mínimo de espera para solicitações receiveMessage. Evite definir como 0 para evitar o desperdício da CPU. | 50 ms | 
| receiveMessageSystemAttributeNames | Lista de [nomes de atributos do sistema](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/sqs/model/MessageSystemAttributeName.html) para solicitar chamadas receiveMessage. | Nenhum | 
| receiveMessageAttributeNames | Lista de [nomes de atributos](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-message-metadata.html#sqs-message-attributes) para solicitar chamadas receiveMessage. | Nenhum | 

# Trabalhe com filas de Amazon Simple Queue Service mensagens
<a name="examples-sqs-message-queues"></a>

Uma *fila de mensagens* é o contêiner lógico usado para enviar mensagens de forma confiável. Amazon Simple Queue Service Existem dois tipos de filas: *padrão* e *First-In, First-Out* (FIFO – Primeiro a entrar, primeiro a sair). Para saber mais sobre as filas e as diferenças entre esses tipos, consulte o [Guia do desenvolvedor do Amazon Simple Queue Service](https://docs.aws.amazon.com//AWSSimpleQueueService/latest/SQSDeveloperGuide/welcome.html).

Este tópico descreve como criar, listar, excluir e obter o URL de uma Amazon Simple Queue Service fila usando o. AWS SDK para Java

A variável `sqsClient` usada nos exemplos a seguir pode ser criada a partir do trecho de código a seguir.

```
SqsClient sqsClient = SqsClient.create();
```

Ao criar um `SqsClient` usando o método estático `create()`, o SDK configura a região usando a [cadeia de provedores de região padrão](region-selection.md#default-region-provider-chain) e as credenciais usando a [cadeia de provedores de credenciais padrão](credentials-chain.md).

## Criar uma fila
<a name="sqs-create-queue"></a>

Use o método `createQueue` do `SqsClient’s` e forneça um objeto `[CreateQueueRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/sqs/model/CreateQueueRequest.html)` que descreva os parâmetros da fila, conforme mostrado no trecho de código a seguir.

 **Importações** 

```
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.sqs.SqsClient;
import software.amazon.awssdk.services.sqs.model.*;
import java.util.List;
```

 **Código** 

```
            CreateQueueRequest createQueueRequest = CreateQueueRequest.builder()
                .queueName(queueName)
                .build();

            sqsClient.createQueue(createQueueRequest);
```

Veja a [amostra completa](https://github.com/awsdocs/aws-doc-sdk-examples/blob/cf25559da654a7b74bec039c0ab9397dc5951dd4/javav2/example_code/sqs/src/main/java/com/example/sqs/SQSExample.java#L52) em GitHub.

## Listar filas
<a name="sqs-list-queues"></a>

Para listar as Amazon Simple Queue Service filas da sua conta, chame o `SqsClient’s` `listQueues` método com um `[ListQueuesRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/sqs/model/ListQueuesRequest.html)` objeto.

Quando você usa a forma do método [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()) que não usa parâmetros, o serviço retorna *todas as filas*, até mil filas. 

É possível fornecer um prefixo de nome da fila para o objeto `[ListQueuesRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/sqs/model/ListQueuesRequest.html)` a fim de limitar os resultados para filas que correspondem a esse prefixo, conforme mostrado no código a seguir.

 **Importações** 

```
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.sqs.SqsClient;
import software.amazon.awssdk.services.sqs.model.*;
import java.util.List;
```

 **Código** 

```
        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);
        }
```

Veja a [amostra completa](https://github.com/awsdocs/aws-doc-sdk-examples/blob/cf25559da654a7b74bec039c0ab9397dc5951dd4/javav2/example_code/sqs/src/main/java/com/example/sqs/SQSExample.java#L79) em GitHub.

## Obter o URL de uma fila
<a name="sqs-get-queue-url"></a>

O código a seguir mostra como obter o URL de uma fila chamando o método `getQueueUrl` do `SqsClient’s` com um objeto `[GetQueueUrlRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/sqs/model/GetQueueUrlRequest.html)`.

 **Importações** 

```
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.sqs.SqsClient;
import software.amazon.awssdk.services.sqs.model.*;
import java.util.List;
```

 **Código** 

```
            GetQueueUrlResponse getQueueUrlResponse =
                sqsClient.getQueueUrl(GetQueueUrlRequest.builder().queueName(queueName).build());
            String queueUrl = getQueueUrlResponse.queueUrl();
            return queueUrl;
```

Veja a [amostra completa](https://github.com/awsdocs/aws-doc-sdk-examples/blob/7486a1a092aa8e16a21698ef26f9d524fef62e55/javav2/example_code/sqs/src/main/java/com/example/sqs/SQSExample.java#L70) em GitHub.

## Excluir uma fila
<a name="sqs-delete-queue"></a>

Forneça o [URL](#sqs-get-queue-url) da fila para o objeto `[DeleteQueueRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/sqs/model/DeleteQueueRequest.html)`. Depois, chame o método `deleteQueue` do `SqsClient’s` para excluir uma fila, conforme mostrado no código a seguir.

 **Importações** 

```
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.sqs.SqsClient;
import software.amazon.awssdk.services.sqs.model.*;
import java.util.List;
```

 **Código** 

```
    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);
        }
    }
```

Veja a [amostra completa](https://github.com/awsdocs/aws-doc-sdk-examples/blob/6240df86c5f17eae1e23d1139d1435c7dc4b2a11/javav2/example_code/sqs/src/main/java/com/example/sqs/DeleteQueue.java#L48) em GitHub.

## Mais informações
<a name="more-information"></a>
+  [CreateQueue](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_CreateQueue.html)na Referência da Amazon Simple Queue Service API
+  [GetQueueUrl](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_GetQueueUrl.html)na Referência da Amazon Simple Queue Service API
+  [ListQueues](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_ListQueues.html)na Referência da Amazon Simple Queue Service API
+  [DeleteQueue](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_DeleteQueue.html)na Referência da Amazon Simple Queue Service API

# Enviar, receber e excluir Amazon Simple Queue Service mensagens
<a name="examples-sqs-messages"></a>

Uma mensagem é um trecho de dados que pode ser enviado e recebido por componentes distribuídos. As mensagens são sempre entregues usando-se uma [fila do SQS](examples-sqs-message-queues.md).

A variável `sqsClient` usada nos exemplos a seguir pode ser criada a partir do trecho de código a seguir.

```
SqsClient sqsClient = SqsClient.create();
```

Ao criar um `SqsClient` usando o método estático `create()`, o SDK configura a região usando a [cadeia de provedores de região padrão](region-selection.md#default-region-provider-chain) e as credenciais usando a [cadeia de provedores de credenciais padrão](credentials-chain.md).

## Enviar uma mensagem
<a name="sqs-message-send"></a>

Adicione uma única mensagem a uma Amazon Simple Queue Service fila chamando o `sendMessage` método SqsClient cliente. Forneça um [SendMessageRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/sqs/model/SendMessageRequest.html)objeto que contenha a [URL](examples-sqs-message-queues.md#sqs-get-queue-url) da fila, o corpo da mensagem e o valor de atraso opcional (em segundos).

 **Importações** 

```
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.sqs.SqsClient;
import software.amazon.awssdk.services.sqs.model.*;
import java.util.List;
```

 **Código** 

```
            sqsClient.sendMessage(SendMessageRequest.builder()
                .queueUrl(queueUrl)
                .messageBody("Hello world!")
                .delaySeconds(10)
                .build());

            sqsClient.sendMessage(sendMsgRequest);
```

## Enviar várias mensagens em uma solicitação
<a name="sqs-messages-send-multiple"></a>

Envie mais de uma mensagem em uma única solicitação usando o método do `sendMessageBatch` do SqsClient . Esse método usa um [SendMessageBatchRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/sqs/model/SendMessageBatchRequest.html)que contém o URL da fila e uma lista de mensagens a serem enviadas. (Cada mensagem é uma [SendMessageBatchRequestEntry](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/sqs/model/SendMessageBatchRequestEntry.html).) Você também pode atrasar o envio de uma mensagem específica, configurando um valor de atraso na mensagem.

 **Importações** 

```
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.sqs.SqsClient;
import software.amazon.awssdk.services.sqs.model.*;
import java.util.List;
```

 **Código** 

```
            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);
```

Veja a [amostra completa](https://github.com/awsdocs/aws-doc-sdk-examples/blob/cf25559da654a7b74bec039c0ab9397dc5951dd4/javav2/example_code/sqs/src/main/java/com/example/sqs/SQSExample.java#L133) em GitHub.

## Recuperar mensagens
<a name="sqs-messages-receive"></a>

Recupere todas as mensagens que estejam atualmente na fila chamando o método do `receiveMessage` do SqsClient . Esse método usa um [ReceiveMessageRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/sqs/model/ReceiveMessageRequest.html)que contém o URL da fila. Você também pode especificar o número máximo de mensagens para retornar. As mensagens são retornadas como uma lista de objetos [Message](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/sqs/model/Message.html).

 **Importações** 

```
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.sqs.SqsClient;
import software.amazon.awssdk.services.sqs.model.*;
import java.util.List;
```

 **Código** 

```
        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;
```

Veja a [amostra completa](https://github.com/awsdocs/aws-doc-sdk-examples/blob/cf25559da654a7b74bec039c0ab9397dc5951dd4/javav2/example_code/sqs/src/main/java/com/example/sqs/SQSExample.java#L148) em GitHub.

## Excluir uma mensagem após o recebimento
<a name="sqs-messages-delete"></a>

Após receber uma mensagem e processar o conteúdo, exclua a mensagem da fila enviando o identificador de recebimento da mensagem e o URL da fila para o método [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)) do `SqsClient's`.

 **Importações** 

```
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.sqs.SqsClient;
import software.amazon.awssdk.services.sqs.model.*;
import java.util.List;
```

 **Código** 

```
        try {
            for (Message message : messages) {
                DeleteMessageRequest deleteMessageRequest = DeleteMessageRequest.builder()
                        .queueUrl(queueUrl)
                        .receiptHandle(message.receiptHandle())
                        .build();
                sqsClient.deleteMessage(deleteMessageRequest);
            }
```

Veja a [amostra completa](https://github.com/awsdocs/aws-doc-sdk-examples/blob/cf25559da654a7b74bec039c0ab9397dc5951dd4/javav2/example_code/sqs/src/main/java/com/example/sqs/SQSExample.java#L187) em GitHub.

## Mais informações
<a name="more-info"></a>
+  [Como Amazon Simple Queue Service as filas funcionam](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-basic-architecture.html) no Guia do Amazon Simple Queue Service desenvolvedor
+  [SendMessage](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_SendMessage.html)na Referência da Amazon Simple Queue Service API
+  [SendMessageBatch](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_SendMessageBatch.html)na Referência da Amazon Simple Queue Service API
+  [ReceiveMessage](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_ReceiveMessage.html)na Referência da Amazon Simple Queue Service API
+  [DeleteMessage](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_DeleteMessage.html)na Referência da Amazon Simple Queue Service API

# Trabalhe com Amazon Transcribe
<a name="examples-transcribe"></a>

O exemplo a seguir mostra como o streaming bidirecional funciona usando o Amazon Transcribe. O streaming bidirecional indica que há um streaming de dados que vai para o serviço e que é recebido de volta em tempo real. O exemplo usa a transcrição de Amazon Transcribe streaming para enviar um fluxo de áudio e receber um fluxo de texto transcrito em tempo real.

Consulte [Transcrição de streaming](https://docs.aws.amazon.com//transcribe/latest/dg/streaming.html) no Guia do Amazon Transcribe desenvolvedor para saber mais sobre esse recurso.

Consulte [Introdução](https://docs.aws.amazon.com//transcribe/latest/dg/getting-started.html) no Guia do Amazon Transcribe desenvolvedor para começar a usar Amazon Transcribe.

## Configurar o microfone
<a name="set-up-the-microphone"></a>

Esse código usa o pacote javax.sound.sampled para fazer streaming de áudio de um dispositivo de entrada.

 **Código** 

```
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;
    }
}
```

Veja o [exemplo completo](https://github.com/awsdocs/aws-doc-sdk-examples/blob/ac748d8ef99cd17e297cb74fe13aa671e2679088/javav2/example_code/transcribe/src/main/java/com/amazonaws/transcribe/Microphone.java) em GitHub.

## Criar um publicador
<a name="create-a-publisher"></a>

Esse código implementa um editor que publica dados de áudio do fluxo de Amazon Transcribe áudio.

 **Código** 

```
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();
        }
    }
}
```

Veja o [exemplo completo](https://github.com/awsdocs/aws-doc-sdk-examples/blob/ac748d8ef99cd17e297cb74fe13aa671e2679088/javav2/example_code/transcribe/src/main/java/com/amazonaws/transcribe/AudioStreamPublisher.java) em GitHub.

## Criar o cliente e iniciar o streaming
<a name="create-the-client-and-start-the-stream"></a>

No método principal, crie um objeto de solicitação, inicie o streaming da entrada de áudio e instancie o editor com a entrada de áudio.

Você também deve criar um [StartStreamTranscriptionResponseHandler](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/transcribestreaming/model/StartStreamTranscriptionResponseHandler.html)para especificar como lidar com a resposta de Amazon Transcribe.

Em seguida, use o `startStreamTranscription` método TranscribeStreamingAsyncClient's para iniciar o streaming bidirecional.

 **Importações** 

```
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;
```

 **Código** 

```
    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);
         }
    }
```

Veja o [exemplo completo](https://github.com/awsdocs/aws-doc-sdk-examples/blob/ac748d8ef99cd17e297cb74fe13aa671e2679088/javav2/example_code/transcribe/src/main/java/com/amazonaws/transcribe/BidirectionalStreaming.java) em GitHub.

## Mais informações
<a name="more-info"></a>
+  [Como funciona](https://docs.aws.amazon.com//transcribe/latest/dg/how-it-works.html) no Guia do Amazon Transcribe desenvolvedor.
+  [Conceitos básicos do streaming de áudio](https://docs.aws.amazon.com//transcribe/latest/dg/getting-started.html) no Guia do desenvolvedor do Amazon Transcribe .