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