
com.amazonaws.services.dynamodbv2.datamodeling.StandardAnnotationMaps Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of aws-java-sdk-dynamodb Show documentation
Show all versions of aws-java-sdk-dynamodb Show documentation
The AWS Java SDK for Amazon DynamoDB module holds the client classes that are used for communicating with Amazon DynamoDB Service
/*
* 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 com.amazonaws.annotation.SdkInternalApi;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapperFieldModel.DynamoDBAttributeType;
import com.amazonaws.services.dynamodbv2.datamodeling.StandardAttributeTypes.AttributeType;
import com.amazonaws.services.dynamodbv2.model.KeyType;
import com.amazonaws.services.dynamodbv2.model.ScalarAttributeType;
import com.amazonaws.util.StringUtils;
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.EnumMap;
import java.util.LinkedHashMap;
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.Buildable defaults;
defaults = new DynamoDBMapperTableModel.Properties.Buildable();
defaults.withId(new DynamoDBMapperTableModel.Id(clazz));
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 Class clazz, final Method getter) {
String name = getter.getName().replaceFirst("^(get|is)","");
name = StringUtils.lowerCase(name.substring(0, 1)) + name.substring(1);
final DynamoDBMapperFieldModel.Properties.Buildable defaults;
defaults = new DynamoDBMapperFieldModel.Properties.Buildable();
defaults.withId(new DynamoDBMapperFieldModel.Id(clazz, name));
defaults.withTargetType((Class)getter.getReturnType());
defaults.withAttributeName(name);
Field declaredField = null;
try {
declaredField = getter.getDeclaringClass().getDeclaredField(name);
} catch (final SecurityException e) {
throw new DynamoDBMappingException(defaults.id().err("no access to field for " + getter), e);
} catch (final NoSuchFieldException no) {}
final FieldMap map = new FieldMap(defaults);
map.putAll(defaults.targetType());
map.putAll(declaredField);
map.putAll(getter);
return map;
}
/**
* Map of annotation type to annotation instance.
*/
static abstract class AnnotationMap {
private final Map,Annotation> map = new LinkedHashMap,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 LinkedHashMap,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;
}
/**
* 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 DynamoDBMapperTableModel.Id id() {
return defaults.id();
}
/**
* {@inheritDoc}
*/
@Override
public Class targetType() {
return defaults.targetType();
}
/**
* {@inheritDoc}
*/
@Override
public final String tableName() {
if (table() != null && !table().tableName().isEmpty()) {
return table().tableName();
}
return 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 DynamoDBDocument} if present.
* @return The annotation if present, null otherwise.
*/
final DynamoDBDocument document() {
return get(DynamoDBDocument.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 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 DynamoDBScalarAttribute} if present.
* @return The annotation if present, null otherwise.
*/
final DynamoDBScalarAttribute scalarAttribute() {
return get(DynamoDBScalarAttribute.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(id().err("must specify one or more attributes"));
}
final Map attributes = new LinkedHashMap();
for (final DynamoDBAttribute a : flattened().attributes()) {
if (a.mappedBy().isEmpty() || a.attributeName().isEmpty()) {
throw new DynamoDBMappingException(id().err("must specify mappedBy and attributeName"));
} else if (attributes.put(a.mappedBy(), a.attributeName()) != null) {
throw new DynamoDBMappingException(id().err("must not duplicate mappedBy=" + a.mappedBy()));
}
}
return attributes;
}
return Collections.emptyMap();
}
/**
* {@inheritDoc}
*/
@Override
public DynamoDBMapperFieldModel.Id id() {
return defaults.id();
}
/**
* {@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();
}
return defaults.attributeName();
}
/**
* {@inheritDoc}
*/
@Override
public final DynamoDBAttributeType attributeType() {
if (nativeBoolean() != null) {
return AttributeType.BOOL.attributeType();
} else if (document() != null) {
return AttributeType.M.attributeType();
} else if (scalarAttribute() != null) {
String name = scalarAttribute().type().name();
if (StandardTypeConverters.Vector.SET.is(targetType())) {
name += "S";
}
return AttributeType.valueOf(name).attributeType();
}
return defaults.attributeType();
}
/**
* {@inheritDoc}
*/
@Override
public final KeyType keyType() {
if (hashKey() != null) {
return KeyType.HASH;
} else if (rangeKey() != null) {
return KeyType.RANGE;
}
return defaults.keyType();
}
/**
* {@inheritDoc}
*/
@Override
public final boolean versioned() {
if (version() != null) {
return Boolean.TRUE;
}
return defaults.versioned();
}
/**
* {@inheritDoc}
*/
@Override
public final Map> globalSecondaryIndexNames() {
if (indexHashKey() != null || indexRangeKey() != null) {
final Map> gsis = new EnumMap>(KeyType.class);
if (indexHashKey() != null) {
if (!indexHashKey().globalSecondaryIndexName().isEmpty()) {
if (indexHashKey().globalSecondaryIndexNames().length > 0) {
throw new DynamoDBMappingException(id().err("must not specify both HASH GSI name/names"));
}
gsis.put(KeyType.HASH, Collections.singletonList(indexHashKey().globalSecondaryIndexName()));
} else if (indexHashKey().globalSecondaryIndexNames().length > 0) {
gsis.put(KeyType.HASH, Collections.unmodifiableList(Arrays.asList(indexHashKey().globalSecondaryIndexNames())));
} else {
throw new DynamoDBMappingException(id().err("must specify one of HASH GSI name/names"));
}
}
if (indexRangeKey() != null) {
if (!indexRangeKey().globalSecondaryIndexName().isEmpty()) {
if (indexRangeKey().globalSecondaryIndexNames().length > 0) {
throw new DynamoDBMappingException(id().err("must not specify both RANGE GSI name/names"));
}
gsis.put(KeyType.RANGE, Collections.singletonList(indexRangeKey().globalSecondaryIndexName()));
} else if (indexRangeKey().globalSecondaryIndexNames().length > 0) {
gsis.put(KeyType.RANGE, Collections.unmodifiableList(Arrays.asList(indexRangeKey().globalSecondaryIndexNames())));
} else if (localSecondaryIndexNames().isEmpty()) {
throw new DynamoDBMappingException(id().err("must specify RANGE GSI and/or LSI name/names"));
}
}
if (!gsis.isEmpty()) {
return Collections.unmodifiableMap(gsis);
}
}
return defaults.globalSecondaryIndexNames();
}
/**
* {@inheritDoc}
*/
@Override
public final List localSecondaryIndexNames() {
if (indexRangeKey() != null) {
if (!indexRangeKey().localSecondaryIndexName().isEmpty()) {
if (indexRangeKey().localSecondaryIndexNames().length > 0) {
throw new DynamoDBMappingException(id().err("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();
}
/**
* {@inheritDoc}
*/
@Override
public final DynamoDBTypeConverter typeConverter() {
if (typeConverted() != null) {
return DynamoDBTypeConverted.Converters.of(targetType(), typeConverted());
}
return defaults.typeConverter();
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy