

Las traducciones son generadas a través de traducción automática. En caso de conflicto entre la traducción y la version original de inglés, prevalecerá la version en inglés.

# Trabaje con documentos JSON con la API de documentos mejorada para DynamoDB
<a name="ddb-en-client-doc-api"></a>

La [API de documentos mejorada](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/document/package-summary.html) para AWS SDK for Java 2.x está diseñada para funcionar con datos orientados a documentos que no tienen un esquema fijo. Sin embargo, también le permite utilizar clases personalizadas para asignar atributos individuales.

 La API de documentos mejorada es la sucesora de la [API de documentos](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/dynamodbv2/document/DynamoDB.html) de la AWS SDK para Java versión 1.x.

**Contents**
+ [Introducción al uso de API de documentos mejorada](ddb-en-client-doc-api-steps.md)
  + [Crear un `DocumentTableSchema` y una `DynamoDbTable`.](ddb-en-client-doc-api-steps.md#ddb-en-client-doc-api-steps-createschema)
+ [Crear documentos mejorados](ddb-en-client-doc-api-steps-create-ed.md)
  + [Compilar a partir de una cadena JSON](ddb-en-client-doc-api-steps-create-ed.md#ddb-en-client-doc-api-steps-create-ed-fromJson)
  + [Construir a partir de elementos individuales](ddb-en-client-doc-api-steps-create-ed.md#ddb-en-client-doc-api-steps-create-ed-fromparts)
+ [Operaciones CRUD](ddb-en-client-doc-api-steps-use.md)
+ [Acceder a los atributos mejorados del documento como objetos personalizados](ddb-en-client-doc-api-convert.md)
+ [Utilizar un `EnhancedDocument` sin DynamoDB](ddb-en-client-doc-api-standalone.md)

# Introducción al uso de API de documentos mejorada
<a name="ddb-en-client-doc-api-steps"></a>

La API de documentos mejorada requiere las mismas [dependencias](ddb-en-client-getting-started.md#ddb-en-client-gs-dep) que se necesitan para la API de cliente mejorado de DynamoDB. También requiere una [instancia de `DynamoDbEnhancedClient`](ddb-en-client-getting-started-dynamodbTable.md#ddb-en-client-getting-started-dynamodbTable-eclient), como se muestra al principio de este tema.

Como la API de documentos mejorada se publicó con la versión 2.20.3 de AWS SDK for Java 2.x, necesita esa versión o una superior.

## Crear un `DocumentTableSchema` y una `DynamoDbTable`.
<a name="ddb-en-client-doc-api-steps-createschema"></a>

Para invocar comandos en una tabla de DynamoDB mediante la API de documentos mejorada, asocie la tabla a un objeto de recurso < > del lado del [DynamoDbTablecliente EnhancedDocument](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/DynamoDbTable.html). 

El método `table()` del cliente mejorado crea una instancia `DynamoDbTable<EnhancedDocument>` y requiere parámetros para el nombre de la tabla de DynamoDB y un `DocumentTableSchema`. 

El generador de a [DocumentTableSchema](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/document/DocumentTableSchema.html)requiere una clave de índice principal y uno o más proveedores de convertidores de atributos. El método `AttributeConverterProvider.defaultProvider()` proporciona convertidores para los [tipos predeterminados](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/internal/converter/attribute/package-summary.html). Debe especificarse incluso si proporciona un proveedor de convertidores de atributos personalizado. Puede añadir una clave de índice secundaria opcional al generador.

El siguiente fragmento de código muestra el código que genera la representación del lado de una tabla `person` de DynamoDB que almacena objetos `EnhancedDocument` sin 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.
```

A continuación, se muestra la representación JSON de un objeto `person` que se utiliza en esta sección.

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

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

Un `[EnhancedDocument](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/document/EnhancedDocument.html)` representa un objeto de tipo documento que tiene una estructura compleja con atributos anidados. Un `EnhancedDocument` requiere atributos de nivel superior que coincidan con los atributos clave principales especificados para el `DocumentTableSchema`. El contenido restante es arbitrario y puede consistir en atributos de nivel superior y también en atributos profundamente anidados.

Para crear una instancia `EnhancedDocument`, utilice un generador que proporciona varias formas de añadir elementos.

## Compilar a partir de una cadena JSON
<a name="ddb-en-client-doc-api-steps-create-ed-fromJson"></a>

Con una cadena JSON, puede construir un `EnhancedDocument` en una llamada al método. El siguiente fragmento de código crea un `EnhancedDocument` a partir de una cadena JSON devuelta por el método auxiliar `jsonPerson()`. El método `jsonPerson()` devuelve la versión de cadena JSON del [objeto persona](ddb-en-client-doc-api-steps.md#ddb-en-client-doc-api-steps-createschema-obj) mostrado anteriormente.

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

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

Alternativamente, puede construir una instancia `EnhancedDocument` a partir de componentes individuales utilizando métodos seguros de tipo del constructor.

En el ejemplo siguiente, se crea un documento mejorado `person` similar al que se crea a partir de la cadena JSON del ejemplo 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"));

    }
```

# Operaciones CRUD
<a name="ddb-en-client-doc-api-steps-use"></a>

Una vez definida una instancia `EnhancedDocument`, puede guardarla en una tabla de DynamoDB. El siguiente fragmento de código utiliza el [PersonDocument](ddb-en-client-doc-api-steps-create-ed.md#ddb-en-client-doc-api-steps-create-ed-fromparts) que se creó a partir de elementos individuales.

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

Después de leer una instancia de documento mejorada de DynamoDB, puede extraer los valores individuales de los atributos utilizando getters como se muestra en el siguiente fragmento de código que accede a los datos guardados del `personDocument`. Como alternativa, puede extraer el contenido completo en una cadena JSON, como se muestra en la última parte del código de ejemplo.

```
        // 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`las instancias se pueden usar con cualquier método `[DynamoDbTable](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/DynamoDbTable.html)` o [DynamoDbEnhancedClient](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/DynamoDbEnhancedClient.html)en lugar de las clases de datos mapeadas.

# Acceder a los atributos mejorados del documento como objetos personalizados
<a name="ddb-en-client-doc-api-convert"></a>

Además de proporcionar una API para leer y escribir atributos con estructuras sin esquema, la API de documentos mejorada te permite convertir atributos desde y hacia instancias de clases personalizadas.

La API del cliente mejorado utiliza `AttributeConverterProvider`s y `AttributeConverter`s que se mostraron en la sección de [conversión de atributos de control](ddb-en-client-adv-features-conversion.md) como parte de la API del cliente mejorado de DynamoDB.

En el ejemplo siguiente, utilizamos a `CustomAttributeConverterProvider` con su clase `AddressConverter` anidada para convertir objetos `Address`. 

En este ejemplo se muestra que se pueden mezclar datos de clases y también datos de estructuras que se crean según sea necesario. En este ejemplo también se muestra que las clases personalizadas se pueden utilizar en cualquier nivel de una estructura anidada. Los objetos `Address` de este ejemplo son valores que se utilizan en un 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'}
```

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

## Clase `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 proporciona direcciones
<a name="ddb-en-client-doc-api-convert-helper"></a>

El siguiente método auxiliar proporciona el mapa que utiliza instancias `Address` personalizadas para los valores en lugar de instancias `Map<String, String>` genéricas para los 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);
    }
```

# Utilizar un `EnhancedDocument` sin DynamoDB
<a name="ddb-en-client-doc-api-standalone"></a>

Aunque normalmente se utiliza una instancia de un `EnhancedDocument` para leer y escribir elementos de DynamoDB de tipo documento, también se puede utilizar con independencia de DynamoDB. 

Puede utilizar `EnhancedDocuments` por su capacidad de convertir cadenas JSON u objetos personalizados en mapas de `AttributeValues` de bajo nivel, como se muestra en el siguiente ejemplo.

```
    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**  
Cuando utilice un documento mejorado independiente de una tabla de DynamoDB, asegúrese de establecer explícitamente los proveedores de convertidores de atributos en el generador.  
Por el contrario, el esquema de la tabla de documentos proporciona los proveedores de conversión cuando se utiliza un documento mejorado con una tabla de DynamoDB.