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

com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBAnnotationRegistry 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 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 java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.amazonaws.annotation.SdkInternalApi;

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

    /**
     * The logging utility.
     */
    private static final Log log = LogFactory.getLog(DynamoDBAnnotationRegistry.class);

    /**
     * Gets all the DynamoDB annotations for a given class.
     * @param clazz The class.
     * @return The map of annotation type to annotation instance.
     */
    final AnnotationMap annotationsOf(final Class clazz) {
        final AnnotationMap annotations = new AnnotationMap();
        annotations.putAll(clazz.getAnnotations());
        annotations.removeInvalidAnnotations();
        return annotations;
    }

    /**
     * Gets all the DynamoDB annotations; method annotations override the field level annotations.
     * @param method The method.
     * @param field The field.
     * @return The map of annotation type to annotation instance.
     */
    final AnnotationMap annotationsOf(final Method method, final Field field) {
        final AnnotationMap annotations = new AnnotationMap();
        if (field != null) {
            annotations.putAll(field.getAnnotations());
        }
        annotations.putAll(method.getAnnotations());
        annotations.removeInvalidAnnotations();
        return annotations;
    }

    /**
     * Map of annotation type to annotation instance.
     */
    static final class AnnotationMap {
        /**
         * Map of annotation type to annotation instance.
         */
        private final Map,Annotation> annotations;

        /**
         * Constructs an instance of {@code AnnotationMap}.
         */
        private AnnotationMap() {
            this.annotations = new HashMap,Annotation>();
        }

        /**
         * Gets the annotations.
         * @return The annotations.
         */
        private final Map,Annotation> getAnnotations() {
            return this.annotations;
        }

        /**
         * Put all the DynamoDB annotations.
         * @param annotations The array of annotations.
         */
        private final void putAll(final Annotation[] annotations) {
            if (annotations != null && annotations.length > 0) {
                for (final Annotation annotation : annotations) {
                    if (annotation != null && annotation.annotationType().isAnnotationPresent(DynamoDB.class)) {
                        getAnnotations().put(annotation.annotationType(), annotation);
                    }
                }
            }
        }

        /**
         * Removes any conflicting annotations.
         * Note, we may consider throwing exceptions here instead in the future.
         */
        private final void removeInvalidAnnotations() {
            // Note, the fact this code exists indicates more thought should be placed
            // into how we are exposing features as annotations. It may not be clear
            // which annotations are compatible to our integrators without extensive
            // documentation. The code should stand alone, or try it's best.
            if (isAutoGeneratedKey()) {
                if (!isHashKey() && !isRangeKey() && !isIndexHashKey() && !isIndexRangeKey()) {
                    log.warn(annotationOf(DynamoDBAutoGeneratedKey.class) + " is only compatible with keys");
                    getAnnotations().remove(DynamoDBAutoGeneratedKey.class);
                } else {
                    if (isVersion()) {
                        log.warn(annotationOf(DynamoDBVersionAttribute.class) + " is not compatible with " + annotationOf(DynamoDBAutoGeneratedKey.class));
                        getAnnotations().remove(DynamoDBVersionAttribute.class);
                    }
                    if (isAutoGeneratedTimestamp()) {
                        throw new DynamoDBMappingException(annotationOf(DynamoDBAutoGeneratedTimestamp.class) +
                            " is not compatible with " + annotationOf(DynamoDBAutoGeneratedKey.class));
                    }
                }
            } else if (isVersion()) {
                if (isAutoGeneratedTimestamp()) {
                    throw new DynamoDBMappingException(annotationOf(DynamoDBAutoGeneratedTimestamp.class) +
                        " is not compatible with " + annotationOf(DynamoDBVersionAttribute.class));
                }
            } else if (isAutoGeneratedTimestamp()) {
                if (isHashKey() || isRangeKey()) {
                    throw new DynamoDBMappingException(annotationOf(DynamoDBAutoGeneratedTimestamp.class) +
                        " is not compatible with primary keys");
                }
            }
        }

        /**
         * Gets the annotation of the specified type.
         * @param clazz The annotation type.
         * @return The annotation or null if not applicable.
         */
        private final  T annotationOf(final Class clazz) {
            return (T)getAnnotations().get(clazz);
        }

        /**
         * Determines if the {@code DynamoDBAttribute} is present.
         * @return True if present, false otherwise.
         */
        final boolean isAttribute() {
            return getAnnotations().containsKey(DynamoDBAttribute.class);
        }

        /**
         * Determines if the {@code DynamoDBAutoGeneratedKey} is present.
         * @return True if present, false otherwise.
         */
        final boolean isAutoGeneratedKey() {
            return getAnnotations().containsKey(DynamoDBAutoGeneratedKey.class);
        }

        /**
         * Determines if the {@code DynamoDBAutoGeneratedTimestamp} is present.
         * @return True if present, false otherwise.
         */
        final boolean isAutoGeneratedTimestamp() {
            return getAnnotations().containsKey(DynamoDBAutoGeneratedTimestamp.class);
        }

        /**
         * Determines if the {@code DynamoDBDocument} is present.
         * @return True if present, false otherwise.
         */
        final boolean isDocument() {
            return getAnnotations().containsKey(DynamoDBDocument.class);
        }

        /**
         * Determines if the {@code DynamoDBHashKey} is present.
         * @return True if present, false otherwise.
         */
        final boolean isHashKey() {
            return getAnnotations().containsKey(DynamoDBHashKey.class);
        }

        /**
         * Determines if the {@code DynamoDBIgnore} is present.
         * @return True if present, false otherwise.
         */
        final boolean isIgnore() {
            return getAnnotations().containsKey(DynamoDBIgnore.class);
        }

        /**
         * Determines if the {@code DynamoDBIndexHashKey} is present.
         * @return True if present, false otherwise.
         */
        final boolean isIndexHashKey() {
            return getAnnotations().containsKey(DynamoDBIndexHashKey.class);
        }

        /**
         * Determines if the {@code DynamoDBIndexRangeKey} is present.
         * @return True if present, false otherwise.
         */
        final boolean isIndexRangeKey() {
            return getAnnotations().containsKey(DynamoDBIndexRangeKey.class);
        }

        /**
         * Determines if the {@code DynamoDBMarshalling} is present.
         * @return True if present, false otherwise.
         */
        final boolean isMarshalling() {
            return getAnnotations().containsKey(DynamoDBMarshalling.class);
        }

        /**
         * Determines if the {@code DynamoDBNativeBoolean} is present.
         * @return True if present, false otherwise.
         */
        final boolean isNativeBoolean() {
            return getAnnotations().containsKey(DynamoDBNativeBoolean.class);
        }

        /**
         * Determines if the {@code DynamoDBRangeKey} is present.
         * @return True if present, false otherwise.
         */
        final boolean isRangeKey() {
            return getAnnotations().containsKey(DynamoDBRangeKey.class);
        }

        /**
         * Determines if the {@code DynamoDBTable} is present.
         * @return True if present, false otherwise.
         */
        final boolean isTable() {
            return getAnnotations().containsKey(DynamoDBTable.class);
        }

        /**
         * Determines if the {@code DynamoDBVersionAttribute} is present.
         * @return True if present, false otherwise.
         */
        final boolean isVersion() {
            return getAnnotations().containsKey(DynamoDBVersionAttribute.class);
        }

        /**
         * Gets the attribute name defaulting if required.
         * @return The attribute name.
         */
        final String getAttributeName() {
            if (isHashKey()) {
                final DynamoDBHashKey annotation = annotationOf(DynamoDBHashKey.class);
                if (!annotation.attributeName().isEmpty()) {
                    return annotation.attributeName();
                }
            }
            if (isIndexHashKey()) {
                final DynamoDBIndexHashKey annotation = annotationOf(DynamoDBIndexHashKey.class);
                if (!annotation.attributeName().isEmpty()) {
                    return annotation.attributeName();
                }
            }
            if (isRangeKey()) {
                final DynamoDBRangeKey annotation = annotationOf(DynamoDBRangeKey.class);
                if (!annotation.attributeName().isEmpty()) {
                    return annotation.attributeName();
                }
            }
            if (isIndexRangeKey()) {
                final DynamoDBIndexRangeKey annotation = annotationOf(DynamoDBIndexRangeKey.class);
                if (!annotation.attributeName().isEmpty()) {
                    return annotation.attributeName();
                }
            }
            if (isAttribute()) {
                final DynamoDBAttribute annotation = annotationOf(DynamoDBAttribute.class);
                if (!annotation.attributeName().isEmpty()) {
                    return annotation.attributeName();
                }
            }
            if (isVersion()) {
                final DynamoDBVersionAttribute annotation = annotationOf(DynamoDBVersionAttribute.class);
                if (!annotation.attributeName().isEmpty()) {
                    return annotation.attributeName();
                }
            }
            return null;
        }

        /**
         * Gets the global secondary index names if applicable.
         * @return The names.
         */
        final Collection getGlobalSecondaryIndexNamesOfIndexHashKey() {
            final DynamoDBIndexHashKey annotation = annotationOf(DynamoDBIndexHashKey.class);
            if (annotation == null) {
                return Collections.emptySet();
            }
            return resolveIndexNames(annotation, annotation.globalSecondaryIndexName(), annotation.globalSecondaryIndexNames());
        }

        /**
         * Gets the global secondary index names if applicable.
         * @return The names.
         */
        final Collection getGlobalSecondaryIndexNamesOfIndexRangeKey() {
            final DynamoDBIndexRangeKey annotation = annotationOf(DynamoDBIndexRangeKey.class);
            if (annotation == null) {
                return Collections.emptySet();
            }
            return resolveIndexNames(annotation, annotation.globalSecondaryIndexName(), annotation.globalSecondaryIndexNames());
        }

        /**
         * Gets the local secondary index names if applicable.
         * @return The names.
         */
        final Collection getLocalSecondaryIndexNamesOfIndexRangeKey() {
            final DynamoDBIndexRangeKey annotation = annotationOf(DynamoDBIndexRangeKey.class);
            if (annotation == null) {
                return Collections.emptySet();
            }
            return resolveIndexNames(annotation, annotation.localSecondaryIndexName(), annotation.localSecondaryIndexNames());
        }

        /**
         * Gets the auto-generate strategy.
         * @return The auto-generate strategy, null if not specified.
         */
        final DynamoDBAutoGenerateStrategy getAutoGenerateStrategy() {
            final DynamoDBAutoGeneratedTimestamp annotation = annotationOf(DynamoDBAutoGeneratedTimestamp.class);
            if (annotation == null) {
                return null;
            }
            return annotation.strategy();
        }

        /**
         * Gets the marshaller class.
         * @return The marshaller class, null if not specified.
         */
        final Class> getMarshallerClass() {
            final DynamoDBMarshalling annotation = annotationOf(DynamoDBMarshalling.class);
            if (annotation == null) {
                return null;
            }
            return annotation.marshallerClass();
        }

        /**
         * Gets the table name.
         * @return The table name, null if not specified.
         */
        final String getTableName() {
            final DynamoDBTable annotation = annotationOf(DynamoDBTable.class);
            if (annotation == null) {
                return null;
            }
            return annotation.tableName();
        }

        /**
         * Resolves between which name/names to use.
         * @param annotation The annotation.
         * @param name The singular name.
         * @param names The multiple names.
         * @return The names, null if they could not be resolved.
         */
        private static final Collection resolveIndexNames(final Annotation annotation, final String name, final String[] names) {
            if (name == null || name.isEmpty()) {
                if (names == null || names.length == 0) {
                    return Collections.emptySet();
                } else {
                    return Arrays.asList(names);
                }
            } else if (names == null || names.length == 0) {
                return Collections.singleton(name);
            } else {
                throw new DynamoDBMappingException(annotation + " contain both index name and names");
            }
        }
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy