/* * Copyright (C) 2012-2015 DataStax 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://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License 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.datastax.driver.mapping; import com.datastax.driver.mapping.annotations.*; import java.lang.annotation.Annotation; import java.util.*; /** * Various checks on mapping annotations. */ class AnnotationChecks { // The package containing the mapping annotations private static final Package MAPPING_PACKAGE = Table.class.getPackage(); /** * Checks that a class is decorated with the given annotation, and return the annotation instance. * Also validates that no other mapping annotation is present. */ static <T extends Annotation> T getTypeAnnotation(Class<T> annotation, Class<?> annotatedClass) { T instance = annotatedClass.getAnnotation(annotation); if (instance == null) throw new IllegalArgumentException(String.format("@%s annotation was not found on %s", annotation.getSimpleName(), annotatedClass)); // Check that no other mapping annotations are present validateAnnotations(annotatedClass, annotation); return instance; } private static void validateAnnotations(Class<?> clazz, Class<? extends Annotation> allowed) { Collection<Annotation> classAnnotations = new HashSet<Annotation>(); Collections.addAll(classAnnotations, clazz.getAnnotations()); Class<? extends Annotation> invalid = validateAnnotations(classAnnotations, Collections.singleton(allowed)); if (invalid != null) throw new IllegalArgumentException(String.format("Cannot have both @%s and @%s on %s", allowed.getSimpleName(), invalid.getSimpleName(), clazz)); } /** * Checks that a field is only annotated with the given mapping annotations, and that its "frozen" annotations are valid. */ static void validateAnnotations(String propertyName, Map<Class<? extends Annotation>, Annotation> annotations, Collection<? extends Class<? extends Annotation>> allowed) { Class<? extends Annotation> invalid = validateAnnotations(annotations.values(), allowed); if (invalid != null) { throw new IllegalArgumentException(String.format("Annotation @%s is not allowed on property '%s'", invalid.getSimpleName(), propertyName)); } checkValidPrimaryKey(propertyName, annotations); checkValidComputed(propertyName, annotations); } // Returns the offending annotation if there is one private static Class<? extends Annotation> validateAnnotations(Collection<Annotation> annotations, Collection<? extends Class<? extends Annotation>> allowed) { for (Annotation annotation : annotations) { Class<? extends Annotation> actual = annotation.annotationType(); if (actual.getPackage().equals(MAPPING_PACKAGE) && !allowed.contains(actual)) return actual; } return null; } private static void checkValidPrimaryKey(String propertyName, Map<Class<? extends Annotation>, Annotation> annotations) { if (annotations.containsKey(PartitionKey.class) && annotations.containsKey(ClusteringColumn.class)) throw new IllegalArgumentException(String.format("Property '%s' cannot be annotated with both @PartitionKey and @ClusteringColumn", propertyName)); } private static void checkValidComputed(String propertyName, Map<Class<? extends Annotation>, Annotation> annotations) { if (annotations.containsKey(Computed.class)) { Computed computed = (Computed) annotations.get(Computed.class); if (computed.value().isEmpty()) { throw new IllegalArgumentException(String.format("Property '%s': attribute 'value' of annotation @Computed is mandatory for computed properties", propertyName)); } if (annotations.containsKey(Column.class)) { throw new IllegalArgumentException(String.format("Property '%s' cannot be annotated with both @Column and @Computed", propertyName)); } } } static void validateOrder(List<AliasedMappedProperty<?>> properties, String annotation) { for (int i = 0; i < properties.size(); i++) { AliasedMappedProperty<?> property = properties.get(i); int pos = property.mappedProperty.getPosition(); if (pos != i) throw new IllegalArgumentException(String.format("Invalid ordering value %d for annotation %s of property '%s', was expecting %d", pos, annotation, property.mappedProperty.getPropertyName(), i)); } } }