Search in sources :

Example 1 with TYPE

use of org.gradle.internal.reflect.AnnotationCategory.TYPE in project gradle by gradle.

the class DefaultTypeMetadataStore method createTypeMetadata.

private <T> TypeMetadata createTypeMetadata(Class<T> type) {
    Class<?> publicType = GeneratedSubclasses.unpack(type);
    ReplayingTypeValidationContext validationContext = new ReplayingTypeValidationContext();
    TypeAnnotationMetadata annotationMetadata = typeAnnotationMetadataStore.getTypeAnnotationMetadata(publicType);
    annotationMetadata.visitValidationFailures(validationContext);
    for (TypeAnnotationHandler annotationHandler : typeAnnotationHandlers) {
        if (annotationMetadata.isAnnotationPresent(annotationHandler.getAnnotationType())) {
            annotationHandler.validateTypeMetadata(publicType, validationContext);
        }
    }
    ImmutableSet.Builder<PropertyMetadata> effectiveProperties = ImmutableSet.builderWithExpectedSize(annotationMetadata.getPropertiesAnnotationMetadata().size());
    for (PropertyAnnotationMetadata propertyAnnotationMetadata : annotationMetadata.getPropertiesAnnotationMetadata()) {
        Map<AnnotationCategory, Annotation> propertyAnnotations = propertyAnnotationMetadata.getAnnotations();
        Annotation typeAnnotation = propertyAnnotations.get(TYPE);
        Annotation normalizationAnnotation = propertyAnnotations.get(NORMALIZATION);
        Class<? extends Annotation> propertyType = determinePropertyType(typeAnnotation, normalizationAnnotation);
        if (propertyType == null) {
            validationContext.visitPropertyProblem(problem -> problem.withId(ValidationProblemId.MISSING_ANNOTATION).forProperty(propertyAnnotationMetadata.getPropertyName()).reportAs(ERROR).withDescription(() -> "is missing " + displayName).happensBecause("A property without annotation isn't considered during up-to-date checking").addPossibleSolution(() -> "Add " + displayName).addPossibleSolution("Mark it as @Internal").documentedAt("validation_problems", "missing_annotation"));
            continue;
        }
        PropertyAnnotationHandler annotationHandler = propertyAnnotationHandlers.get(propertyType);
        if (annotationHandler == null) {
            validationContext.visitPropertyProblem(problem -> problem.withId(ValidationProblemId.ANNOTATION_INVALID_IN_CONTEXT).forProperty(propertyAnnotationMetadata.getPropertyName()).reportAs(ERROR).withDescription(() -> String.format("is annotated with invalid property type @%s", propertyType.getSimpleName())).happensBecause(() -> "The '@" + propertyType.getSimpleName() + "' annotation cannot be used in this context").addPossibleSolution("Remove the property").addPossibleSolution(() -> "Use a different annotation, e.g one of " + toListOfAnnotations(propertyAnnotationHandlers.keySet())).documentedAt("validation_problems", "annotation_invalid_in_context"));
            continue;
        }
        ImmutableSet<? extends AnnotationCategory> allowedModifiersForPropertyType = annotationHandler.getAllowedModifiers();
        for (Map.Entry<AnnotationCategory, Annotation> entry : propertyAnnotations.entrySet()) {
            AnnotationCategory annotationCategory = entry.getKey();
            if (annotationCategory == TYPE) {
                continue;
            }
            Class<? extends Annotation> annotationType = entry.getValue().annotationType();
            if (!allowedModifiersForPropertyType.contains(annotationCategory)) {
                validationContext.visitPropertyProblem(problem -> problem.withId(ValidationProblemId.INCOMPATIBLE_ANNOTATIONS).forProperty(propertyAnnotationMetadata.getPropertyName()).reportAs(ERROR).withDescription(() -> "is annotated with @" + annotationType.getSimpleName() + " but that is not allowed for '" + propertyType.getSimpleName() + "' properties").happensBecause(() -> "This modifier is used in conjunction with a property of type '" + propertyType.getSimpleName() + "' but this doesn't have semantics").withLongDescription(() -> "The list of allowed modifiers for '" + propertyType.getSimpleName() + "' is " + toListOfAnnotations(allowedPropertyModifiers)).addPossibleSolution(() -> "Remove the '@" + annotationType.getSimpleName() + "' annotation").documentedAt("validation_problems", "incompatible_annotations"));
            } else if (!allowedPropertyModifiers.contains(annotationType)) {
                validationContext.visitPropertyProblem(problem -> problem.withId(ValidationProblemId.ANNOTATION_INVALID_IN_CONTEXT).forProperty(propertyAnnotationMetadata.getPropertyName()).reportAs(ERROR).withDescription(() -> String.format("is annotated with invalid modifier @%s", annotationType.getSimpleName())).happensBecause(() -> "The '@" + annotationType.getSimpleName() + "' annotation cannot be used in this context").addPossibleSolution("Remove the annotation").addPossibleSolution(() -> "Use a different annotation, e.g one of " + toListOfAnnotations(allowedPropertyModifiers)).documentedAt("validation_problems", "annotation_invalid_in_context"));
            }
        }
        PropertyMetadata property = new DefaultPropertyMetadata(propertyType, propertyAnnotationMetadata);
        annotationHandler.validatePropertyMetadata(property, validationContext);
        if (annotationHandler.isPropertyRelevant()) {
            effectiveProperties.add(property);
        }
    }
    return new DefaultTypeMetadata(effectiveProperties.build(), validationContext, propertyAnnotationHandlers);
}
Also used : TypeAnnotationMetadata(org.gradle.internal.reflect.annotations.TypeAnnotationMetadata) AbstractOutputPropertyAnnotationHandler(org.gradle.api.internal.tasks.properties.annotations.AbstractOutputPropertyAnnotationHandler) TypeAnnotationHandler(org.gradle.api.internal.tasks.properties.annotations.TypeAnnotationHandler) InputFiles(org.gradle.api.tasks.InputFiles) Function(java.util.function.Function) NORMALIZATION(org.gradle.api.internal.tasks.properties.ModifierAnnotationCategory.NORMALIZATION) PropertyAnnotationHandler(org.gradle.api.internal.tasks.properties.annotations.PropertyAnnotationHandler) Map(java.util.Map) TYPE(org.gradle.internal.reflect.AnnotationCategory.TYPE) Collector(java.util.stream.Collector) Method(java.lang.reflect.Method) Nullable(javax.annotation.Nullable) GeneratedSubclasses(org.gradle.api.internal.GeneratedSubclasses) Classpath(org.gradle.api.tasks.Classpath) ImmutableSet(com.google.common.collect.ImmutableSet) CompileClasspath(org.gradle.api.tasks.CompileClasspath) ImmutableMap(com.google.common.collect.ImmutableMap) Collection(java.util.Collection) ReplayingTypeValidationContext(org.gradle.internal.reflect.validation.ReplayingTypeValidationContext) Set(java.util.Set) AnnotationCategory(org.gradle.internal.reflect.AnnotationCategory) TypeValidationContext(org.gradle.internal.reflect.validation.TypeValidationContext) CrossBuildInMemoryCache(org.gradle.cache.internal.CrossBuildInMemoryCache) Maps(com.google.common.collect.Maps) Collectors(java.util.stream.Collectors) TypeAnnotationMetadataStore(org.gradle.internal.reflect.annotations.TypeAnnotationMetadataStore) PropertyMetadata(org.gradle.internal.reflect.PropertyMetadata) PropertyAnnotationMetadata(org.gradle.internal.reflect.annotations.PropertyAnnotationMetadata) ERROR(org.gradle.internal.reflect.validation.Severity.ERROR) Annotation(java.lang.annotation.Annotation) CrossBuildInMemoryCacheFactory(org.gradle.cache.internal.CrossBuildInMemoryCacheFactory) ValidationProblemId(org.gradle.internal.reflect.problems.ValidationProblemId) AbstractOutputPropertyAnnotationHandler(org.gradle.api.internal.tasks.properties.annotations.AbstractOutputPropertyAnnotationHandler) PropertyAnnotationHandler(org.gradle.api.internal.tasks.properties.annotations.PropertyAnnotationHandler) TypeAnnotationHandler(org.gradle.api.internal.tasks.properties.annotations.TypeAnnotationHandler) PropertyAnnotationMetadata(org.gradle.internal.reflect.annotations.PropertyAnnotationMetadata) ReplayingTypeValidationContext(org.gradle.internal.reflect.validation.ReplayingTypeValidationContext) AnnotationCategory(org.gradle.internal.reflect.AnnotationCategory) Annotation(java.lang.annotation.Annotation) ImmutableSet(com.google.common.collect.ImmutableSet) PropertyMetadata(org.gradle.internal.reflect.PropertyMetadata) TypeAnnotationMetadata(org.gradle.internal.reflect.annotations.TypeAnnotationMetadata) Map(java.util.Map) ImmutableMap(com.google.common.collect.ImmutableMap)

Example 2 with TYPE

use of org.gradle.internal.reflect.AnnotationCategory.TYPE in project gradle by gradle.

the class DefaultTypeAnnotationMetadataStore method mergePropertiesAndFieldMetadata.

private ImmutableSortedSet<PropertyAnnotationMetadata> mergePropertiesAndFieldMetadata(Class<?> type, ImmutableList<PropertyAnnotationMetadataBuilder> propertyBuilders, ImmutableMap<String, ImmutableMap<Class<? extends Annotation>, Annotation>> fieldAnnotationsByPropertyName, TypeValidationContext validationContext) {
    ImmutableSortedSet.Builder<PropertyAnnotationMetadata> propertiesMetadataBuilder = ImmutableSortedSet.naturalOrder();
    ImmutableSet.Builder<String> fieldsSeenBuilder = ImmutableSet.builderWithExpectedSize(fieldAnnotationsByPropertyName.size());
    for (PropertyAnnotationMetadataBuilder metadataBuilder : propertyBuilders) {
        String propertyName = metadataBuilder.getPropertyName();
        ImmutableMap<Class<? extends Annotation>, Annotation> fieldAnnotations = fieldAnnotationsByPropertyName.get(propertyName);
        if (fieldAnnotations != null) {
            fieldsSeenBuilder.add(propertyName);
            for (Annotation annotation : fieldAnnotations.values()) {
                metadataBuilder.declareAnnotation(annotation);
            }
        }
        propertiesMetadataBuilder.add(metadataBuilder.build());
    }
    ImmutableSortedSet<PropertyAnnotationMetadata> propertiesMetadata = propertiesMetadataBuilder.build();
    // Report fields with annotations that have not been seen while processing properties
    ImmutableSet<String> fieldsSeen = fieldsSeenBuilder.build();
    if (fieldsSeen.size() != fieldAnnotationsByPropertyName.size()) {
        fieldAnnotationsByPropertyName.entrySet().stream().filter(entry -> {
            String fieldName = entry.getKey();
            ImmutableMap<Class<? extends Annotation>, Annotation> fieldAnnotations = entry.getValue();
            return !fieldAnnotations.isEmpty() && !fieldsSeen.contains(fieldName) && // @Inject is allowed on fields only
            !fieldAnnotations.containsKey(Inject.class);
        }).forEach(entry -> {
            String fieldName = entry.getKey();
            ImmutableMap<Class<? extends Annotation>, Annotation> fieldAnnotations = entry.getValue();
            validationContext.visitTypeProblem(problem -> problem.withId(ValidationProblemId.IGNORED_ANNOTATIONS_ON_FIELD).forType(type).reportAs(ERROR).withDescription(() -> String.format("field '%s' without corresponding getter has been annotated with %s", fieldName, simpleAnnotationNames(fieldAnnotations.keySet().stream()))).happensBecause("Annotations on fields are only used if there's a corresponding getter for the field").withLongDescription("If a field is annotated but there's no corresponding getter, then the annotations are ignored").addPossibleSolution(() -> "Add a getter for field '" + fieldName + "'").addPossibleSolution(() -> "Remove the annotations on '" + fieldName + "'").documentedAt("validation_problems", "ignored_annotations_on_field"));
        });
    }
    return propertiesMetadata;
}
Also used : Iterables(com.google.common.collect.Iterables) Arrays(java.util.Arrays) TypeAnnotationMetadata(org.gradle.internal.reflect.annotations.TypeAnnotationMetadata) ListMultimap(com.google.common.collect.ListMultimap) MultimapBuilder(com.google.common.collect.MultimapBuilder) HashMap(java.util.HashMap) PropertyAccessorType(org.gradle.internal.reflect.PropertyAccessorType) Inject(javax.inject.Inject) LinkedHashMap(java.util.LinkedHashMap) ImmutableList(com.google.common.collect.ImmutableList) Map(java.util.Map) TYPE(org.gradle.internal.reflect.AnnotationCategory.TYPE) Comparator.comparing(java.util.Comparator.comparing) Method(java.lang.reflect.Method) ImmutableSortedSet(com.google.common.collect.ImmutableSortedSet) ImmutableSet(com.google.common.collect.ImmutableSet) Equivalence(com.google.common.base.Equivalence) Action(org.gradle.api.Action) Iterator(java.util.Iterator) ImmutableMap(com.google.common.collect.ImmutableMap) Predicate(java.util.function.Predicate) Collection(java.util.Collection) ReplayingTypeValidationContext(org.gradle.internal.reflect.validation.ReplayingTypeValidationContext) Set(java.util.Set) AnnotationCategory(org.gradle.internal.reflect.AnnotationCategory) TypeValidationContext(org.gradle.internal.reflect.validation.TypeValidationContext) CrossBuildInMemoryCache(org.gradle.cache.internal.CrossBuildInMemoryCache) Field(java.lang.reflect.Field) Collectors(java.util.stream.Collectors) SetMultimap(com.google.common.collect.SetMultimap) Collectors.joining(java.util.stream.Collectors.joining) TypeAnnotationMetadataStore(org.gradle.internal.reflect.annotations.TypeAnnotationMetadataStore) List(java.util.List) SIGNATURE_EQUIVALENCE(org.gradle.internal.reflect.Methods.SIGNATURE_EQUIVALENCE) Stream(java.util.stream.Stream) Ordering(com.google.common.collect.Ordering) PropertyAnnotationMetadata(org.gradle.internal.reflect.annotations.PropertyAnnotationMetadata) ERROR(org.gradle.internal.reflect.validation.Severity.ERROR) PropertyProblemBuilder(org.gradle.internal.reflect.validation.PropertyProblemBuilder) Modifier(java.lang.reflect.Modifier) Annotation(java.lang.annotation.Annotation) CrossBuildInMemoryCacheFactory(org.gradle.cache.internal.CrossBuildInMemoryCacheFactory) ValidationProblemId(org.gradle.internal.reflect.problems.ValidationProblemId) AnnotatedElement(java.lang.reflect.AnnotatedElement) Inject(javax.inject.Inject) PropertyAnnotationMetadata(org.gradle.internal.reflect.annotations.PropertyAnnotationMetadata) Annotation(java.lang.annotation.Annotation) ImmutableMap(com.google.common.collect.ImmutableMap) ImmutableSet(com.google.common.collect.ImmutableSet) ImmutableSortedSet(com.google.common.collect.ImmutableSortedSet)

Aggregations

ImmutableMap (com.google.common.collect.ImmutableMap)2 ImmutableSet (com.google.common.collect.ImmutableSet)2 Annotation (java.lang.annotation.Annotation)2 Method (java.lang.reflect.Method)2 Collection (java.util.Collection)2 Map (java.util.Map)2 Set (java.util.Set)2 Collectors (java.util.stream.Collectors)2 CrossBuildInMemoryCache (org.gradle.cache.internal.CrossBuildInMemoryCache)2 CrossBuildInMemoryCacheFactory (org.gradle.cache.internal.CrossBuildInMemoryCacheFactory)2 AnnotationCategory (org.gradle.internal.reflect.AnnotationCategory)2 TYPE (org.gradle.internal.reflect.AnnotationCategory.TYPE)2 PropertyAnnotationMetadata (org.gradle.internal.reflect.annotations.PropertyAnnotationMetadata)2 TypeAnnotationMetadata (org.gradle.internal.reflect.annotations.TypeAnnotationMetadata)2 TypeAnnotationMetadataStore (org.gradle.internal.reflect.annotations.TypeAnnotationMetadataStore)2 ValidationProblemId (org.gradle.internal.reflect.problems.ValidationProblemId)2 ReplayingTypeValidationContext (org.gradle.internal.reflect.validation.ReplayingTypeValidationContext)2 ERROR (org.gradle.internal.reflect.validation.Severity.ERROR)2 TypeValidationContext (org.gradle.internal.reflect.validation.TypeValidationContext)2 Equivalence (com.google.common.base.Equivalence)1