Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .brazil.json
Original file line number Diff line number Diff line change
Expand Up @@ -319,7 +319,7 @@
"skipImport": true
},
"dynamodb-mapper": {
"packageName": "AwsJavaSdk-DynamoDbMapper"
"skipImport": true
}
},
"dependencies": {
Expand Down
30 changes: 3 additions & 27 deletions services-custom/dynamodb-mapper/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -41,35 +41,16 @@
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<!-- v1-coupled tests not yet ported to the v2 client/model; tracked for a dedicated
follow-up port PR. The golden-master ShapeRequestTest/ShapeResponseTest suite
proves the ported data-plane paths are behavior-preserving in the meantime. -->
<!-- The only tests still excluded are the S3Link feature tests. They exercise S3Link
main code that is still on the v1 client/model and is ported in a dedicated
follow-up PR; these come off this list when that port lands. -->
<testExcludes>
<testExclude>software/amazon/awssdk/mapper/dynamodb/ConfigureS3LinksTest.java</testExclude>
<testExclude>software/amazon/awssdk/mapper/dynamodb/DynamoDBS3IntegrationTest.java</testExclude>
<testExclude>software/amazon/awssdk/mapper/dynamodb/DynamoDBS3IntegrationTestBase.java</testExclude>
<testExclude>software/amazon/awssdk/mapper/dynamodb/GenerateDeleteTableRequestTest.java</testExclude>
<testExclude>software/amazon/awssdk/mapper/dynamodb/GsiAlwaysUpdateTest.java</testExclude>
<testExclude>software/amazon/awssdk/mapper/dynamodb/LocalDynamoDB.java</testExclude>
<testExclude>software/amazon/awssdk/mapper/dynamodb/LocalDynamoDBTestBase.java</testExclude>
<testExclude>software/amazon/awssdk/mapper/dynamodb/S3ClientCacheIntegrationTest.java</testExclude>
<testExclude>software/amazon/awssdk/mapper/dynamodb/S3LinkIDTest.java</testExclude>
<testExclude>software/amazon/awssdk/mapper/dynamodb/S3LinkTest.java</testExclude>
<testExclude>software/amazon/awssdk/mapper/dynamodb/BatchLoadTest.java</testExclude>
<testExclude>software/amazon/awssdk/mapper/dynamodb/mapper/BatchWriteTest.java</testExclude>
<!-- Blocked on Table-admin: calls mapper.generateCreateTableRequest(), which still
returns a v1 CreateTableRequest. Rides with the GenerateCreateTableRequest* PR. -->
<testExclude>software/amazon/awssdk/mapper/dynamodb/JsonIntegrationTest.java</testExclude>
<testExclude>software/amazon/awssdk/mapper/dynamodb/mapper/GenerateCreateTableRequest2Test.java</testExclude>
<testExclude>software/amazon/awssdk/mapper/dynamodb/mapper/GenerateCreateTableRequestTest.java</testExclude>
<testExclude>software/amazon/awssdk/mapper/dynamodb/mapper/HashKeyOnlyTableWithGSITest.java</testExclude>
<testExclude>software/amazon/awssdk/mapper/dynamodb/mapper/MapperLoadingStrategyConfigTest.java</testExclude>
<testExclude>software/amazon/awssdk/mapper/dynamodb/test/resources/DynamoDBTableResource.java</testExclude>
<testExclude>software/amazon/awssdk/mapper/dynamodb/test/resources/ResourceCentricBlockJUnit4ClassRunner.java</testExclude>
<testExclude>software/amazon/awssdk/mapper/dynamodb/test/resources/TestResourceUtils.java</testExclude>
<testExclude>software/amazon/awssdk/mapper/dynamodb/test/resources/tables/BasicTempTable.java</testExclude>
<testExclude>software/amazon/awssdk/mapper/dynamodb/test/resources/tables/TempTableWithBinaryKey.java</testExclude>
<testExclude>software/amazon/awssdk/mapper/dynamodb/test/resources/tables/TempTableWithSecondaryIndexes.java</testExclude>
</testExcludes>
</configuration>
</plugin>
Expand Down Expand Up @@ -126,11 +107,6 @@
<artifactId>dynamodb</artifactId>
<version>${awsjavasdk.version}</version>
</dependency>
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk-dynamodb</artifactId>
<version>${sdk-v1.version}</version>
</dependency>
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk-s3</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@

import software.amazon.awssdk.mapper.dynamodb.DynamoDBMapper.FailedBatch;
import software.amazon.awssdk.services.dynamodb.model.AttributeValue;
import com.amazonaws.services.dynamodbv2.model.CreateTableRequest;
import com.amazonaws.services.dynamodbv2.model.DeleteTableRequest;
import software.amazon.awssdk.services.dynamodb.model.CreateTableRequest;
import software.amazon.awssdk.services.dynamodb.model.DeleteTableRequest;
import com.amazonaws.services.s3.model.Region;

import java.util.Arrays;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
import software.amazon.awssdk.mapper.dynamodb.DynamoDBMapperConfig.ConsistentReads;
import software.amazon.awssdk.mapper.dynamodb.DynamoDBMapperConfig.SaveBehavior;
import software.amazon.awssdk.services.dynamodb.model.AttributeAction;
import com.amazonaws.services.dynamodbv2.model.AttributeDefinition;
import software.amazon.awssdk.services.dynamodb.model.AttributeDefinition;
import software.amazon.awssdk.services.dynamodb.model.AttributeValue;
import software.amazon.awssdk.services.dynamodb.model.AttributeValueUpdate;
import software.amazon.awssdk.services.dynamodb.model.BatchGetItemRequest;
Expand All @@ -35,18 +35,20 @@
import software.amazon.awssdk.services.dynamodb.model.ConditionCheck;
import software.amazon.awssdk.services.dynamodb.model.ConditionalCheckFailedException;
import software.amazon.awssdk.services.dynamodb.model.ConditionalOperator;
import com.amazonaws.services.dynamodbv2.model.CreateTableRequest;
import software.amazon.awssdk.services.dynamodb.model.CreateTableRequest;
import software.amazon.awssdk.services.dynamodb.model.Delete;
import software.amazon.awssdk.services.dynamodb.model.DeleteItemRequest;
import software.amazon.awssdk.services.dynamodb.model.DeleteRequest;
import com.amazonaws.services.dynamodbv2.model.DeleteTableRequest;
import software.amazon.awssdk.services.dynamodb.model.DeleteTableRequest;
import software.amazon.awssdk.services.dynamodb.model.ExpectedAttributeValue;
import software.amazon.awssdk.services.dynamodb.model.Get;
import software.amazon.awssdk.services.dynamodb.model.GetItemRequest;
import software.amazon.awssdk.services.dynamodb.model.GetItemResponse;
import software.amazon.awssdk.services.dynamodb.model.GlobalSecondaryIndex;
import software.amazon.awssdk.services.dynamodb.model.ItemResponse;
import com.amazonaws.services.dynamodbv2.model.KeySchemaElement;
import software.amazon.awssdk.services.dynamodb.model.KeySchemaElement;
import software.amazon.awssdk.services.dynamodb.model.KeysAndAttributes;
import software.amazon.awssdk.services.dynamodb.model.LocalSecondaryIndex;
import software.amazon.awssdk.services.dynamodb.model.Put;
import software.amazon.awssdk.services.dynamodb.model.PutItemRequest;
import software.amazon.awssdk.services.dynamodb.model.PutItemResponse;
Expand All @@ -55,7 +57,7 @@
import software.amazon.awssdk.services.dynamodb.model.QueryResponse;
import software.amazon.awssdk.services.dynamodb.model.ReturnValue;
import software.amazon.awssdk.services.dynamodb.model.ReturnValuesOnConditionCheckFailure;
import com.amazonaws.services.dynamodbv2.model.ScalarAttributeType;
import software.amazon.awssdk.services.dynamodb.model.ScalarAttributeType;
import software.amazon.awssdk.services.dynamodb.model.ScanRequest;
import software.amazon.awssdk.services.dynamodb.model.ScanResponse;
import software.amazon.awssdk.services.dynamodb.model.Select;
Expand Down Expand Up @@ -2255,31 +2257,44 @@ public <T> CreateTableRequest generateCreateTableRequest(Class<T> clazz, DynamoD
config = mergeConfig(config);
final DynamoDBMapperTableModel<T> model = getTableModel(clazz, config);

final CreateTableRequest request = new CreateTableRequest();
request.setTableName(getTableName(clazz, config));
request.withKeySchema(new KeySchemaElement(model.hashKey().name(), com.amazonaws.services.dynamodbv2.model.KeyType.HASH));
final List<KeySchemaElement> keySchema = new ArrayList<KeySchemaElement>();
keySchema.add(KeySchemaElement.builder().attributeName(model.hashKey().name()).keyType(HASH).build());
if (model.rangeKeyIfExists() != null) {
request.withKeySchema(new KeySchemaElement(model.rangeKey().name(), com.amazonaws.services.dynamodbv2.model.KeyType.RANGE));
keySchema.add(KeySchemaElement.builder().attributeName(model.rangeKey().name()).keyType(RANGE).build());
}
request.setGlobalSecondaryIndexes(model.globalSecondaryIndexes());
request.setLocalSecondaryIndexes(model.localSecondaryIndexes());

final List<AttributeDefinition> attributeDefinitions = new ArrayList<AttributeDefinition>();
for (final DynamoDBMapperFieldModel<T,Object> field : model.fields()) {
if (field.keyType() != null || field.indexed()) {
request.withAttributeDefinitions(new AttributeDefinition()
.withAttributeType(ScalarAttributeType.valueOf(field.attributeType().name()))
.withAttributeName(field.name())
);
attributeDefinitions.add(AttributeDefinition.builder()
.attributeType(ScalarAttributeType.valueOf(field.attributeType().name()))
.attributeName(field.name())
.build());
}
}
return request;

final CreateTableRequest.Builder request = CreateTableRequest.builder()
.tableName(getTableName(clazz, config))
.keySchema(keySchema)
.attributeDefinitions(attributeDefinitions);
// globalSecondaryIndexes()/localSecondaryIndexes() rebuild their collections on every call and
// return null (not empty) when the class declares none, so read once and guard on null to keep
// the v1 behavior of leaving the field unset.
final Collection<GlobalSecondaryIndex> globalSecondaryIndexes = model.globalSecondaryIndexes();
if (globalSecondaryIndexes != null) {
request.globalSecondaryIndexes(globalSecondaryIndexes);
}
final Collection<LocalSecondaryIndex> localSecondaryIndexes = model.localSecondaryIndexes();
if (localSecondaryIndexes != null) {
request.localSecondaryIndexes(localSecondaryIndexes);
}
return request.build();
}

@Override
public <T> DeleteTableRequest generateDeleteTableRequest(Class<T> clazz, DynamoDBMapperConfig config) {
config = mergeConfig(config);
DeleteTableRequest deleteTableRequest = new DeleteTableRequest();
deleteTableRequest.setTableName(getTableName(clazz, config));
return deleteTableRequest;
return DeleteTableRequest.builder().tableName(getTableName(clazz, config)).build();
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,18 @@

import static software.amazon.awssdk.services.dynamodb.model.KeyType.HASH;
import static software.amazon.awssdk.services.dynamodb.model.KeyType.RANGE;
import static com.amazonaws.services.dynamodbv2.model.ProjectionType.KEYS_ONLY;
import static software.amazon.awssdk.services.dynamodb.model.ProjectionType.KEYS_ONLY;

import software.amazon.awssdk.services.dynamodb.model.AttributeValue;
import software.amazon.awssdk.services.dynamodb.model.KeyType;
import com.amazonaws.services.dynamodbv2.model.GlobalSecondaryIndex;
import com.amazonaws.services.dynamodbv2.model.KeySchemaElement;
import com.amazonaws.services.dynamodbv2.model.LocalSecondaryIndex;
import com.amazonaws.services.dynamodbv2.model.Projection;
import com.amazonaws.services.dynamodbv2.model.ProjectionType;
import software.amazon.awssdk.services.dynamodb.model.GlobalSecondaryIndex;
import software.amazon.awssdk.services.dynamodb.model.KeySchemaElement;
import software.amazon.awssdk.services.dynamodb.model.LocalSecondaryIndex;
import software.amazon.awssdk.services.dynamodb.model.Projection;

import java.util.Arrays;
import java.util.ArrayList;
import java.util.List;
import java.util.Collection;
import java.util.Collections;
import java.util.EnumMap;
Expand Down Expand Up @@ -190,12 +190,15 @@ public GlobalSecondaryIndex globalSecondaryIndex(final String indexName) {
return null;
}
final GlobalSecondaryIndex gsi = globalSecondaryIndexes.get(indexName);
final GlobalSecondaryIndex copy = new GlobalSecondaryIndex().withIndexName(gsi.getIndexName());
copy.withProjection(new Projection().withProjectionType(gsi.getProjection().getProjectionType()));
for (final KeySchemaElement key : gsi.getKeySchema()) {
copy.withKeySchema(new KeySchemaElement(key.getAttributeName(), key.getKeyType()));
final List<KeySchemaElement> keySchema = new ArrayList<KeySchemaElement>();
for (final KeySchemaElement key : gsi.keySchema()) {
keySchema.add(KeySchemaElement.builder().attributeName(key.attributeName()).keyType(key.keyType()).build());
}
return copy;
return GlobalSecondaryIndex.builder()
.indexName(gsi.indexName())
.projection(Projection.builder().projectionType(gsi.projection().projectionType()).build())
.keySchema(keySchema)
.build();
}

/**
Expand Down Expand Up @@ -224,12 +227,15 @@ public LocalSecondaryIndex localSecondaryIndex(final String indexName) {
return null;
}
final LocalSecondaryIndex lsi = localSecondaryIndexes.get(indexName);
final LocalSecondaryIndex copy = new LocalSecondaryIndex().withIndexName(lsi.getIndexName());
copy.withProjection(new Projection().withProjectionType(lsi.getProjection().getProjectionType()));
for (final KeySchemaElement key : lsi.getKeySchema()) {
copy.withKeySchema(new KeySchemaElement(key.getAttributeName(), key.getKeyType()));
final List<KeySchemaElement> keySchema = new ArrayList<KeySchemaElement>();
for (final KeySchemaElement key : lsi.keySchema()) {
keySchema.add(KeySchemaElement.builder().attributeName(key.attributeName()).keyType(key.keyType()).build());
}
return copy;
return LocalSecondaryIndex.builder()
.indexName(lsi.indexName())
.projection(Projection.builder().projectionType(lsi.projection().projectionType()).build())
.keySchema(keySchema)
.build();
}

/**
Expand Down Expand Up @@ -371,49 +377,61 @@ public Builder<T> with(final DynamoDBMapperFieldModel<T,Object> field) {
}

public Map<String,GlobalSecondaryIndex> globalSecondaryIndexes() {
final Map<String,GlobalSecondaryIndex> map = new LinkedHashMap<String,GlobalSecondaryIndex>();
// v2 index models are immutable, so stage each index's key schema and build once. The hash
// key is collected first and the range key (if any) appended in a second pass, matching v1.
final Map<String,List<KeySchemaElement>> keySchemasByIndex = new LinkedHashMap<String,List<KeySchemaElement>>();
for (final DynamoDBMapperFieldModel<T,Object> field : fields.values()) {
for (final String indexName : field.globalSecondaryIndexNames(HASH)) {
final GlobalSecondaryIndex gsi = new GlobalSecondaryIndex().withIndexName(indexName);
if (map.put(indexName, gsi) != null) {
final List<KeySchemaElement> keySchema = new ArrayList<KeySchemaElement>();
keySchema.add(KeySchemaElement.builder().attributeName(field.name()).keyType(KeyType.HASH).build());
if (keySchemasByIndex.put(indexName, keySchema) != null) {
throw new DynamoDBMappingException(
targetType.getSimpleName() + "[" + field.name() + "]; must not duplicate GSI " + indexName
);
}
gsi.withProjection(new Projection().withProjectionType(KEYS_ONLY));
gsi.withKeySchema(new KeySchemaElement(field.name(), com.amazonaws.services.dynamodbv2.model.KeyType.HASH));
}
}
for (final DynamoDBMapperFieldModel<T,Object> field : fields.values()) {
for (final String indexName : field.globalSecondaryIndexNames(RANGE)) {
final GlobalSecondaryIndex gsi = map.get(indexName);
if (gsi == null) {
final List<KeySchemaElement> keySchema = keySchemasByIndex.get(indexName);
if (keySchema == null) {
throw new DynamoDBMappingException(
targetType.getSimpleName() + "[" + field.name() + "]; no HASH key for GSI " + indexName
);
}
gsi.withKeySchema(new KeySchemaElement(field.name(), com.amazonaws.services.dynamodbv2.model.KeyType.RANGE));
keySchema.add(KeySchemaElement.builder().attributeName(field.name()).keyType(KeyType.RANGE).build());
}
}
if (map.isEmpty()) {
if (keySchemasByIndex.isEmpty()) {
return Collections.<String,GlobalSecondaryIndex>emptyMap();
}
final Map<String,GlobalSecondaryIndex> map = new LinkedHashMap<String,GlobalSecondaryIndex>();
for (final Map.Entry<String,List<KeySchemaElement>> entry : keySchemasByIndex.entrySet()) {
map.put(entry.getKey(), GlobalSecondaryIndex.builder()
.indexName(entry.getKey())
.projection(Projection.builder().projectionType(KEYS_ONLY).build())
.keySchema(entry.getValue())
.build());
}
return Collections.unmodifiableMap(map);
}

public Map<String,LocalSecondaryIndex> localSecondaryIndexes() {
final Map<String,LocalSecondaryIndex> map = new LinkedHashMap<String,LocalSecondaryIndex>();
for (final DynamoDBMapperFieldModel<T,Object> field : fields.values()) {
for (final String indexName : field.localSecondaryIndexNames()) {
final LocalSecondaryIndex lsi = new LocalSecondaryIndex().withIndexName(indexName);
final LocalSecondaryIndex lsi = LocalSecondaryIndex.builder()
.indexName(indexName)
.projection(Projection.builder().projectionType(KEYS_ONLY).build())
.keySchema(
KeySchemaElement.builder().attributeName(keys.get(HASH).name()).keyType(KeyType.HASH).build(),
KeySchemaElement.builder().attributeName(field.name()).keyType(KeyType.RANGE).build())
.build();
if (map.put(indexName, lsi) != null) {
throw new DynamoDBMappingException(
targetType.getSimpleName() + "[" + field.name() + "]; must not duplicate LSI " + indexName
);
}
lsi.withProjection(new Projection().withProjectionType(KEYS_ONLY));
lsi.withKeySchema(new KeySchemaElement(keys.get(HASH).name(), com.amazonaws.services.dynamodbv2.model.KeyType.HASH));
lsi.withKeySchema(new KeySchemaElement(field.name(), com.amazonaws.services.dynamodbv2.model.KeyType.RANGE));
}
}
if (map.isEmpty()) {
Expand Down
Loading
Loading