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);
}
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;
}
Aggregations