clazz, final String obj) {
+ try {
+ return Enum.valueOf(clazz, obj);
+ } catch (final Exception e) {
+ throw MapperExceptions.failure(e, "Unable to unmarshall the enum value " + obj);
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/services-custom/dynamodb-mapper/src/main/java/software/amazon/awssdk/mapper/dynamodb/ArgumentMarshaller.java b/services-custom/dynamodb-mapper/src/main/java/software/amazon/awssdk/mapper/dynamodb/ArgumentMarshaller.java
new file mode 100644
index 000000000000..138ecac135d4
--- /dev/null
+++ b/services-custom/dynamodb-mapper/src/main/java/software/amazon/awssdk/mapper/dynamodb/ArgumentMarshaller.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License").
+ * You may not use this file except in compliance with the License.
+ * A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0
+ *
+ * or in the "license" file accompanying this file. This file is distributed
+ * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+ * express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package software.amazon.awssdk.mapper.dynamodb;
+
+import software.amazon.awssdk.annotations.SdkPublicApi;
+import software.amazon.awssdk.services.dynamodb.model.AttributeValue;
+
+/**
+ * Interface to make it possible to cache the expensive type determination
+ * behavior.
+ */
+@SdkPublicApi
+public interface ArgumentMarshaller {
+
+ /**
+ * Marshalls the object given into an AttributeValue.
+ */
+ AttributeValue marshall(Object obj);
+
+ interface BooleanAttributeMarshaller extends ArgumentMarshaller {}
+ interface StringAttributeMarshaller extends ArgumentMarshaller {}
+ interface NumberAttributeMarshaller extends ArgumentMarshaller {}
+ interface BinaryAttributeMarshaller extends ArgumentMarshaller {}
+ interface StringSetAttributeMarshaller extends ArgumentMarshaller {}
+ interface NumberSetAttributeMarshaller extends ArgumentMarshaller {}
+ interface BinarySetAttributeMarshaller extends ArgumentMarshaller {}
+ interface ListAttributeMarshaller extends ArgumentMarshaller {}
+ interface MapAttributeMarshaller extends ArgumentMarshaller {}
+}
diff --git a/services-custom/dynamodb-mapper/src/main/java/software/amazon/awssdk/mapper/dynamodb/ArgumentUnmarshaller.java b/services-custom/dynamodb-mapper/src/main/java/software/amazon/awssdk/mapper/dynamodb/ArgumentUnmarshaller.java
new file mode 100644
index 000000000000..6dac8660aed9
--- /dev/null
+++ b/services-custom/dynamodb-mapper/src/main/java/software/amazon/awssdk/mapper/dynamodb/ArgumentUnmarshaller.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License").
+ * You may not use this file except in compliance with the License.
+ * A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0
+ *
+ * or in the "license" file accompanying this file. This file is distributed
+ * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+ * express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package software.amazon.awssdk.mapper.dynamodb;
+
+import software.amazon.awssdk.annotations.SdkPublicApi;
+import java.lang.reflect.Method;
+import java.text.ParseException;
+
+import software.amazon.awssdk.services.dynamodb.model.AttributeValue;
+
+/**
+ * Unmarshaller interface to make it possible to cache the expensive
+ * type-determination behavior necessary when turning a service result back
+ * into an object.
+ */
+@SdkPublicApi
+public interface ArgumentUnmarshaller {
+
+ /**
+ * Asserts that the value given can be processed using the setter given.
+ */
+ void typeCheck(AttributeValue value, Method setter);
+
+ /**
+ * Unmarshalls the {@link AttributeValue} given into an instance of the
+ * appropriate type, as determined by {@link DynamoDBMapper}
+ *
+ * @throws ParseException when unable to parse a date string
+ */
+ Object unmarshall(AttributeValue value) throws ParseException;
+}
diff --git a/services-custom/dynamodb-mapper/src/main/java/software/amazon/awssdk/mapper/dynamodb/AttributeTransformer.java b/services-custom/dynamodb-mapper/src/main/java/software/amazon/awssdk/mapper/dynamodb/AttributeTransformer.java
new file mode 100644
index 000000000000..767c44a063a5
--- /dev/null
+++ b/services-custom/dynamodb-mapper/src/main/java/software/amazon/awssdk/mapper/dynamodb/AttributeTransformer.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License").
+ * You may not use this file except in compliance with the License.
+ * A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0
+ *
+ * or in the "license" file accompanying this file. This file is distributed
+ * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+ * express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package software.amazon.awssdk.mapper.dynamodb;
+
+import software.amazon.awssdk.annotations.SdkPublicApi;
+import java.util.Map;
+
+import software.amazon.awssdk.services.dynamodb.model.AttributeValue;
+
+/**
+ * A hook allowing a custom transform/untransform of the raw attribute
+ * values immediately before writing them into DynamoDB and immediately
+ * after reading them out of DynamoDB, but with extra context about
+ * the model class not available at the raw AmazonDynamoDB level.
+ *
+ * This interface contains both a {@code transform} method and a corresponding
+ * {@code untransform} method. These methods SHOULD be inverses, such that
+ * untransform(transform(value)) == value.
+ */
+@SdkPublicApi
+public interface AttributeTransformer {
+ /**
+ * Parameters for the {@code transform} and {@code untransform} methods,
+ * so we don't have to break the interface in order to add additional
+ * parameters.
+ *
+ * Consuming code should NOT implement this interface.
+ */
+ interface Parameters {
+ /**
+ * Returns the raw attribute values to be transformed or untransformed.
+ * The returned map is not modifiable.
+ *
+ * @return the raw attribute values to transform or untransform
+ */
+ Map getAttributeValues();
+
+ /**
+ * Returns true if this transformation is being called as part of a
+ * partial update operation. If true, the attributes returned by
+ * {@link #getAttributeValues()} do not represent the entire new
+ * item, but only a snapshot of the attributes which are getting
+ * new values.
+ *
+ * Implementations which do not support transforming a partial
+ * view of an item (for example, because they need to calculate a
+ * signature based on all of the item's attributes that won't be valid
+ * if only a subset of the attributes are taken into consideration)
+ * should check this flag and throw an exception rather than than
+ * corrupting the data in DynamoDB.
+ *
+ * This method always returns {@code false} for instances passed to
+ * {@link AttributeTransformer#untransform(Parameters)}.
+ *
+ * @return true if this operation is a partial update, false otherwise
+ */
+ boolean isPartialUpdate();
+
+ /**
+ * @return the type of the model class we're transforming to or from
+ */
+ Class getModelClass();
+
+ /**
+ * @return the mapper config for this operation
+ */
+ DynamoDBMapperConfig getMapperConfig();
+
+ /**
+ * @return the name of the DynamoDB table the attributes were read
+ * from or will be written to
+ */
+ String getTableName();
+
+ /**
+ * @return the name of the hash key for the table
+ */
+ String getHashKeyName();
+
+ /**
+ * @return the name of the range key for the table, if it has one,
+ * otherwise {@code null}
+ */
+ String getRangeKeyName();
+ }
+
+ /**
+ * Transforms the input set of attribute values derived from the model
+ * object before writing them into DynamoDB.
+ *
+ * @param parameters transformation parameters
+ * @return the transformed attribute value map
+ */
+ Map transform(Parameters> parameters);
+
+ /**
+ * Untransform the input set of attribute values read from DynamoDB before
+ * creating a model object from them.
+ *
+ * @param parameters transformation parameters
+ * @return the untransformed attribute value map
+ */
+ Map untransform(Parameters> parameters);
+}
diff --git a/services-custom/dynamodb-mapper/src/main/java/software/amazon/awssdk/mapper/dynamodb/AttributeTransformerChain.java b/services-custom/dynamodb-mapper/src/main/java/software/amazon/awssdk/mapper/dynamodb/AttributeTransformerChain.java
new file mode 100644
index 000000000000..872f82cc1205
--- /dev/null
+++ b/services-custom/dynamodb-mapper/src/main/java/software/amazon/awssdk/mapper/dynamodb/AttributeTransformerChain.java
@@ -0,0 +1,166 @@
+/*
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License").
+ * You may not use this file except in compliance with the License.
+ * A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0
+ *
+ * or in the "license" file accompanying this file. This file is distributed
+ * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+ * express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package software.amazon.awssdk.mapper.dynamodb;
+
+import software.amazon.awssdk.annotations.SdkPublicApi;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import software.amazon.awssdk.services.dynamodb.model.AttributeValue;
+
+/**
+ * A virtual {@code AttributeTransformer} that transforms and untransforms
+ * attributes by running them through a cascading series of child
+ * {@code AttributeTransformer} instances.
+ */
+@SdkPublicApi
+public final class AttributeTransformerChain implements AttributeTransformer {
+
+ private final List transformers;
+
+ /**
+ * Creates a new transformer chain from the given array of transformers.
+ * When transforming attributes, these transformers are invoked from first
+ * to last; when untransforming they are invoked in the opposite order.
+ *
+ * @param transformers the chain of transformers.
+ */
+ public AttributeTransformerChain(
+ final AttributeTransformer... transformers) {
+
+ this(Arrays.asList(transformers));
+ }
+
+ /**
+ * Creates a new transformer chain from the given list of transformers.
+ * When transforming attributes, these transformers are invoked from first
+ * to last; when untransforming they are invoked in the opposite order.
+ *
+ * @param transformers the chain of transformers.
+ */
+ public AttributeTransformerChain(
+ final List transformers) {
+
+ this.transformers = Collections.unmodifiableList(
+ new ArrayList(transformers));
+ }
+
+ /**
+ * @return the transformers in this chain
+ */
+ public List getTransformers() {
+ return transformers;
+ }
+
+ @Override
+ public Map transform(
+ final Parameters> parameters) {
+
+ ProxyParameters> proxy = new ProxyParameters(parameters);
+
+ for (int i = 0; i < transformers.size(); ++i) {
+ proxy.setAttributeValues(transformers.get(i).transform(proxy));
+ }
+
+ return proxy.getAttributeValues();
+ }
+
+ @Override
+ public Map untransform(
+ final Parameters> parameters) {
+
+ ProxyParameters> proxy = new ProxyParameters(parameters);
+
+ for (int i = transformers.size() - 1; i >= 0; --i) {
+ proxy.setAttributeValues(transformers.get(i).untransform(proxy));
+ }
+
+ return proxy.getAttributeValues();
+ }
+
+ @Override
+ public String toString() {
+ return transformers.toString();
+ }
+
+ /**
+ * A {@code Parameters} proxy that intercepts calls to
+ * {@code getAttributeValues} and overrides the return value.
+ */
+ private static class ProxyParameters implements Parameters {
+
+ private final Parameters delegate;
+ private Map values;
+
+ /**
+ * Create a new proxy wrapping the given {@code Parameters} object.
+ *
+ * @param delegate the parameters object to wrap
+ */
+ public ProxyParameters(final Parameters delegate) {
+ this.delegate = delegate;
+ this.values = delegate.getAttributeValues();
+ }
+
+ @Override
+ public Map getAttributeValues() {
+ return values;
+ }
+
+ /**
+ * Changes the attribute values for this instance.
+ *
+ * @param values the new values
+ */
+ public void setAttributeValues(
+ final Map values) {
+ this.values = Collections.unmodifiableMap(values);
+ }
+
+ @Override
+ public boolean isPartialUpdate() {
+ return delegate.isPartialUpdate();
+ }
+
+ @Override
+ public Class getModelClass() {
+ return delegate.getModelClass();
+ }
+
+ @Override
+ public DynamoDBMapperConfig getMapperConfig() {
+ return delegate.getMapperConfig();
+ }
+
+ @Override
+ public String getTableName() {
+ return delegate.getTableName();
+ }
+
+ @Override
+ public String getHashKeyName() {
+ return delegate.getHashKeyName();
+ }
+
+ @Override
+ public String getRangeKeyName() {
+ return delegate.getRangeKeyName();
+ }
+ }
+}
diff --git a/services-custom/dynamodb-mapper/src/main/java/software/amazon/awssdk/mapper/dynamodb/BatchLoadContext.java b/services-custom/dynamodb-mapper/src/main/java/software/amazon/awssdk/mapper/dynamodb/BatchLoadContext.java
new file mode 100644
index 000000000000..cc2ee62c443b
--- /dev/null
+++ b/services-custom/dynamodb-mapper/src/main/java/software/amazon/awssdk/mapper/dynamodb/BatchLoadContext.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License").
+ * You may not use this file except in compliance with the License.
+ * A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0
+ *
+ * or in the "license" file accompanying this file. This file is distributed
+ * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+ * express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+
+package software.amazon.awssdk.mapper.dynamodb;
+
+import software.amazon.awssdk.annotations.SdkPublicApi;
+import java.util.Objects;
+import software.amazon.awssdk.services.dynamodb.model.BatchGetItemRequest;
+import software.amazon.awssdk.services.dynamodb.model.BatchGetItemResponse;
+
+
+/**
+ * Container object that has information about the batch load request made to DynamoDB.
+ *
+ * @author avinam
+ */
+@SdkPublicApi
+public final class BatchLoadContext {
+ /**
+ * The BatchGetItemResponse returned by the DynamoDB client.
+ */
+ private BatchGetItemResponse batchGetItemResult;
+ /**
+ * The BatchGetItemRequest.
+ */
+ private BatchGetItemRequest batchGetItemRequest;
+ /**
+ * The number of times the request has been retried.
+ */
+ private int retriesAttempted;
+
+ /**
+ * Instantiates a new BatchLoadContext.
+ * @param batchGetItemRequest see {@link BatchGetItemRequest}.
+ * */
+ public BatchLoadContext(BatchGetItemRequest batchGetItemRequest) {
+ this.batchGetItemRequest = Objects.requireNonNull(batchGetItemRequest, "batchGetItemRequest");
+ this.batchGetItemResult = null;
+ this.retriesAttempted = 0;
+ }
+
+ /**
+ * @return the BatchGetItemResponse
+ */
+ public BatchGetItemResponse getBatchGetItemResult() {
+ return batchGetItemResult;
+ }
+
+ /**
+ * @return the BatchGetItemResponse
+ */
+ public void setBatchGetItemResult(BatchGetItemResponse batchGetItemResult) {
+ this.batchGetItemResult = batchGetItemResult;
+ }
+
+
+ /**
+ * @return the BatchGetItemRequest.
+ */
+ public BatchGetItemRequest getBatchGetItemRequest() {
+ return batchGetItemRequest;
+ }
+
+ /**
+ * Updates the BatchGetItemRequest for the next retry attempt.
+ */
+ public void setBatchGetItemRequest(BatchGetItemRequest batchGetItemRequest) {
+ this.batchGetItemRequest = batchGetItemRequest;
+ }
+
+ /**
+ * Gets the retriesAttempted.
+ *
+ * @return the retriesAttempted
+ */
+ public int getRetriesAttempted() {
+ return retriesAttempted;
+ }
+
+ /**
+ * Sets retriesAttempted.
+ *
+ * @param retriesAttempted the number of retries attempted
+ */
+ public void setRetriesAttempted(int retriesAttempted) {
+ this.retriesAttempted = retriesAttempted;
+ }
+}
diff --git a/services-custom/dynamodb-mapper/src/main/java/software/amazon/awssdk/mapper/dynamodb/ConversionSchema.java b/services-custom/dynamodb-mapper/src/main/java/software/amazon/awssdk/mapper/dynamodb/ConversionSchema.java
new file mode 100644
index 000000000000..0de861a1ed0c
--- /dev/null
+++ b/services-custom/dynamodb-mapper/src/main/java/software/amazon/awssdk/mapper/dynamodb/ConversionSchema.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License").
+ * You may not use this file except in compliance with the License.
+ * A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0
+ *
+ * or in the "license" file accompanying this file. This file is distributed
+ * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+ * express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package software.amazon.awssdk.mapper.dynamodb;
+
+import software.amazon.awssdk.annotations.SdkPublicApi;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * A strategy for mapping between Java types and DynamoDB types. Serves as a
+ * factory for {@code ItemConverter} instances that implement this mapping.
+ * Standard implementations are available in the {@link ConversionSchemas}
+ * class.
+ */
+@SdkPublicApi
+public interface ConversionSchema {
+
+ /**
+ * Dependency injection for the {@code ItemConverter}s that this
+ * {@code ConversionSchema} generates.
+ */
+ static class Dependencies {
+
+ private final Map, Object> values;
+
+ public Dependencies() {
+ values = new HashMap, Object>();
+ }
+
+ @SuppressWarnings("unchecked")
+ public T get(Class clazz) {
+ return (T) values.get(clazz);
+ }
+
+ public Dependencies with(Class clazz, T value) {
+ values.put(clazz, value);
+ return this;
+ }
+
+ @Override
+ public String toString() {
+ return values.toString();
+ }
+ }
+
+ /**
+ * Creates an {@code ItemConverter}, injecting dependencies from the
+ * {@code DynamoDBMapper} that needs it.
+ *
+ * @param dependencies the dependencies to inject
+ * @return a new ItemConverter
+ */
+ ItemConverter getConverter(Dependencies dependencies);
+}
diff --git a/services-custom/dynamodb-mapper/src/main/java/software/amazon/awssdk/mapper/dynamodb/ConversionSchemas.java b/services-custom/dynamodb-mapper/src/main/java/software/amazon/awssdk/mapper/dynamodb/ConversionSchemas.java
new file mode 100644
index 000000000000..a008dc186201
--- /dev/null
+++ b/services-custom/dynamodb-mapper/src/main/java/software/amazon/awssdk/mapper/dynamodb/ConversionSchemas.java
@@ -0,0 +1,1493 @@
+/*
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License").
+ * You may not use this file except in compliance with the License.
+ * A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0
+ *
+ * or in the "license" file accompanying this file. This file is distributed
+ * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+ * express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package software.amazon.awssdk.mapper.dynamodb;
+
+import software.amazon.awssdk.annotations.SdkPublicApi;
+import software.amazon.awssdk.mapper.dynamodb.ArgumentMarshaller.BinaryAttributeMarshaller;
+import software.amazon.awssdk.mapper.dynamodb.ArgumentMarshaller.BinarySetAttributeMarshaller;
+import software.amazon.awssdk.mapper.dynamodb.ArgumentMarshaller.BooleanAttributeMarshaller;
+import software.amazon.awssdk.mapper.dynamodb.ArgumentMarshaller.ListAttributeMarshaller;
+import software.amazon.awssdk.mapper.dynamodb.ArgumentMarshaller.MapAttributeMarshaller;
+import software.amazon.awssdk.mapper.dynamodb.ArgumentMarshaller.NumberAttributeMarshaller;
+import software.amazon.awssdk.mapper.dynamodb.ArgumentMarshaller.NumberSetAttributeMarshaller;
+import software.amazon.awssdk.mapper.dynamodb.ArgumentMarshaller.StringAttributeMarshaller;
+import software.amazon.awssdk.mapper.dynamodb.ArgumentMarshaller.StringSetAttributeMarshaller;
+import software.amazon.awssdk.mapper.dynamodb.DynamoDBMapperFieldModel.DynamoDBAttributeType;
+import software.amazon.awssdk.mapper.dynamodb.StandardBeanProperties.Bean;
+import software.amazon.awssdk.mapper.dynamodb.StandardModelFactories.Rule;
+import software.amazon.awssdk.mapper.dynamodb.StandardModelFactories.RuleFactory;
+import software.amazon.awssdk.mapper.dynamodb.internal.marshallers.BooleanSetToNumberSetMarshaller;
+import software.amazon.awssdk.mapper.dynamodb.internal.marshallers.BooleanToBooleanMarshaller;
+import software.amazon.awssdk.mapper.dynamodb.internal.marshallers.BooleanToNumberMarshaller;
+import software.amazon.awssdk.mapper.dynamodb.internal.marshallers.ByteArraySetToBinarySetMarshaller;
+import software.amazon.awssdk.mapper.dynamodb.internal.marshallers.ByteArrayToBinaryMarshaller;
+import software.amazon.awssdk.mapper.dynamodb.internal.marshallers.ByteBufferSetToBinarySetMarshaller;
+import software.amazon.awssdk.mapper.dynamodb.internal.marshallers.ByteBufferToBinaryMarshaller;
+import software.amazon.awssdk.mapper.dynamodb.internal.marshallers.CalendarSetToStringSetMarshaller;
+import software.amazon.awssdk.mapper.dynamodb.internal.marshallers.CalendarToStringMarshaller;
+import software.amazon.awssdk.mapper.dynamodb.internal.marshallers.CollectionToListMarshaller;
+import software.amazon.awssdk.mapper.dynamodb.internal.marshallers.CustomMarshaller;
+import software.amazon.awssdk.mapper.dynamodb.internal.marshallers.DateSetToStringSetMarshaller;
+import software.amazon.awssdk.mapper.dynamodb.internal.marshallers.DateToStringMarshaller;
+import software.amazon.awssdk.mapper.dynamodb.internal.marshallers.MapToMapMarshaller;
+import software.amazon.awssdk.mapper.dynamodb.internal.marshallers.NumberSetToNumberSetMarshaller;
+import software.amazon.awssdk.mapper.dynamodb.internal.marshallers.NumberToNumberMarshaller;
+import software.amazon.awssdk.mapper.dynamodb.internal.marshallers.ObjectSetToStringSetMarshaller;
+import software.amazon.awssdk.mapper.dynamodb.internal.marshallers.ObjectToMapMarshaller;
+import software.amazon.awssdk.mapper.dynamodb.internal.marshallers.ObjectToStringMarshaller;
+import software.amazon.awssdk.mapper.dynamodb.internal.marshallers.S3LinkToStringMarshaller;
+import software.amazon.awssdk.mapper.dynamodb.internal.marshallers.StringSetToStringSetMarshaller;
+import software.amazon.awssdk.mapper.dynamodb.internal.marshallers.StringToStringMarshaller;
+import software.amazon.awssdk.mapper.dynamodb.internal.marshallers.UUIDSetToStringSetMarshaller;
+import software.amazon.awssdk.mapper.dynamodb.internal.unmarshallers.BigDecimalSetUnmarshaller;
+import software.amazon.awssdk.mapper.dynamodb.internal.unmarshallers.BigDecimalUnmarshaller;
+import software.amazon.awssdk.mapper.dynamodb.internal.unmarshallers.BigIntegerSetUnmarshaller;
+import software.amazon.awssdk.mapper.dynamodb.internal.unmarshallers.BigIntegerUnmarshaller;
+import software.amazon.awssdk.mapper.dynamodb.internal.unmarshallers.BooleanSetUnmarshaller;
+import software.amazon.awssdk.mapper.dynamodb.internal.unmarshallers.BooleanUnmarshaller;
+import software.amazon.awssdk.mapper.dynamodb.internal.unmarshallers.ByteArraySetUnmarshaller;
+import software.amazon.awssdk.mapper.dynamodb.internal.unmarshallers.ByteArrayUnmarshaller;
+import software.amazon.awssdk.mapper.dynamodb.internal.unmarshallers.ByteBufferSetUnmarshaller;
+import software.amazon.awssdk.mapper.dynamodb.internal.unmarshallers.ByteBufferUnmarshaller;
+import software.amazon.awssdk.mapper.dynamodb.internal.unmarshallers.ByteSetUnmarshaller;
+import software.amazon.awssdk.mapper.dynamodb.internal.unmarshallers.ByteUnmarshaller;
+import software.amazon.awssdk.mapper.dynamodb.internal.unmarshallers.CalendarSetUnmarshaller;
+import software.amazon.awssdk.mapper.dynamodb.internal.unmarshallers.CalendarUnmarshaller;
+import software.amazon.awssdk.mapper.dynamodb.internal.unmarshallers.CustomUnmarshaller;
+import software.amazon.awssdk.mapper.dynamodb.internal.unmarshallers.DateSetUnmarshaller;
+import software.amazon.awssdk.mapper.dynamodb.internal.unmarshallers.DateUnmarshaller;
+import software.amazon.awssdk.mapper.dynamodb.internal.unmarshallers.DoubleSetUnmarshaller;
+import software.amazon.awssdk.mapper.dynamodb.internal.unmarshallers.DoubleUnmarshaller;
+import software.amazon.awssdk.mapper.dynamodb.internal.unmarshallers.FloatSetUnmarshaller;
+import software.amazon.awssdk.mapper.dynamodb.internal.unmarshallers.FloatUnmarshaller;
+import software.amazon.awssdk.mapper.dynamodb.internal.unmarshallers.IntegerSetUnmarshaller;
+import software.amazon.awssdk.mapper.dynamodb.internal.unmarshallers.IntegerUnmarshaller;
+import software.amazon.awssdk.mapper.dynamodb.internal.unmarshallers.ListUnmarshaller;
+import software.amazon.awssdk.mapper.dynamodb.internal.unmarshallers.LongSetUnmarshaller;
+import software.amazon.awssdk.mapper.dynamodb.internal.unmarshallers.LongUnmarshaller;
+import software.amazon.awssdk.mapper.dynamodb.internal.unmarshallers.MapUnmarshaller;
+import software.amazon.awssdk.mapper.dynamodb.internal.unmarshallers.NullableUnmarshaller;
+import software.amazon.awssdk.mapper.dynamodb.internal.unmarshallers.ObjectSetUnmarshaller;
+import software.amazon.awssdk.mapper.dynamodb.internal.unmarshallers.ObjectUnmarshaller;
+import software.amazon.awssdk.mapper.dynamodb.internal.unmarshallers.S3LinkUnmarshaller;
+import software.amazon.awssdk.mapper.dynamodb.internal.unmarshallers.ShortSetUnmarshaller;
+import software.amazon.awssdk.mapper.dynamodb.internal.unmarshallers.ShortUnmarshaller;
+import software.amazon.awssdk.mapper.dynamodb.internal.unmarshallers.StringSetUnmarshaller;
+import software.amazon.awssdk.mapper.dynamodb.internal.unmarshallers.StringUnmarshaller;
+import software.amazon.awssdk.mapper.dynamodb.internal.unmarshallers.UUIDSetUnmarshaller;
+import software.amazon.awssdk.mapper.dynamodb.internal.unmarshallers.UUIDUnmarshaller;
+import software.amazon.awssdk.services.dynamodb.model.AttributeValue;
+
+import software.amazon.awssdk.utils.Logger;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.nio.ByteBuffer;
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.UUID;
+
+/**
+ * Pre-defined strategies for mapping between Java types and DynamoDB types.
+ */
+@SdkPublicApi
+public final class ConversionSchemas {
+
+ private static final Logger LOGGER = Logger.loggerFor(ConversionSchemas.class);
+
+ /**
+ * The V1 schema mapping, which retains strict backwards compatibility with
+ * the original DynamoDB data model. In particular, it marshals Java
+ * Booleans as DynamoDB Numbers rather than the newer Boolean type, and does
+ * not support marshaling Lists or Maps. It can unmarshal
+ * values written in newer formats to ease migration.
+ *
+ * Use me if you have other code still using an old version of the SDK that
+ * does not understand the new List and Map types and want to ensure that
+ * you don't accidentally start writing values using these types.
+ */
+ public static final ConversionSchema V1 = v1Builder("V1ConversionSchema").build();
+
+ /**
+ * A V2 conversion schema which retains backwards compatibility with the
+ * V1 conversion schema for existing DynamoDB types, but adds the ability
+ * to marshall recursive structures using the new List and Map types. This
+ * is currently the default conversion schema.
+ */
+ public static final ConversionSchema V2_COMPATIBLE = v2CompatibleBuilder(
+ "V2CompatibleConversionSchema").build();
+
+ /**
+ * The native V2 conversion schema. This schema breaks compatibility with
+ * older versions of the mapper that only support the V1 schema by
+ * storing booleans as native DynamoDB Booleans rather than as a 1 or 0
+ * in a DynamoDB Number. Switching to the V2 schema will prevent older
+ * versions of the mapper from reading items you write that contain
+ * booleans.
+ */
+ public static final ConversionSchema V2 = v2Builder("V2ConversionSchema").build();
+
+ static final ConversionSchema DEFAULT = V2_COMPATIBLE;
+
+ /**
+ * A ConversionSchema builder that defaults to building {@link #V1}.
+ */
+ public static Builder v1Builder(String name) {
+ return new Builder(name, V1MarshallerSet.marshallers(), V1MarshallerSet.setMarshallers(),
+ StandardUnmarshallerSet.unmarshallers(),
+ StandardUnmarshallerSet.setUnmarshallers());
+ }
+
+ /**
+ * A ConversionSchema builder that defaults to building {@link #V2_COMPATIBLE}.
+ */
+ public static Builder v2CompatibleBuilder(String name) {
+ return new Builder(name, V2CompatibleMarshallerSet.marshallers(),
+ V2CompatibleMarshallerSet.setMarshallers(),
+ StandardUnmarshallerSet.unmarshallers(),
+ StandardUnmarshallerSet.setUnmarshallers());
+ }
+
+ /**
+ * A ConversionSchema builder that defaults to building {@link #V2}.
+ */
+ public static Builder v2Builder(String name) {
+ return new Builder(name, V2MarshallerSet.marshallers(), V2MarshallerSet.setMarshallers(),
+ StandardUnmarshallerSet.unmarshallers(),
+ StandardUnmarshallerSet.setUnmarshallers());
+ }
+
+ public static class Builder {
+
+ private final String name;
+ private final List> marshallers;
+ private final List> setMarshallers;
+ private final List> unmarshallers;
+ private final List> setUnmarshallers;
+
+ Builder(String name, List> marshallers,
+ List> setMarshallers,
+ List> unmarshallers,
+ List> setUnmarshallers) {
+ this.name = name;
+ this.marshallers = marshallers;
+ this.setMarshallers = setMarshallers;
+ this.unmarshallers = unmarshallers;
+ this.setUnmarshallers = setUnmarshallers;
+ }
+
+ /**
+ * Adds marshaling of a type to the schema. Types are in LIFO order, so the last type added
+ * will be the first matched.
+ */
+ public Builder addFirstType(Class> clazz, ArgumentMarshaller marshaller,
+ ArgumentUnmarshaller unmarshaller) {
+ this.marshallers.add(0, Pair.of(clazz, marshaller));
+ this.unmarshallers.add(0, Pair.of(clazz, unmarshaller));
+ return this;
+ }
+
+ /**
+ * Adds marshaling of a Set of a type to the schema. Types are in LIFO order, so the last
+ * type added will be the first matched.
+ */
+ public Builder addFirstSetType(Class> clazz, ArgumentMarshaller marshaller,
+ ArgumentUnmarshaller unmarshaller) {
+ this.setMarshallers.add(0, Pair.of(clazz, marshaller));
+ this.setUnmarshallers.add(0, Pair.of(clazz, unmarshaller));
+ return this;
+ }
+
+ public ConversionSchema build() {
+ return new StandardConversionSchema(name, new AbstractMarshallerSet(marshallers,
+ setMarshallers),
+ new StandardUnmarshallerSet(unmarshallers,
+ setUnmarshallers));
+ }
+ }
+
+ static class StandardConversionSchema implements ConversionSchema {
+
+ private final String name;
+ private final MarshallerSet marshallers;
+ private final UnmarshallerSet unmarshallers;
+
+ public StandardConversionSchema(
+ String name,
+ MarshallerSet marshallers,
+ UnmarshallerSet unmarshallers) {
+
+ this.name = name;
+ this.marshallers = new CachingMarshallerSet(
+ new AnnotationAwareMarshallerSet(marshallers));
+
+ this.unmarshallers = new CachingUnmarshallerSet(
+ new AnnotationAwareUnmarshallerSet(unmarshallers));
+ }
+
+ @Override
+ public ItemConverter getConverter(Dependencies dependencies) {
+
+ S3ClientCache s3cc = dependencies.get(S3ClientCache.class);
+
+ return new StandardItemConverter(
+ marshallers,
+ unmarshallers,
+ s3cc);
+ }
+
+ @Override
+ public String toString() {
+ return name;
+ }
+ }
+
+
+ static class StandardItemConverter implements ItemConverter {
+
+ private final MarshallerSet marshallerSet;
+ private final UnmarshallerSet unmarshallerSet;
+ private final S3ClientCache s3cc;
+
+ public StandardItemConverter(
+ MarshallerSet marshallerSet,
+ UnmarshallerSet unmarshallerSet,
+ S3ClientCache s3cc) {
+
+ this.marshallerSet = marshallerSet;
+ this.unmarshallerSet = unmarshallerSet;
+ this.s3cc = s3cc;
+ }
+
+ @Override
+ public DynamoDBMapperFieldModel getFieldModel(Method getter) {
+ ArgumentMarshaller marshaller = getMarshaller(getter);
+
+ DynamoDBAttributeType attributeType;
+ if (marshaller instanceof StringAttributeMarshaller) {
+ attributeType = DynamoDBAttributeType.S;
+ } else if (marshaller instanceof NumberAttributeMarshaller) {
+ attributeType = DynamoDBAttributeType.N;
+ } else if (marshaller instanceof BinaryAttributeMarshaller) {
+ attributeType = DynamoDBAttributeType.B;
+ } else if (marshaller instanceof StringSetAttributeMarshaller) {
+ attributeType = DynamoDBAttributeType.SS;
+ } else if (marshaller instanceof NumberSetAttributeMarshaller) {
+ attributeType = DynamoDBAttributeType.NS;
+ } else if (marshaller instanceof BinarySetAttributeMarshaller) {
+ attributeType = DynamoDBAttributeType.BS;
+ } else if (marshaller instanceof BooleanAttributeMarshaller) {
+ attributeType = DynamoDBAttributeType.BOOL;
+ } else if (marshaller instanceof ListAttributeMarshaller) {
+ attributeType = DynamoDBAttributeType.L;
+ } else if (marshaller instanceof MapAttributeMarshaller) {
+ attributeType = DynamoDBAttributeType.M;
+ } else {
+ throw new DynamoDBMappingException(
+ "Unrecognized marshaller type for " + getter + ": "
+ + marshaller);
+ }
+
+ // Note, generating the attribute name using this method is not
+ // actually correct for @DynamoDBFlattened attributes, however,
+ // its the best that can be done given only the method. The
+ // proper way to get this information is using the model factory.
+ StandardAnnotationMaps.FieldMap annotations = StandardAnnotationMaps.of(getter, null);
+ DynamoDBMapperFieldModel.Builder builder = new DynamoDBMapperFieldModel.Builder(void.class, annotations);
+ builder.with(attributeType);
+ return builder.build();
+ }
+
+ @Override
+ public AttributeValue convert(Method getter, Object object) {
+ if (object == null) {
+ return null;
+ }
+
+ ArgumentMarshaller marshaller = getMarshaller(getter);
+ return marshaller.marshall(object);
+ }
+
+ @Override
+ public Map convert(Object object) {
+ if (object == null) {
+ return null;
+ }
+
+ Class