Search in sources :

Example 1 with ProcessorException

use of org.realityforge.proton.ProcessorException in project react4j by react4j.

the class React4jProcessor method determineScheduleRenderMethods.

private void determineScheduleRenderMethods(@Nonnull final TypeElement typeElement, @Nonnull final ViewDescriptor descriptor) {
    final List<ScheduleRenderDescriptor> scheduleRenderDescriptors = new ArrayList<>();
    for (final ExecutableElement method : getMethods(typeElement)) {
        final AnnotationMirror annotation = AnnotationsUtil.findAnnotationByType(method, Constants.SCHEDULE_RENDER_CLASSNAME);
        if (null != annotation) {
            MemberChecks.mustBeAbstract(Constants.SCHEDULE_RENDER_CLASSNAME, method);
            MemberChecks.mustBeSubclassCallable(typeElement, Constants.VIEW_CLASSNAME, Constants.SCHEDULE_RENDER_CLASSNAME, method);
            MemberChecks.mustNotReturnAnyValue(Constants.SCHEDULE_RENDER_CLASSNAME, method);
            MemberChecks.mustNotThrowAnyExceptions(Constants.SCHEDULE_RENDER_CLASSNAME, method);
            final ViewType viewType = descriptor.getType();
            if (ViewType.STATEFUL != viewType) {
                final String message = MemberChecks.mustNot(Constants.SCHEDULE_RENDER_CLASSNAME, "be enclosed in a type if it is annotated by @View(type=" + viewType + "). The type must be STATEFUL");
                throw new ProcessorException(message, method);
            }
            final boolean skipShouldViewUpdate = AnnotationsUtil.getAnnotationValueValue(annotation, "skipShouldViewUpdate");
            scheduleRenderDescriptors.add(new ScheduleRenderDescriptor(method, skipShouldViewUpdate));
        }
    }
    descriptor.setScheduleRenderDescriptors(scheduleRenderDescriptors);
}
Also used : AnnotationMirror(javax.lang.model.element.AnnotationMirror) ProcessorException(org.realityforge.proton.ProcessorException) ExecutableElement(javax.lang.model.element.ExecutableElement) ArrayList(java.util.ArrayList)

Example 2 with ProcessorException

use of org.realityforge.proton.ProcessorException in project react4j by react4j.

the class React4jProcessor method determineRenderMethod.

private void determineRenderMethod(@Nonnull final TypeElement typeElement, @Nonnull final ViewDescriptor descriptor) {
    boolean foundRender = false;
    for (final ExecutableElement method : getMethods(typeElement)) {
        final AnnotationMirror annotation = AnnotationsUtil.findAnnotationByType(method, Constants.RENDER_CLASSNAME);
        if (null != annotation) {
            MemberChecks.mustNotBeAbstract(Constants.RENDER_CLASSNAME, method);
            MemberChecks.mustBeSubclassCallable(typeElement, Constants.VIEW_CLASSNAME, Constants.RENDER_CLASSNAME, method);
            MemberChecks.mustNotHaveAnyParameters(Constants.RENDER_CLASSNAME, method);
            MemberChecks.mustReturnAnInstanceOf(processingEnv, method, Constants.RENDER_CLASSNAME, Constants.VNODE_CLASSNAME);
            MemberChecks.mustNotThrowAnyExceptions(Constants.RENDER_CLASSNAME, method);
            MemberChecks.mustNotHaveAnyTypeParameters(Constants.RENDER_CLASSNAME, method);
            descriptor.setRender(method);
            foundRender = true;
        }
    }
    final boolean requireRender = descriptor.requireRender();
    if (requireRender && !foundRender) {
        throw new ProcessorException(MemberChecks.must(Constants.VIEW_CLASSNAME, "contain a method annotated with the " + MemberChecks.toSimpleName(Constants.RENDER_CLASSNAME) + " annotation or must specify type=NO_RENDER"), typeElement);
    } else if (!requireRender) {
        if (foundRender) {
            throw new ProcessorException(MemberChecks.mustNot(Constants.VIEW_CLASSNAME, "contain a method annotated with the " + MemberChecks.toSimpleName(Constants.RENDER_CLASSNAME) + " annotation or must not specify type=NO_RENDER"), typeElement);
        } else if (!descriptor.hasConstructor() && !descriptor.hasPostConstruct() && null == descriptor.getPostMount() && null == descriptor.getPostRender() && null == descriptor.getPreUpdate() && null == descriptor.getPostUpdate() && !descriptor.hasPreUpdateOnInputChange() && !descriptor.hasPostUpdateOnInputChange()) {
            throw new ProcessorException(MemberChecks.must(Constants.VIEW_CLASSNAME, "contain lifecycle methods if the the @View(type=NO_RENDER) parameter is specified"), typeElement);
        }
    }
}
Also used : AnnotationMirror(javax.lang.model.element.AnnotationMirror) ProcessorException(org.realityforge.proton.ProcessorException) ExecutableElement(javax.lang.model.element.ExecutableElement)

Example 3 with ProcessorException

use of org.realityforge.proton.ProcessorException in project react4j by react4j.

the class React4jProcessor method determineDefaultInputsMethods.

private void determineDefaultInputsMethods(@Nonnull final ViewDescriptor descriptor) {
    final List<ExecutableElement> defaultInputsMethods = getMethods(descriptor.getElement()).stream().filter(m -> AnnotationsUtil.hasAnnotationOfType(m, Constants.INPUT_DEFAULT_CLASSNAME)).collect(Collectors.toList());
    for (final ExecutableElement method : defaultInputsMethods) {
        final String name = deriveInputDefaultName(method);
        final InputDescriptor input = descriptor.findInputNamed(name);
        if (null == input) {
            throw new ProcessorException("@InputDefault target for input named '" + name + "' has no corresponding " + "@Input annotated method.", method);
        }
        final ExecutableType methodType = resolveMethodType(descriptor, method);
        if (!processingEnv.getTypeUtils().isAssignable(methodType.getReturnType(), input.getMethodType().getReturnType())) {
            throw new ProcessorException("@InputDefault target has a return type that is not assignable to the " + "return type of the associated @Input annotated method.", method);
        }
        MemberChecks.mustBeStaticallySubclassCallable(descriptor.getElement(), Constants.VIEW_CLASSNAME, Constants.INPUT_DEFAULT_CLASSNAME, method);
        MemberChecks.mustNotHaveAnyParameters(Constants.INPUT_DEFAULT_CLASSNAME, method);
        MemberChecks.mustNotThrowAnyExceptions(Constants.INPUT_DEFAULT_CLASSNAME, method);
        MemberChecks.mustReturnAValue(Constants.INPUT_DEFAULT_CLASSNAME, method);
        input.setDefaultMethod(method);
    }
}
Also used : Arrays(java.util.Arrays) SupportedOptions(javax.annotation.processing.SupportedOptions) Modifier(javax.lang.model.element.Modifier) VariableElement(javax.lang.model.element.VariableElement) DeferredElementSet(org.realityforge.proton.DeferredElementSet) HashMap(java.util.HashMap) TypeElement(javax.lang.model.element.TypeElement) SupportedAnnotationTypes(javax.annotation.processing.SupportedAnnotationTypes) ArrayList(java.util.ArrayList) HashSet(java.util.HashSet) ElementsUtil(org.realityforge.proton.ElementsUtil) SupportedSourceVersion(javax.annotation.processing.SupportedSourceVersion) Matcher(java.util.regex.Matcher) Diagnostic(javax.tools.Diagnostic) Map(java.util.Map) DeclaredType(javax.lang.model.type.DeclaredType) ProcessorException(org.realityforge.proton.ProcessorException) Nonnull(javax.annotation.Nonnull) Nullable(javax.annotation.Nullable) ArrayType(javax.lang.model.type.ArrayType) ElementKind(javax.lang.model.element.ElementKind) ExecutableType(javax.lang.model.type.ExecutableType) Collection(java.util.Collection) ExecutableElement(javax.lang.model.element.ExecutableElement) Set(java.util.Set) IOException(java.io.IOException) Element(javax.lang.model.element.Element) Types(javax.lang.model.util.Types) AnnotationsUtil(org.realityforge.proton.AnnotationsUtil) Collectors(java.util.stream.Collectors) AnnotationMirror(javax.lang.model.element.AnnotationMirror) TypeParameterElement(javax.lang.model.element.TypeParameterElement) TypeKind(javax.lang.model.type.TypeKind) AbstractStandardProcessor(org.realityforge.proton.AbstractStandardProcessor) SourceVersion(javax.lang.model.SourceVersion) List(java.util.List) TypeMirror(javax.lang.model.type.TypeMirror) MemberChecks(org.realityforge.proton.MemberChecks) RoundEnvironment(javax.annotation.processing.RoundEnvironment) TypeName(com.squareup.javapoet.TypeName) TypeVariable(javax.lang.model.type.TypeVariable) AnnotationValue(javax.lang.model.element.AnnotationValue) Pattern(java.util.regex.Pattern) Collections(java.util.Collections) ExecutableType(javax.lang.model.type.ExecutableType) ProcessorException(org.realityforge.proton.ProcessorException) ExecutableElement(javax.lang.model.element.ExecutableElement)

Example 4 with ProcessorException

use of org.realityforge.proton.ProcessorException in project react4j by react4j.

the class React4jProcessor method deriveInputName.

@Nonnull
private String deriveInputName(@Nonnull final ExecutableElement method) throws ProcessorException {
    final String specifiedName = (String) AnnotationsUtil.getAnnotationValue(method, Constants.INPUT_CLASSNAME, "name").getValue();
    final String name = getPropertyAccessorName(method, specifiedName);
    if (!SourceVersion.isIdentifier(name)) {
        throw new ProcessorException("@Input target specified an invalid name '" + specifiedName + "'. The " + "name must be a valid java identifier.", method);
    } else if (SourceVersion.isKeyword(name)) {
        throw new ProcessorException("@Input target specified an invalid name '" + specifiedName + "'. The " + "name must not be a java keyword.", method);
    } else {
        return name;
    }
}
Also used : ProcessorException(org.realityforge.proton.ProcessorException) Nonnull(javax.annotation.Nonnull)

Example 5 with ProcessorException

use of org.realityforge.proton.ProcessorException in project react4j by react4j.

the class React4jProcessor method createInputDescriptor.

@Nonnull
private InputDescriptor createInputDescriptor(@Nonnull final ViewDescriptor descriptor, @Nonnull final ExecutableElement method) {
    final String name = deriveInputName(method);
    final ExecutableType methodType = resolveMethodType(descriptor, method);
    verifyNoDuplicateAnnotations(method);
    MemberChecks.mustBeAbstract(Constants.INPUT_CLASSNAME, method);
    MemberChecks.mustNotHaveAnyParameters(Constants.INPUT_CLASSNAME, method);
    MemberChecks.mustReturnAValue(Constants.INPUT_CLASSNAME, method);
    MemberChecks.mustNotThrowAnyExceptions(Constants.INPUT_CLASSNAME, method);
    MemberChecks.mustNotBePackageAccessInDifferentPackage(descriptor.getElement(), Constants.VIEW_CLASSNAME, Constants.INPUT_CLASSNAME, method);
    final TypeMirror returnType = method.getReturnType();
    if ("build".equals(name)) {
        throw new ProcessorException("@Input named 'build' is invalid as it conflicts with the method named " + "build() that is used in the generated Builder classes", method);
    } else if ("child".equals(name) && (returnType.getKind() != TypeKind.DECLARED && !"react4j.ReactNode".equals(returnType.toString()))) {
        throw new ProcessorException("@Input named 'child' should be of type react4j.ReactNode", method);
    } else if ("children".equals(name) && (returnType.getKind() != TypeKind.DECLARED && !"react4j.ReactNode[]".equals(returnType.toString()))) {
        throw new ProcessorException("@Input named 'children' should be of type react4j.ReactNode[]", method);
    }
    if (returnType instanceof TypeVariable) {
        final TypeVariable typeVariable = (TypeVariable) returnType;
        final String typeVariableName = typeVariable.asElement().getSimpleName().toString();
        List<? extends TypeParameterElement> typeParameters = method.getTypeParameters();
        if (typeParameters.stream().anyMatch(p -> p.getSimpleName().toString().equals(typeVariableName))) {
            throw new ProcessorException("@Input named '" + name + "' is has a type variable as a return type " + "that is declared on the method.", method);
        }
    }
    final String qualifier = (String) AnnotationsUtil.getAnnotationValue(method, Constants.INPUT_CLASSNAME, "qualifier").getValue();
    final boolean contextInput = isContextInput(method);
    final Element inputType = processingEnv.getTypeUtils().asElement(returnType);
    final boolean immutable = isInputImmutable(method);
    final boolean observable = isInputObservable(descriptor, method, immutable);
    final boolean disposable = null != inputType && isInputDisposable(method, inputType);
    final TypeName typeName = TypeName.get(returnType);
    if (typeName.isBoxedPrimitive() && AnnotationsUtil.hasNonnullAnnotation(method)) {
        throw new ProcessorException("@Input named '" + name + "' is a boxed primitive annotated with a " + "@Nonnull annotation. The return type should be the primitive type.", method);
    }
    final ImmutableInputKeyStrategy strategy = immutable ? getImmutableInputKeyStrategy(typeName, inputType) : null;
    if (!"".equals(qualifier) && !contextInput) {
        throw new ProcessorException(MemberChecks.mustNot(Constants.INPUT_CLASSNAME, "specify qualifier parameter unless source=CONTEXT is also specified"), method);
    }
    final String requiredValue = ((VariableElement) AnnotationsUtil.getAnnotationValue(method, Constants.INPUT_CLASSNAME, "require").getValue()).getSimpleName().toString();
    final boolean dependency = isInputDependency(method, immutable, disposable);
    final InputDescriptor inputDescriptor = new InputDescriptor(descriptor, name, qualifier, method, methodType, inputType, contextInput, !immutable, observable, disposable, dependency, strategy, requiredValue);
    if (inputDescriptor.mayNeedMutableInputAccessedInPostConstructInvariant()) {
        if (ElementsUtil.isWarningSuppressed(method, Constants.WARNING_MUTABLE_INPUT_ACCESSED_IN_POST_CONSTRUCT, Constants.SUPPRESS_REACT4J_WARNINGS_CLASSNAME)) {
            inputDescriptor.suppressMutableInputAccessedInPostConstruct();
        }
    }
    return inputDescriptor;
}
Also used : ExecutableType(javax.lang.model.type.ExecutableType) TypeName(com.squareup.javapoet.TypeName) ProcessorException(org.realityforge.proton.ProcessorException) TypeMirror(javax.lang.model.type.TypeMirror) TypeVariable(javax.lang.model.type.TypeVariable) VariableElement(javax.lang.model.element.VariableElement) TypeElement(javax.lang.model.element.TypeElement) ExecutableElement(javax.lang.model.element.ExecutableElement) Element(javax.lang.model.element.Element) TypeParameterElement(javax.lang.model.element.TypeParameterElement) Nonnull(javax.annotation.Nonnull)

Aggregations

ProcessorException (org.realityforge.proton.ProcessorException)13 ExecutableElement (javax.lang.model.element.ExecutableElement)12 Nonnull (javax.annotation.Nonnull)8 AnnotationMirror (javax.lang.model.element.AnnotationMirror)7 VariableElement (javax.lang.model.element.VariableElement)7 TypeName (com.squareup.javapoet.TypeName)6 ArrayList (java.util.ArrayList)6 Element (javax.lang.model.element.Element)6 TypeElement (javax.lang.model.element.TypeElement)6 TypeParameterElement (javax.lang.model.element.TypeParameterElement)6 ExecutableType (javax.lang.model.type.ExecutableType)6 TypeMirror (javax.lang.model.type.TypeMirror)6 ArrayType (javax.lang.model.type.ArrayType)5 DeclaredType (javax.lang.model.type.DeclaredType)5 TypeVariable (javax.lang.model.type.TypeVariable)5 IOException (java.io.IOException)4 Arrays (java.util.Arrays)4 Collection (java.util.Collection)4 Collections (java.util.Collections)4 HashMap (java.util.HashMap)4