기계 번역으로 제공되는 번역입니다. 제공된 번역과 원본 영어의 내용이 상충하는 경우에는 영어 버전이 우선합니다.
AWS SDK for Java의 1.x와 2.x 간 역직렬화 차이점
V2의 비어 있는 컬렉션과 V1의 nulls 비교
SDK for Java v1.x 및 v2.x는 JSON 응답을 비어 있는 목록 및 맵과 역직렬화하는 방식이 다릅니다.
SDK가 목록 또는 맵으로 모델링된 누락 속성이 있는 응답을 수신하면 V1은 누락된 속성을 null로 역직렬화하는 반면, V2는 속성을 변경할 수 없는 비어 있는 컬렉션 객체로 역직렬화합니다.
예를 들어 DynamoDB 클라이언트에서 describeTable 메서드에 대해 반환된 응답을 고려합니다. 다음 예제 메서드에는 글로벌 보조 인덱스가 없는 테이블에서 describeTable 메서드를 실행하는 V2 DynamoDB 클라이언트와 V1 DynamoDB 클라이언트가 포함되어 있습니다.
예 응답에 누락된 목록으로 모델링된 속성의 역직렬화
public void deserializationDiffs(){ DescribeTableResponse v2Response = dynamoDbClientV2.describeTable(builder -> builder.tableName(TABLE_NAME)); // V2 provides has* methods on model objects for list/map members. No null check needed. LOGGER.info( String.valueOf(v2Response.table().hasGlobalSecondaryIndexes()) ); LOGGER.info( String.valueOf(v2Response.table().globalSecondaryIndexes().isEmpty()) ); // V2 deserialize to an empty collection. LOGGER.info(v2Response.table().globalSecondaryIndexes().toString()); // V1 deserialize to null. DescribeTableResult v1Result = dynamoDbClientV1.describeTable(new DescribeTableRequest(TABLE_NAME)); if (v1Result.getTable().getGlobalSecondaryIndexes() != null){ LOGGER.info(v1Result.getTable().getGlobalSecondaryIndexes().toString()); } else { LOGGER.info("The list of global secondary indexes returned by the V1 call is <null>"); } }
다음은 로그된 출력을 보여줍니다.
INFO org.example.DeserializationDifferences:45 - false INFO org.example.DeserializationDifferences:46 - true INFO org.example.DeserializationDifferences:48 - [] INFO org.example.DeserializationDifferences:55 - The list of global secondary indexes returned by the V1 call is <null>
Java SDK 2.x는 null을 반환하는 대신 비어 있는 목록을 역직렬화하고 변경 불가능한 비어 있는 컬렉션에 매핑하여 더 안전하고 간결한 코드를 승격해 관용적인 접근 방식을 취합니다. V2를 사용하면 서비스가 이전 예제에 표시된 hasGlobalSecondaryIndexes와 같이 has* 메서드를 사용하여 목록 또는 맵으로 모델링된 속성을 반환했는지 확인할 수 있습니다.
이 접근 방식은 명시적 null 확인의 필요성을 방지하고 존재하지 않거나 비어 있는 데이터 구문을 처리하기 위한 최신 Java 모범 사례에 부합합니다.
package org.example; import com.amazonaws.regions.Regions; import com.amazonaws.services.dynamodbv2.AmazonDynamoDB; import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClientBuilder; import com.amazonaws.services.dynamodbv2.model.DescribeTableRequest; import com.amazonaws.services.dynamodbv2.model.DescribeTableResult; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import software.amazon.awssdk.services.dynamodb.DynamoDbClient; import software.amazon.awssdk.services.dynamodb.model.BillingMode; import software.amazon.awssdk.services.dynamodb.model.DescribeTableResponse; import software.amazon.awssdk.services.dynamodb.model.KeyType; import software.amazon.awssdk.services.dynamodb.model.ScalarAttributeType; import java.util.UUID; public class DeserializationDifferences { private static final Logger LOGGER = LoggerFactory.getLogger(DeserializationDifferences.class); private static final String TABLE_NAME = "DeserializationTable-" + UUID.randomUUID(); DynamoDbClient dynamoDbClientV2 = DynamoDbClient.create(); AmazonDynamoDB dynamoDbClientV1 = AmazonDynamoDBClientBuilder.standard().withRegion(Regions.US_EAST_1).build(); public static void main(String[] args) { DeserializationDifferences difference = new DeserializationDifferences(); difference.createTable(); difference.deserializationDiffs(); difference.deleteTable(); } public void createTable(){ dynamoDbClientV2.createTable(b -> b .billingMode(BillingMode.PAY_PER_REQUEST) .tableName(TABLE_NAME) .keySchema(b1 -> b1.attributeName("Id").keyType(KeyType.HASH)) .attributeDefinitions(b2 -> b2.attributeName("Id").attributeType(ScalarAttributeType.S))); dynamoDbClientV2.waiter().waitUntilTableExists(b -> b.tableName(TABLE_NAME)); } public void deserializationDiffs(){ DescribeTableResponse v2Response = dynamoDbClientV2.describeTable(builder -> builder.tableName(TABLE_NAME)); // V2 provides has* methods on model objects for list/map members. No null check needed. LOGGER.info( String.valueOf(v2Response.table().hasGlobalSecondaryIndexes()) ); LOGGER.info( String.valueOf(v2Response.table().globalSecondaryIndexes().isEmpty()) ); // V2 deserialize to an empty collection. LOGGER.info(v2Response.table().globalSecondaryIndexes().toString()); // V1 deserialize to null. DescribeTableResult v1Result = dynamoDbClientV1.describeTable(new DescribeTableRequest(TABLE_NAME)); if (v1Result.getTable().getGlobalSecondaryIndexes() != null){ LOGGER.info(v1Result.getTable().getGlobalSecondaryIndexes().toString()); } else { LOGGER.info("The list of global secondary indexes returned by the V1 call is <null>"); } } public void deleteTable(){ dynamoDbClientV2.deleteTable(b -> b.tableName(TABLE_NAME)); dynamoDbClientV2.waiter().waitUntilTableNotExists(b -> b.tableName(TABLE_NAME)); } }
V1 및 V2 클라이언트의 describeTable 메서드에 대한 JSON 응답에는 GlobalSecondaryIndexes 속성이 없습니다.
{ "Table": { "AttributeDefinitions": [ { "AttributeName": "Id", "AttributeType": "S" } ], "BillingModeSummary": { "BillingMode": "PAY_PER_REQUEST", "LastUpdateToPayPerRequestDateTime": ... }, "CreationDateTime": ..., "DeletionProtectionEnabled": false, "ItemCount": 0, "KeySchema": [ { "AttributeName": "Id", "KeyType": "HASH" } ], "ProvisionedThroughput": { "NumberOfDecreasesToday": 0, "ReadCapacityUnits": 0, "WriteCapacityUnits": 0 }, "TableArn": "arn:aws:dynamodb:us-east-1:11111111111:table/DeserializationTable-...", "TableId": "...", "TableName": "DeserializationTable-...", "TableSizeBytes": 0, "TableStatus": "ACTIVE", "TableThroughputModeSummary": { "LastUpdateToPayPerRequestDateTime": ..., "TableThroughputMode": "PAY_PER_REQUEST" }, "WarmThroughput": { "ReadUnitsPerSecond": 12000, "Status": "ACTIVE", "WriteUnitsPerSecond": 4000 } } }