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

com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMappingsRegistry 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 2015-2016 Amazon Technologies, Inc.
 *
 * 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.reflect.Method;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

import com.amazonaws.annotation.SdkInternalApi;
import com.amazonaws.services.dynamodbv2.datamodeling.StandardBeanProperties.Bean;
import com.amazonaws.services.dynamodbv2.model.KeyType;

/**
 * Reflection assistant for {@link DynamoDBMapper}
 */
@SdkInternalApi
final class DynamoDBMappingsRegistry {

    /**
     * The default instance.
     */
    private static final DynamoDBMappingsRegistry INSTANCE = new DynamoDBMappingsRegistry();

    /**
     * Gets the default instance.
     * @return The default instance.
     */
    static final DynamoDBMappingsRegistry instance() {
        return INSTANCE;
    }

    /**
     * The cache of class to mapping definition.
     */
    private final ConcurrentMap, Mappings> mappings = new ConcurrentHashMap, Mappings>();

    /**
     * Gets the mapping definition for a given class.
     * @param clazz The class.
     * @return The mapping definition.
     */
    final Mappings mappingsOf(final Class clazz) {
        if (!mappings.containsKey(clazz)) {
            mappings.putIfAbsent(clazz, new Mappings(clazz));
        }
        return mappings.get(clazz);
    }

    /**
     * Gets the mapping definition for a given method.
     * @param method The method.
     * @return The mapping definition.
     */
    final Mapping mappingOf(final Method method) {
        return mappingsOf(method.getDeclaringClass()).getMapping(method);
    }

    /**
     * Holds the properties for mapping an object.
     */
    static final class Mappings {
        private final Class objectType;
        private final Map byNames = new HashMap();
        private final Map byGetters = new HashMap();
        private final Map byKeyTypes = new HashMap();

        /**
         * Constructs a mapping definition for the specified class.
         * @param clazz The class.
         */
        private Mappings(final Class clazz) {
            objectType = (Class)clazz;
            for (final Map.Entry> bean : StandardBeanProperties.of(objectType).entrySet()) {
                final Mapping mapping = new Mapping(bean.getKey(), bean.getValue());
                if (byNames.containsKey(mapping.getAttributeName())) {
                    throw new DynamoDBMappingException(objectType +
                        " maps duplicate attributes named " + mapping.getAttributeName());
                }
                if (mapping.isPrimaryKey() && byKeyTypes.put(mapping.bean().annotations().keyType(), mapping) != null) {
                    throw new DynamoDBMappingException(objectType +
                        " maps multiple " + mapping.bean().annotations().keyType() +  " key attributes");
                }
                byNames.put(mapping.getAttributeName(), mapping);
                byGetters.put(mapping.getter(), mapping);
            }
        }

        /**
         * Gets the attribute mappings for this class.
         * @return The attribute mappings.
         */
        final Collection getMappings() {
            return byNames.values();
        }

        /**
         * Gets the attribute mapping for a specific method.
         * @param method The method.
         * @return The attribute mapping.
         */
        final Mapping getMapping(final Method method) {
            final Mapping mapping = byGetters.get(method);
            if (mapping == null) {
                throw new DynamoDBMappingException(objectType + " does not map any getter named " + method.getName());
            }
            return mapping;
        }

        /**
         * Gets the collection of key attributes.
         * @return The key attributes.
         */
        final Collection getPrimaryKeys() {
            return byKeyTypes.values();
        }

        /**
         * Gets the hash key attribute mapping for this class.
         * @return The range key attribute.
         */
        final Mapping getHashKey() {
            if (!byKeyTypes.containsKey(KeyType.HASH)) {
                throw new DynamoDBMappingException(objectType + " does not map a @DynamoDBHashKey attribute" +
                    "; ensure a public, zero-parameter get method/field is annotated");
            }
            return byKeyTypes.get(KeyType.HASH);
        }

        /**
         * Determines if the mapping has a range key attribute.
         * @return True if range key is present, false otherwise.
         */
        final boolean hasRangeKey() {
            return byKeyTypes.containsKey(KeyType.RANGE);
        }

        /**
         * Gets the range key attribute mapping for this class.
         * @return The attribute mapping.
         */
        final Mapping getRangeKey() {
            return byKeyTypes.get(KeyType.RANGE);
        }
    }

    /**
     * Holds the properties for mapping an object attribute.
     */
    static final class Mapping {
        private final Bean bean;
        private final String attributeName;

        /**
         * Constructs an object attribute mapping for the specified method.
         * @param bean The bean property.
         * @param attributeName The attribute name.
         */
        private Mapping(final String attributeName, final Bean bean) {
            this.attributeName = attributeName;
            this.bean = bean;
        }

        /**
         * Gets the bean property.
         * @return The bean property.
         */
        final Bean bean() {
            return this.bean;
        }

        /**
         * Gets the getter method for this attribute.
         * @return The getter method.
         */
        final Method getter() {
            return bean.getter();
        }

        /**
         * @return True if this Mapping represents a primary key (i.e. a hash key or a range key).
         *         False otherwise.
         */
        final boolean isPrimaryKey() {
            return bean.annotations().keyType() != null;
        }

        /**
         * Determines if this attribute maps to a hash key.
         * @return True if it maps, false otherwise.
         */
        final boolean isHashKey() {
            return bean.annotations().hashKey() != null;
        }

        /**
         * Determines if this attribute maps to an index hash key.
         * @return True if it maps, false otherwise.
         */
        final boolean isIndexHashKey() {
            return bean.annotations().indexHashKey() != null;
        }

        /**
         * Determines if this attribute maps to a version attribute.
         * @return True if it maps, false otherwise.
         */
        final boolean isVersion() {
            return bean.annotations().version() != null;
        }

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

}