All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapperFieldModel Maven / Gradle / Ivy

Go to download

The AWS SDK for Java with support for OSGi. The AWS SDK for Java provides Java APIs for building software on AWS' cost-effective, scalable, and reliable infrastructure products. The AWS Java SDK allows developers to code against APIs for all of Amazon's infrastructure web services (Amazon S3, Amazon EC2, Amazon SQS, Amazon Relational Database Service, Amazon AutoScaling, etc).

There is a newer version: 1.11.60
Show newest version
/*
 * Copyright 2011-2016 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.
 * You may obtain a copy of the License at:
 *
 *    http://aws.amazon.com/apache2.0
 *
 * 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 com.amazonaws.services.dynamodbv2.datamodeling;

import static com.amazonaws.services.dynamodbv2.model.KeyType.HASH;
import static com.amazonaws.services.dynamodbv2.model.KeyType.RANGE;

import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapperConfig.SaveBehavior;
import com.amazonaws.services.dynamodbv2.datamodeling.StandardTypeConverters.Vector;
import com.amazonaws.services.dynamodbv2.model.AttributeDefinition;
import com.amazonaws.services.dynamodbv2.model.AttributeValue;
import com.amazonaws.services.dynamodbv2.model.ComparisonOperator;
import com.amazonaws.services.dynamodbv2.model.Condition;
import com.amazonaws.services.dynamodbv2.model.ExpectedAttributeValue;
import com.amazonaws.services.dynamodbv2.model.KeyType;
import com.amazonaws.services.dynamodbv2.model.ScalarAttributeType;

import java.util.Arrays;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * Field model.
 *
 * @param  The object type.
 * @param  The field model type.
 */
public class DynamoDBMapperFieldModel implements DynamoDBAutoGenerator, DynamoDBTypeConverter {

    public static enum DynamoDBAttributeType { B, N, S, BS, NS, SS, BOOL, NULL, L, M; };

    private final Id id;
    private final Reflect reflect;
    private final DynamoDBMapperValueConverter converter;
    private final Properties properties;

    @Deprecated
    private ArgumentMarshaller argumentMarshaller;
    private DynamoDBAttributeType dynamoDBAttributeType;

    /**
     * {@deprecated}
     */
    @Deprecated
    public DynamoDBMapperFieldModel(
            String dynamoDBAttributeName,
            DynamoDBAttributeType dynamoDBAttributeType,
            ArgumentMarshaller argumentMarshaller) {
        this.id = new Id((Class)Void.class, dynamoDBAttributeName);
        this.properties = new Properties.Builder().withAttributeName(dynamoDBAttributeName);
        this.reflect = null;
        this.converter = null;
        this.dynamoDBAttributeType = dynamoDBAttributeType;
        this.argumentMarshaller = argumentMarshaller;
    }

    /**
     * Creates a new field model instance.
     * @param builder The builder.
     */
    private DynamoDBMapperFieldModel(final Builder builder) {
        this.id = builder.id;
        this.properties = builder.properties;
        this.reflect = builder.reflect;
        this.converter = builder.converter;
    }

    /**
     * Returns the name of the DynamoDB attribute this mapped field will be
     * stored as.
     */
    public String getDynamoDBAttributeName() {
        return properties.attributeName();
    }

    /**
     * Returns the type of the DynamoDB attribute this mapped field will be
     * stored as.
     */
    public DynamoDBAttributeType getDynamoDBAttributeType() {
        return converter == null ? dynamoDBAttributeType : converter.getDynamoDBAttributeType();
    }

    /**
     * (Internal usage only)
     * Returns the argument marshaller that is bound to this mapped field.
     */
    @Deprecated
    ArgumentMarshaller getArgumentMarshaller() {
        return argumentMarshaller;
    }

    /**
     * Gets the ID.
     * @return The ID.
     */
    public final Id id() {
        return id;
    }

    /**
     * Gets the attribute name.
     * @return The attribute name.
     */
    public final String name() {
        return properties.attributeName();
    }

    /**
     * Gets the value from the object instance.
     * @param object The object instance.
     * @return The value.
     */
    public final V get(final T object) {
        try {
            return reflect.get(object);
        } catch (final RuntimeException e) {
            throw new DynamoDBMappingException(id.format("could not get"), e);
        }
    }

    /**
     * Sets the value on the object instance.
     * @param object The object instance.
     * @param value The value.
     */
    public final void set(final T object, final V value) {
        try {
            reflect.set(object, value);
        } catch (final RuntimeException e) {
            throw new DynamoDBMappingException(id.format("could not set"), e);
        }
    }

    /**
     * Determines if the mapping value can be auto-generated.
     * @param object The object instance.
     * @param saveBehavior The save behaviour.
     * @param model The table model.
     * @return True if can be auto-generated, false otherwise.
     */
    public final boolean canGenerate(final T object, final SaveBehavior saveBehavior, final DynamoDBMapperTableModel model) {
        if (getGenerateStrategy() == null) {
            return false;
        } else if (DynamoDBAutoGenerateStrategy.ALWAYS == getGenerateStrategy()) {
            return true;
        } else if (get(object) != null) {
            return false;
        } else if (anyKey()) {
            return true;
        } else if (saveBehavior == SaveBehavior.CLOBBER || saveBehavior == SaveBehavior.UPDATE) {
            return true;
        } else if (model != null && model.anyKeyGeneratable(object, saveBehavior)) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * Indicates if this attribute is a version attribute.
     * @return True if it is, false otherwise.
     */
    public final boolean versioned() {
        if (properties.autoGenerator() != null) {
            return properties.autoGenerator().getClass() == DynamoDBVersionAttribute.Generator.class;
        }
        return false;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public final DynamoDBAutoGenerateStrategy getGenerateStrategy() {
        if (properties.autoGenerator() != null) {
            return properties.autoGenerator().getGenerateStrategy();
        }
        return null;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public final V generate(final V currentValue) {
        try {
            return properties.autoGenerator().generate(currentValue);
        } catch (final RuntimeException e) {
            throw new DynamoDBMappingException(id.format("could not generate"), e);
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public final AttributeValue convert(final V object) {
        try {
            return converter.convert(object);
        } catch (final RuntimeException e) {
            throw new DynamoDBMappingException(id.format("could not convert"), e);
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public final V unconvert(final AttributeValue object) {
        try {
            return converter.unconvert(object);
        } catch (final RuntimeException e) {
            throw new DynamoDBMappingException(id.format("could not unconvert"), e);
        }
    }

    /**
     * Gets the key type.
     * @return The key type, or null if not a key.
     */
    public final KeyType keyType() {
        return properties.keyType();
    }

    /**
     * Gets the global secondary indexes.
     * @param keyType The key type.
     * @return The list of global secondary indexes.
     */
    public final List globalSecondaryIndexNames(final KeyType keyType) {
        return properties.globalSecondaryIndexNames(keyType);
    }

    /**
     * Gets the local secondary indexes.
     * @return The list of local secondary indexes.
     */
    public final List localSecondaryIndexNames() {
        return properties.localSecondaryIndexNames();
    }

    /**
     * Returns true if the field matches any key or index key.
     * @param keyTypes The key types.
     * @return True if matching any key type.
     */
    public final boolean anyKey(KeyType ... keyTypes) {
        for (final KeyType k : (keyTypes.length == 0 ? KeyType.values() : keyTypes)) {
            if (keyType() == k) {
                return true;
            } else if (!globalSecondaryIndexNames(k).isEmpty()) {
                return true;
            } else if (RANGE == k && !localSecondaryIndexNames().isEmpty()) {
                return true;
            }
        }
        return false;
    }

    /**
     * Gets the attribute deinition for this field.
     * @return The attribute definition.
     */
    public final AttributeDefinition definition() {
        try {
            return new AttributeDefinition(name(), ScalarAttributeType.valueOf(getDynamoDBAttributeType().name()));
        } catch (final RuntimeException e) {
            throw new DynamoDBMappingException(id.format("must be scalar (B, N, or S) but is " + getDynamoDBAttributeType()), e);
        }
    }

    /**
     * Get the current value from the object and generates a new value.
     * @param object The object instance.
     * @return The generated value.
     */
    public final AttributeValue generateAndConvert(final T object) {
        return convert(generate(get(object)));
    }

    /**
     * Get the current value from the object and convert it.
     * @param object The object instance.
     * @return The converted value.
     */
    public final AttributeValue getAndConvert(final T object) {
        return convert(get(object));
    }

    /**
     * Unconverts the value and sets it on the object.
     * @param object The object instance.
     * @param value The attribute value.
     */
    public final void unconvertAndSet(final T object, final AttributeValue value) {
        set(object, unconvert(value));
    }

    /**
     * Converts the object values into {@code AttributeValue}s.
     * @param values The object values.
     * @return The attribute values.
     */
    public final Collection convertAll(final Collection values) {
        return Vector.convert(values, this);
    }

    /**
     * Unconverts the {@code AttributeValue}s into the object value.
     * @param values The attribute values.
     * @return The field model values.
     */
    public final Collection unconvertAll(final Collection values) {
        return Vector.unconvert(values, this);
    }

    /**
     * Creates an expectation that the value should exist.
     * @param value The value.
     * @return The expected value.
     * @see com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBSaveExpression#withExpectedEntry
     * @see com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBDeleteExpression#withExpectedEntry
     * @see com.amazonaws.services.dynamodbv2.model.ExpectedAttributeValue
     */
    public final ExpectedAttributeValue expectedExists(final V value) {
        return new ExpectedAttributeValue().withExists(true).withValue(convert(value));
    }

    /**
     * Creates an expectation that the value should not exist.
     * @return The expected value.
     * @see com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBSaveExpression#withExpectedEntry
     * @see com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBDeleteExpression#withExpectedEntry
     * @see com.amazonaws.services.dynamodbv2.model.ExpectedAttributeValue
     */
    public final ExpectedAttributeValue expectedNotExists() {
        return new ExpectedAttributeValue().withExists(false);
    }

    /**
     * Creates an expectation that the value should exist if the value is not
     * null or an expectation that the value should not exist otherwise.
     * @param value The value.
     * @return The expected value.
     * @see com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBSaveExpression#withExpectedEntry
     * @see com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBDeleteExpression#withExpectedEntry
     * @see com.amazonaws.services.dynamodbv2.model.ExpectedAttributeValue
     */
    public final ExpectedAttributeValue expectedIfExists(final V value) {
        return value == null ? expectedNotExists() : expectedExists(value);
    }

    /**
     * Creates a condition which filters on the specified value.
     * @param value The value.
     * @return The condition.
     * @see com.amazonaws.services.dynamodbv2.model.ComparisonOperator#BEGINS_WITH
     * @see com.amazonaws.services.dynamodbv2.model.Condition
     */
    public final Condition beginsWith(final V value) {
        return new Condition().withComparisonOperator(ComparisonOperator.BEGINS_WITH).withAttributeValueList(convert(value));
    }

    /**
     * Creates a condition which filters on the specified values.
     * @param lo The start of the range (inclusive).
     * @param hi The end of the range (inclusive).
     * @return The condition.
     * @see com.amazonaws.services.dynamodbv2.model.ComparisonOperator#BETWEEN
     * @see com.amazonaws.services.dynamodbv2.model.Condition
     */
    public final Condition between(final V lo, final V hi) {
        return new Condition().withComparisonOperator(ComparisonOperator.BETWEEN).withAttributeValueList(convert(lo), convert(hi));
    }

    /**
     * Creates a condition which filters on the specified value.
     * @param value The value.
     * @return The condition.
     * @see com.amazonaws.services.dynamodbv2.model.ComparisonOperator#CONTAINS
     * @see com.amazonaws.services.dynamodbv2.model.Condition
     */
    public final Condition contains(final V value) {
        return new Condition().withComparisonOperator(ComparisonOperator.CONTAINS).withAttributeValueList(convert(value));
    }

    /**
     * Creates a condition which filters on the specified value.
     * @param value The value.
     * @return The condition.
     * @see com.amazonaws.services.dynamodbv2.model.ComparisonOperator#EQ
     * @see com.amazonaws.services.dynamodbv2.model.Condition
     */
    public final Condition eq(final V value) {
        return new Condition().withComparisonOperator(ComparisonOperator.EQ).withAttributeValueList(convert(value));
    }

    /**
     * Creates a condition which filters on the specified value.
     * @param value The value.
     * @return The condition.
     * @see com.amazonaws.services.dynamodbv2.model.ComparisonOperator#GE
     * @see com.amazonaws.services.dynamodbv2.model.Condition
     */
    public final Condition ge(final V value) {
        return new Condition().withComparisonOperator(ComparisonOperator.GE).withAttributeValueList(convert(value));
    }

    /**
     * Creates a condition which filters on the specified value.
     * @param value The value.
     * @return The condition.
     * @see com.amazonaws.services.dynamodbv2.model.ComparisonOperator#GT
     * @see com.amazonaws.services.dynamodbv2.model.Condition
     */
    public final Condition gt(final V value) {
        return new Condition().withComparisonOperator(ComparisonOperator.GT).withAttributeValueList(convert(value));
    }

    /**
     * Creates a condition which filters on the specified values.
     * @param values The values.
     * @return The condition.
     * @see com.amazonaws.services.dynamodbv2.model.ComparisonOperator#IN
     * @see com.amazonaws.services.dynamodbv2.model.Condition
     */
    public final Condition in(final V ... values) {
        return new Condition().withComparisonOperator(ComparisonOperator.IN).withAttributeValueList(convertAll(Arrays.asList(values)));
    }

    /**
     * Creates a condition which filters on the specified values.
     * @param values The values.
     * @return The condition.
     * @see com.amazonaws.services.dynamodbv2.model.ComparisonOperator#IN
     * @see com.amazonaws.services.dynamodbv2.model.Condition
     */
    public final Condition in(final Collection values) {
        return new Condition().withComparisonOperator(ComparisonOperator.IN).withAttributeValueList(convertAll(values));
    }

    /**
     * Creates a condition which filters on the specified value.
     * @return The condition.
     * @see com.amazonaws.services.dynamodbv2.model.ComparisonOperator#NULL
     * @see com.amazonaws.services.dynamodbv2.model.Condition
     */
    public final Condition isNull() {
        return new Condition().withComparisonOperator(ComparisonOperator.NULL);
    }

    /**
     * Creates a condition which filters on the specified value.
     * @param value The value.
     * @return The condition.
     * @see com.amazonaws.services.dynamodbv2.model.ComparisonOperator#LE
     * @see com.amazonaws.services.dynamodbv2.model.Condition
     */
    public final Condition le(final V value) {
        return new Condition().withComparisonOperator(ComparisonOperator.LE).withAttributeValueList(convert(value));
    }

    /**
     * Creates a condition which filters on the specified value.
     * @param value The value.
     * @return The condition.
     * @see com.amazonaws.services.dynamodbv2.model.ComparisonOperator#LT
     * @see com.amazonaws.services.dynamodbv2.model.Condition
     */
    public final Condition lt(final V value) {
        return new Condition().withComparisonOperator(ComparisonOperator.LT).withAttributeValueList(convert(value));
    }

    /**
     * Creates a condition which filters on the specified value.
     * @param value The value.
     * @return The condition.
     * @see com.amazonaws.services.dynamodbv2.model.ComparisonOperator#NE
     * @see com.amazonaws.services.dynamodbv2.model.Condition
     */
    public final Condition ne(final V value) {
        return new Condition().withComparisonOperator(ComparisonOperator.NE).withAttributeValueList(convert(value));
    }

    /**
     * Creates a condition which filters on the specified value.
     * @param value The value.
     * @return The condition.
     * @see com.amazonaws.services.dynamodbv2.model.ComparisonOperator#NOT_CONTAINS
     * @see com.amazonaws.services.dynamodbv2.model.Condition
     */
    public final Condition notContains(final V value) {
        return new Condition().withComparisonOperator(ComparisonOperator.NOT_CONTAINS).withAttributeValueList(convert(value));
    }

    /**
     * Creates a condition which filters on the specified value.
     * @return The condition.
     * @see com.amazonaws.services.dynamodbv2.model.ComparisonOperator#NOT_NULL
     * @see com.amazonaws.services.dynamodbv2.model.Condition
     */
    public final Condition notNull() {
        return new Condition().withComparisonOperator(ComparisonOperator.NOT_NULL);
    }

    /**
     * Creates a condition which filters on any non-null argument; if {@code lo}
     * is null a {@code LE} condition is applied on {@code hi}, if {@code hi}
     * is null a {@code GE} condition is applied on {@code lo}.
     * @param lo The start of the range (inclusive).
     * @param hi The end of the range (inclusive).
     * @return The condition or null if both arguments are null.
     * @see com.amazonaws.services.dynamodbv2.model.ComparisonOperator#BETWEEN
     * @see com.amazonaws.services.dynamodbv2.model.ComparisonOperator#EQ
     * @see com.amazonaws.services.dynamodbv2.model.ComparisonOperator#GE
     * @see com.amazonaws.services.dynamodbv2.model.ComparisonOperator#LE
     * @see com.amazonaws.services.dynamodbv2.model.Condition
     */
    public final Condition betweenAny(final V lo, final V hi) {
        return lo == null ? (hi == null ? null : le(hi)) : (hi == null ? ge(lo) : (lo.equals(hi) ? eq(lo) : between(lo,hi)));
    }

    /**
     * The field's "global" identifier.
     */
    public static final class Id {
        private final Class type;
        private final String name;

        /**
         * Construts a new field identifier.
         * @param type The object type.
         * @param name The attribute name.
         */
        public Id(final Class type, final String name) {
            this.type = type;
            this.name = name;
        }

        /**
         * Gets the attribute name.
         * @return The attribute name.
         */
        public String name() {
            return this.name;
        }

        /**
         * {@inheritDoc}
         */
        @Override
        public final boolean equals(final Object o) {
            return o instanceof Id && ((Id)o).type == type && ((Id)o).name.equals(name);
        }

        /**
         * {@inheritDoc}
         */
        @Override
        public final int hashCode() {
            return type.hashCode() ^ name.hashCode();
        }

        /**
         * {@inheritDoc}
         */
        @Override
        public final String toString() {
            return new StringBuilder().append(type.getName()).append("[").append(name).append("]").toString();
        }

        /**
         * Formats an exception message with the identifier.
         * @param message The exception message.
         * @param args Optional formatting arguments.
         * @return The formatted message.
         */
        public final String format(String message, final Object ... args) {
            if (message != null && args.length > 0) {
                try {
                    message = String.format(message, args);
                } catch (final RuntimeException no) {}
            }
            return new StringBuilder().append("Field ").append(this).append(" ").append(message).toString();
        }
    }

    /**
     * Get/set reflection operations.
     * @param  The object type.
     * @param  The value type.
     */
    static interface Reflect {
        public V get(T object);
        public void set(T object, V value);
    }

    /**
     * The field model properties.
     */
    static interface Properties {
        public Class targetType();
        public String attributeName();
        public KeyType keyType();
        public List globalSecondaryIndexNames(KeyType keyType);
        public List localSecondaryIndexNames();
        public DynamoDBAutoGenerator autoGenerator();

        /**
         * Properties builder.
         */
        static final class Builder implements Properties {
            private Map> gsis = Collections.emptyMap();
            private List lsis = Collections.emptyList();
            private DynamoDBAutoGenerator autoGenerator;
            private String attributeName;
            private Class targetType;
            private KeyType keyType;

            /**
             * Populates the builder properties with the specified defaults.
             * @param defaults The default properties.
             * @return This builder instance for chaining.
             */
            public Builder with(final Properties defaults) {
                this.targetType = defaults.targetType();
                this.attributeName = defaults.attributeName();
                this.keyType = defaults.keyType();
                this.autoGenerator = defaults.autoGenerator();
                this.lsis = defaults.localSecondaryIndexNames();
                for (final KeyType keyType : KeyType.values()) {
                    final List names = defaults.globalSecondaryIndexNames(keyType);
                    if (!names.isEmpty()) {
                        if (this.gsis.isEmpty()) {
                            this.gsis = new LinkedHashMap>();
                        }
                        this.gsis.put(keyType, names);
                    }
                }
                return this;
            }

            /**
             * Sets the target type.
             * @param targetType The target type.
             * @return This builder instance for chaining.
             */
            public Builder withTargetType(final Class targetType) {
                this.targetType = targetType;
                return this;
            }

            /**
             * Sets the attribute name.
             * @param attributeName The attribute name.
             * @return This builder instance for chaining.
             */
            public Builder withAttributeName(final String attributeName) {
                this.attributeName = attributeName;
                return this;
            }

            /**
             * {@inheritDoc}
             */
            @Override
            public Class targetType() {
                return targetType;
            }

            /**
             * {@inheritDoc}
             */
            @Override
            public String attributeName() {
                return attributeName;
            }

            /**
             * {@inheritDoc}
             */
            @Override
            public KeyType keyType() {
                return keyType;
            }

            /**
             * {@inheritDoc}
             */
            @Override
            public List globalSecondaryIndexNames(final KeyType keyType) {
                return gsis.containsKey(keyType) ? gsis.get(keyType) : Collections.emptyList();
            }

            /**
             * {@inheritDoc}
             */
            @Override
            public List localSecondaryIndexNames() {
                return lsis;
            }

            /**
             * {@inheritDoc}
             */
            @Override
            public DynamoDBAutoGenerator autoGenerator() {
                return autoGenerator;
            }
        }
    }

    /**
     * {@link DynamoDBMapperFieldModel} builder.
     */
    static class Builder {
        private final Id id;
        private final Properties.Builder properties;
        private DynamoDBMapperValueConverter converter;
        private Reflect reflect;

        /**
         * Construts a new builder.
         * @param type The object type.
         * @param name The attribute name.
         * @param defaults The default properties.
         */
        public Builder(final Id id, final Properties defaults) {
            this.properties = new Properties.Builder().with(defaults).withAttributeName(id.name());
            this.id = id;
        }

        /**
         * Sets the object's reflection property.
         * @param reflect The object's refleciton property.
         * @return This builder instance for chaining.
         */
        public Builder with(final Reflect reflect) {
            this.reflect = reflect;
            return this;
        }

        /**
         * Sets the attribute value converter.
         * @param converter The attribute value converter.
         * @return This builder instance for chaining.
         */
        public Builder with(final DynamoDBMapperValueConverter converter) {
            this.converter = converter;
            return this;
        }

        /**
         * Builds the instance.
         * @return The built instance.
         */
        public final DynamoDBMapperFieldModel build() {
            final DynamoDBMapperFieldModel field = new DynamoDBMapperFieldModel(this);
            if (field.keyType() != null && field.getGenerateStrategy() == DynamoDBAutoGenerateStrategy.ALWAYS) {
                throw new DynamoDBMappingException(id.format("must not have auto-generated key with ALWAYS strategy"));
            }
            return field;
        }
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy