@Pure @Override public @Nonnull Contract generateContract(@Nonnull Element element, @Nonnull AnnotationMirror annotationMirror, @NonCaptured @Modified @Nonnull TypeImporter typeImporter) { final @Nonnull String suffix = getSuffix(annotationMirror); final @Nonnull TypeMirror elementType = ProcessingUtility.getType(element); final @Nonnull Element enclosingElement = element.getEnclosingElement(); final boolean primitive = elementType.getKind().isPrimitive() || element.getAnnotation(Nonnull.class) == null && element.getAnnotation(Nullable.class) == null; final boolean local = hasMethodToCheckValidity((DeclaredType) ProcessingUtility.getSurroundingType(element).asType(), elementType, enclosingElement.getKind() == ElementKind.CONSTRUCTOR, suffix); return Contract.with((primitive ? "" : "# == null || ") + (local ? "" : ((ExecutableElement) enclosingElement).getParameters().get(0).getSimpleName() + ".") + "isValid" + suffix + "(#)", "The # has to be " + (primitive ? "" : "null or ") + "valid but was $.", element); }
@Override public void checkUsage(@Nonnull Element element, @Nonnull AnnotationMirror annotationMirror, @NonCaptured @Modified @Nonnull ErrorLogger errorLogger) { ProcessingLog.information("Called checkUsage of @Index validator for element $ in $", element.getSimpleName(), ProcessingUtility.getSurroundingType(element).getSimpleName()); super.checkUsage(element, annotationMirror, errorLogger); }
/** * Returns the type in which the given element is declared. * * @require element.getKind() != ElementKind.PACKAGE : "The element may not be a package."; */ @Pure public static @Nonnull TypeElement getSurroundingType(@Nonnull Element element) { Require.that(element.getKind() != ElementKind.PACKAGE).orThrow("The element $ may not be a package.", SourcePosition.of(element)); if (element.getKind().isClass() || element.getKind().isInterface()) { return (TypeElement) element; } return getSurroundingType(element.getEnclosingElement()); }
@Pure @Override public void checkUsage(@Nonnull Element element, @Nonnull AnnotationMirror annotationMirror, @NonCaptured @Modified @Nonnull ErrorLogger errorLogger) { final @Nonnull String suffix = getSuffix(annotationMirror); final @Nonnull TypeMirror elementType = ProcessingUtility.getType(element); final @Nonnull Element enclosingElement = element.getEnclosingElement(); final boolean inConstructor = enclosingElement.getKind() == ElementKind.CONSTRUCTOR; if (hasMethodToCheckValidity((DeclaredType) ProcessingUtility.getSurroundingType(element).asType(), elementType, inConstructor, suffix)) { return; } if (enclosingElement.getKind() == ElementKind.METHOD) { @Nonnull TypeMirror typeOfFirstParameter = ((ExecutableElement) enclosingElement).getParameters().get(0).asType(); if (typeOfFirstParameter.getKind() == TypeKind.TYPEVAR) { typeOfFirstParameter = ((TypeVariable) typeOfFirstParameter).getUpperBound(); } if (typeOfFirstParameter.getKind() == TypeKind.DECLARED && hasMethodToCheckValidity((DeclaredType) typeOfFirstParameter, elementType, false, suffix)) { return; } } final @Nonnull String annotationValue = suffix.isEmpty() ? "" : Brackets.inRound(Quotes.inDouble(suffix)); if (inConstructor) { errorLogger.log("The annotation '@Valid" + annotationValue + "' may only be used on constructor parameters of types that have a 'public static boolean isValid" + suffix + "(value)' method for the corresponding type.", SourcePosition.of(element, annotationMirror)); } else { errorLogger.log("The annotation '@Valid" + annotationValue + "' may only be used in types that have a corresponding non-private '(static) boolean isValid" + suffix + "(value)' method or on method parameters where the first method parameter has such a method.", SourcePosition.of(element, annotationMirror)); } }
/** * Overrides the methods of the superclass and generates contracts and/or method interceptors according to the method annotations. */ private void overrideMethods() { if (!typeInformation.getOverriddenMethods().isEmpty()) { addSection("Overridden Methods"); } for (final @Nonnull MethodInformation method : typeInformation.getOverriddenMethods()) { if (ProcessingUtility.getSurroundingType(method.getElement()).getQualifiedName().toString().startsWith("net.digitalid")) { final @Nonnull String callToSuperMethod = MethodUtility.createSuperCall(method); generateMethodWithStatement(method, callToSuperMethod, "result", method.getDefaultValue()); } } }
@Pure @Override public void checkUsage(@Nonnull Element element, @Nonnull AnnotationMirror annotationMirror, @NonCaptured @Modified @Nonnull ErrorLogger errorLogger) { if (element.getKind() == ElementKind.PARAMETER) { final @Nonnull Element enclosingElement = element.getEnclosingElement(); if (!(enclosingElement.getKind() == ElementKind.CONSTRUCTOR && ProcessingUtility.getConstructors(ProcessingUtility.getSurroundingType(element)).isSingle() || ProcessingUtility.hasAnnotation(enclosingElement, Recover.class))) { errorLogger.log("The generation annotation may only be used on parameters of a unique constructor or an executable annotated with '@Recover'.", SourcePosition.of(element, annotationMirror)); } } else if (element.getKind() == ElementKind.METHOD) { final @Nonnull ExecutableElement method = (ExecutableElement) element; if (!method.getModifiers().contains(Modifier.ABSTRACT)/* || !ProcessingUtility.isGetter(method)*/) { // TODO: @Default also has to be allowed on generated properties. errorLogger.log("The generation annotation may only be used on abstract getters.", SourcePosition.of(element, annotationMirror)); } } else { errorLogger.log("The generation annotation may only be used on parameters and methods.", SourcePosition.of(element, annotationMirror)); } }
@Pure @Override public void checkUsage(@Nonnull Element element, @Nonnull AnnotationMirror annotationMirror, @NonCaptured @Modified @Nonnull ErrorLogger errorLogger) { ValueAnnotationValidator.super.checkUsage(element, annotationMirror, errorLogger); if (!ProcessingUtility.hasNonPrivateMethod(ProcessingUtility.getSurroundingType(element), "size", int.class)) { errorLogger.log("The annotation $ may only be used in types with a non-private 'int size()' method:", SourcePosition.of(element, annotationMirror), getAnnotationNameWithLeadingAt()); } }
@Pure @Override public default void checkUsage(@Nonnull Element element, @Nonnull AnnotationMirror annotationMirror, @NonCaptured @Modified @Nonnull ErrorLogger errorLogger) { if (element.getKind() != ElementKind.METHOD && element.getKind() != ElementKind.CONSTRUCTOR) { errorLogger.log("The method annotation $ may only be used on methods and constructors.", SourcePosition.of(element, annotationMirror), getAnnotationNameWithLeadingAt()); } else if (!ProcessingUtility.isRawSubtype(ProcessingUtility.getSurroundingType(element), getReceiverType())) { errorLogger.log("The method annotation $ can only be used in $.", SourcePosition.of(element, annotationMirror), getAnnotationNameWithLeadingAt(), getReceiverType().getCanonicalName()); } }
@Pure @Override public void checkUsage(@Nonnull Element element, @Nonnull AnnotationMirror annotationMirror, @NonCaptured @Modified @Nonnull ErrorLogger errorLogger) { final @Nonnull TypeElement surroundingType = ProcessingUtility.getSurroundingType(element); if (element.getKind() == ElementKind.METHOD) { final @Nonnull ExecutableElement method = (ExecutableElement) element; final @Nonnull Types typeUtils = StaticProcessingEnvironment.getTypeUtils(); if (!element.getModifiers().contains(Modifier.STATIC) || !typeUtils.isSubtype(method.getReturnType(), typeUtils.erasure(surroundingType.asType()))) { errorLogger.log("The annotation $ may only be used on static methods whose return type is a subtype of the surrounding type.", SourcePosition.of(element, annotationMirror), getAnnotationNameWithLeadingAt()); } } else if (element.getKind() == ElementKind.CONSTRUCTOR) { if (ProcessingUtility.getConstructors(surroundingType).isSingle()) { errorLogger.log("The annotation $ may only be used on constructors if there are also other constructors in the same class.", SourcePosition.of(element, annotationMirror), getAnnotationNameWithLeadingAt()); } } else { errorLogger.log("The annotation $ may only be used on methods and constructors.", SourcePosition.of(element, annotationMirror), getAnnotationNameWithLeadingAt()); } for (@Nonnull ExecutableElement executableElement : ProcessingUtility.getConstructors(surroundingType).combine(ProcessingUtility.getMethods(surroundingType))) { if (ProcessingUtility.hasAnnotation(executableElement, Recover.class) && !executableElement.equals(element)) { errorLogger.log("The annotation $ may only be used on at most one executable in the same type.", SourcePosition.of(element, annotationMirror), getAnnotationNameWithLeadingAt()); } } }