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

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

Go to download

The AWS Java SDK for Amazon DynamoDB module holds the client classes that are used for communicating with Amazon DynamoDB Service

There is a newer version: 1.9.11
Show newest version
/*
 * Copyright 2016-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.annotation.SdkInternalApi;
import com.amazonaws.services.dynamodbv2.model.KeyType;

import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Map of DynamoDB annotations.
 */
@SdkInternalApi
final class StandardAnnotationMaps {

    /**
     * Gets all the DynamoDB annotations for a given class.
     * @param clazz The object type.
     * @return The map of annotation type to annotation instance.
     */
    static final  TableMap of(final Class clazz) {
        final DynamoDBMapperTableModel.Properties.Builder defaults;
        defaults = new DynamoDBMapperTableModel.Properties.Builder();
        defaults.withTargetType(clazz);

        final TableMap map = new TableMap(defaults);
        map.putAll(clazz);
        return map;
    }

    /**
     * Gets all the DynamoDB annotations; method annotations override field
     * level annotations which override class/type level annotations.
     * @param getter The getter method.
     * @return The map of annotation type to annotation instance.
     */
    static final  FieldMap of(final Method getter) {
        final DynamoDBMapperFieldModel.Properties.Builder defaults;
        defaults = new DynamoDBMapperFieldModel.Properties.Builder();
        defaults.withAttributeName(StandardBeanProperties.nameOf(getter, null));
        defaults.withTargetType((Class)getter.getReturnType());

        final FieldMap map = new FieldMap(defaults);
        map.putAll(getter.getReturnType());
        map.putAll(StandardBeanProperties.declaredFieldOf(getter));
        map.putAll(getter);
        return map;
    }

    /**
     * Map of annotation type to annotation instance.
     */
    static abstract class AnnotationMap {
        private final Map,Annotation> map = new HashMap,Annotation>();

        /**
         * Put all the DynamoDB annotations present on the annotated element.
         * @param annotated The annotated element.
         * @return This instance for chaining.
         */
        final AnnotationMap putAll(final AnnotatedElement annotated) {
            if (annotated != null && annotated.getAnnotations().length > 0) {
                final Map,Annotation> tmp = new HashMap,Annotation>();
                for (final Annotation a1 : annotated.getAnnotations()) {
                    if (a1.annotationType().isAnnotationPresent(DynamoDB.class)) {
                        if (tmp.containsKey(a1.annotationType())) {
                            throw new DynamoDBMappingException("conflicting annotations " + a1 + " and " +
                                tmp.get(a1.annotationType()) + "; allowed only one of @" + a1.annotationType().getSimpleName());
                        }
                        tmp.put(a1.annotationType(), a1);
                    }
                    for (final Annotation a2 : a1.annotationType().getAnnotations()) {
                        if (a2.annotationType().isAnnotationPresent(DynamoDB.class)) {
                            if (tmp.containsKey(a2.annotationType())) {
                                throw new DynamoDBMappingException("conflicting annotations " + a1 + " and " +
                                    tmp.get(a2.annotationType()) + "; allowed only one of @" + a2.annotationType().getSimpleName());
                            }
                            tmp.put(a2.annotationType(), a1);
                        }
                    }
                }
                this.map.putAll(tmp);
            }
            return this;
        }

        /**
         * Indicates if any of the specified types are mapped.
         * @param annotationTypes The annotation types.
         * @return True if any are mapped, false otherwise.
         */
        final boolean has(final Class ... annotationTypes) {
            for (final Class annotationType : annotationTypes) {
                if (get(annotationType, true) != null) {
                    return true;
                }
            }
            return false;
        }

        /**
         * Gets the annotation of the specified type; if the annotation is
         * mapped to another type and the actual flag is specified, then it's
         * meta annotation is returned.
         * @param annotationType The annotation type.
         * @param mappedBy To return the annotation mapped by the type.
         * @return The annotation or null if not applicable.
         */
        final  A get(final Class annotationType, final boolean mappedBy) {
            final Annotation annotation = this.map.get(annotationType);
            if (mappedBy == false && annotation != null && annotation.annotationType() != annotationType) {
                return (A)annotation.annotationType().getAnnotation(annotationType);
            }
            return (A)annotation;
        }

        /**
         * Gets the actual annotation of the specified type; if the annotation
         * is mapped to another type, then it's meta annotatoin is returned.
         * @param annotationType The annotation type.
         * @return The annotation or null if not applicable.
         */
        final  A get(final Class annotationType) {
            return get(annotationType, false);
        }
    }

    /**
     * {@link DynamoDBMapperTableModel} annotations.
     */
    static final class TableMap extends AnnotationMap implements DynamoDBMapperTableModel.Properties {
        private final DynamoDBMapperTableModel.Properties defaults;

        /**
         * Constructs a new annotation map.
         * @param defaults The default properties.
         */
        private TableMap(final DynamoDBMapperTableModel.Properties defaults) {
            this.defaults = defaults;
        }

        /**
         * Gets the annotation {@code DynamoDBDocument} if present.
         * @return The annotation if present, null otherwise.
         */
        final DynamoDBDocument document() {
            return get(DynamoDBDocument.class);
        }

        /**
         * Gets the annotation {@code DynamoDBTable} if present.
         * @return The annotation if present, null otherwise.
         */
        final DynamoDBTable table() {
            return get(DynamoDBTable.class);
        }

        /**
         * Indicates if the map has typed annotations.
         * @return True if any typed annotations, false otherwise.
         */
        final boolean typed() {
            return table() != null || document() != null;
        }

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

        /**
         * {@inheritDoc}
         */
        @Override
        public final String tableName() {
            return table() != null ? table().tableName() : defaults.tableName();
        }
    }

    /**
     * {@link DynamoDBMapperFieldModel} annotations.
     */
    static final class FieldMap extends AnnotationMap implements DynamoDBMapperFieldModel.Properties {
        private final DynamoDBMapperFieldModel.Properties defaults;

        /**
         * Constructs a new annotation map.
         * @param defaults The default properties.
         */
        private FieldMap(final DynamoDBMapperFieldModel.Properties defaults) {
            this.defaults = defaults;
        }

        /**
         * Gets the annotation {@code DynamoDBAutoGenerated} if present.
         * @return The annotation if present, null otherwise.
         */
        final Annotation autoGenerated() {
            return get(DynamoDBAutoGenerated.class, true);
        }

        /**
         * Gets the annotation {@code DynamoDBAutoGenerated} if present.
         * @return The annotation if present, null otherwise.
         */
        final Annotation typeConverted() {
            return get(DynamoDBTypeConverted.class, true);
        }

        /**
         * Gets the annotation {@code DynamoDBAttribute} if present.
         * @return The annotation if present, null otherwise.
         */
        final DynamoDBAttribute attribute() {
            return get(DynamoDBAttribute.class);
        }

        /**
         * Gets the annotation {@code DynamoDBFlattened} if present.
         * @return The annotation if present, null otherwise.
         */
        final DynamoDBFlattened flattened() {
            return get(DynamoDBFlattened.class);
        }

        /**
         * Gets the annotation {@code DynamoDBHashKey} if present.
         * @return The annotation if present, null otherwise.
         */
        final DynamoDBHashKey hashKey() {
            return get(DynamoDBHashKey.class);
        }

        /**
         * Gets the annotation {@code DynamoDBIgnore} if present.
         * @return The annotation if present, null otherwise.
         */
        final DynamoDBIgnore ignore() {
            return get(DynamoDBIgnore.class);
        }

        /**
         * Gets the annotation {@code DynamoDBIndexHashKey} if present.
         * @return The annotation if present, null otherwise.
         */
        final DynamoDBIndexHashKey indexHashKey() {
            return get(DynamoDBIndexHashKey.class);
        }

        /**
         * Gets the annotation {@code DynamoDBIndexRangeKey} if present.
         * @return The annotation if present, null otherwise.
         */
        final DynamoDBIndexRangeKey indexRangeKey() {
            return get(DynamoDBIndexRangeKey.class);
        }

        /**
         * Gets the annotation {@code DynamoDBMarshalling} if present.
         * @return The annotation if present, null otherwise.
         */
        final DynamoDBMarshalling marshalling() {
            return get(DynamoDBMarshalling.class);
        }

        /**
         * Gets the annotation {@code DynamoDBNativeBoolean} if present.
         * @return The annotation if present, null otherwise.
         */
        final DynamoDBNativeBoolean nativeBoolean() {
            return get(DynamoDBNativeBoolean.class);
        }

        /**
         * Gets the annotation {@code DynamoDBRangeKey} if present.
         * @return The annotation if present, null otherwise.
         */
        final DynamoDBRangeKey rangeKey() {
            return get(DynamoDBRangeKey.class);
        }

        /**
         * Gets the annotation {@code DynamoDBVersionAttribute} if present.
         * @return The annotation if present, null otherwise.
         */
        final DynamoDBVersionAttribute version() {
            return get(DynamoDBVersionAttribute.class);
        }

        /**
         * Indicates if an ignored attribute.
         * @return True if ignored, false otherwise.
         */
        final boolean ignored() {
            return ignore() != null;
        }

        /**
         * Gets the flattened attribute names map.
         * @return The attribute names map.
         */
        final Map attributes() {
            if (flattened() != null) {
                if (flattened().attributes().length == 0) {
                    throw new DynamoDBMappingException("must specify one or more attributes");
                }
                final Map attributes = new HashMap();
                for (final DynamoDBAttribute a : flattened().attributes()) {
                    if (a.mappedBy().isEmpty() || a.attributeName().isEmpty()) {
                        throw new DynamoDBMappingException("must specify mappedBy and attributeName");
                    } else if (attributes.put(a.mappedBy(), a.attributeName()) != null) {
                        throw new DynamoDBMappingException("must not duplicate mappedBy=" + a.mappedBy());
                    }
                }
                return attributes;
            }
            return Collections.emptyMap();
        }

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

        /**
         * {@inheritDoc}
         */
        @Override
        public final String attributeName() {
            if (hashKey() != null && !hashKey().attributeName().isEmpty()) {
                return hashKey().attributeName();
            } else if (indexHashKey() != null && !indexHashKey().attributeName().isEmpty()) {
                return indexHashKey().attributeName();
            } else if (rangeKey() != null && !rangeKey().attributeName().isEmpty()) {
                return rangeKey().attributeName();
            } else if (indexRangeKey() != null && !indexRangeKey().attributeName().isEmpty()) {
                return indexRangeKey().attributeName();
            } else if (attribute() != null && !attribute().attributeName().isEmpty()) {
                return attribute().attributeName();
            } else if (version() != null && !version().attributeName().isEmpty()) {
                return version().attributeName();
            } else {
                return defaults.attributeName();
            }
        }

        /**
         * {@inheritDoc}
         */
        @Override
        public final KeyType keyType() {
            return hashKey() != null ? HASH : rangeKey() != null ? RANGE : defaults.keyType();
        }

        /**
         * {@inheritDoc}
         */
        @Override
        public final List globalSecondaryIndexNames(final KeyType keyType) {
            if (keyType == HASH && indexHashKey() != null) {
                if (!indexHashKey().globalSecondaryIndexName().isEmpty()) {
                    if (indexHashKey().globalSecondaryIndexNames().length > 0) {
                        throw new DynamoDBMappingException("must not specify both HASH GSI name/names");
                    }
                    return Collections.singletonList(indexHashKey().globalSecondaryIndexName());
                } else if (indexHashKey().globalSecondaryIndexNames().length > 0) {
                    return Collections.unmodifiableList(Arrays.asList(indexHashKey().globalSecondaryIndexNames()));
                } else {
                    throw new DynamoDBMappingException("must specify one of HASH GSI name/names");
                }
            } else if (keyType == RANGE && indexRangeKey() != null) {
                if (!indexRangeKey().globalSecondaryIndexName().isEmpty()) {
                    if (indexRangeKey().globalSecondaryIndexNames().length > 0) {
                        throw new DynamoDBMappingException("must not specify both RANGE GSI name/names");
                    }
                    return Collections.singletonList(indexRangeKey().globalSecondaryIndexName());
                } else if (indexRangeKey().globalSecondaryIndexNames().length > 0) {
                    return Collections.unmodifiableList(Arrays.asList(indexRangeKey().globalSecondaryIndexNames()));
                } else if (localSecondaryIndexNames().isEmpty()) {
                    throw new DynamoDBMappingException("must specify RANGE GSI and/or LSI name/names");
                }
            }
            return defaults.globalSecondaryIndexNames(keyType);
        }

        /**
         * {@inheritDoc}
         */
        @Override
        public final List localSecondaryIndexNames() {
            if (indexRangeKey() != null) {
                if (!indexRangeKey().localSecondaryIndexName().isEmpty()) {
                    if (indexRangeKey().localSecondaryIndexNames().length > 0) {
                        throw new DynamoDBMappingException("must not specify both LSI name/names");
                    }
                    return Collections.singletonList(indexRangeKey().localSecondaryIndexName());
                } else if (indexRangeKey().localSecondaryIndexNames().length > 0) {
                    return Collections.unmodifiableList(Arrays.asList(indexRangeKey().localSecondaryIndexNames()));
                }
            }
            return defaults.localSecondaryIndexNames();
        }

        /**
         * {@inheritDoc}
         */
        @Override
        public final DynamoDBAutoGenerator autoGenerator() {
            if (autoGenerated() != null) {
                return DynamoDBAutoGenerated.Generators.of(targetType(), autoGenerated());
            }
            return defaults.autoGenerator();
        }

        /**
         * Gets the custom type-converter.
         * @return The custom type-converter.
         */
        final  DynamoDBTypeConverter typeConverter() {
            if (typeConverted() != null) {
                return DynamoDBTypeConverted.Converters.of(targetType(), typeConverted());
            }
            return null;
        }
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy