use of javax.lang.model.type.ExecutableType in project react4j by react4j.
the class ReactProcessor method determineCallbacks.
private void determineCallbacks(@Nonnull final ComponentDescriptor descriptor) {
final List<CallbackDescriptor> callbacks = ProcessorUtil.getMethods(descriptor.getElement(), processingEnv.getTypeUtils()).stream().filter(m -> null != ProcessorUtil.findAnnotationByType(m, Constants.CALLBACK_ANNOTATION_CLASSNAME)).map(m -> createCallbackDescriptor(descriptor, m)).collect(Collectors.toList());
for (final CallbackDescriptor callback : callbacks) {
final ExecutableElement method = callback.getMethod();
final TypeElement callbackType = getCallbackType(method);
if (ElementKind.INTERFACE != callbackType.getKind()) {
throw new ReactProcessorException("The @Callback specified an invalid type that is not an interface.", callback.getMethod());
}
if (null == ProcessorUtil.findAnnotationByType(callbackType, Constants.JS_FUNCTION_CLASSNAME)) {
throw new ReactProcessorException("The @Callback specified an invalid type that is not annotated " + "with the annotation jsinterop.annotations.JsFunction.", callback.getMethod());
}
final CallbackDescriptor matched = callbacks.stream().filter(h -> h != callback && h.getName().equals(callback.getName())).findAny().orElse(null);
if (null != matched) {
throw new ReactProcessorException("The @Callback has the same name as the callback defined by " + matched.getMethod() + ".", callback.getMethod());
}
final CallbackDescriptor matched2 = callbacks.stream().filter(h -> h != callback && h.getMethod().getSimpleName().equals(callback.getMethod().getSimpleName())).findAny().orElse(null);
if (null != matched2) {
throw new ReactProcessorException("The @Callback has the same method name as the callback defined " + "by " + matched2.getMethod() + ".", callback.getMethod());
}
final ExecutableType methodType = callback.getMethodType();
final List<? extends TypeMirror> parameters = methodType.getParameterTypes();
if (!parameters.isEmpty()) {
// Our annotated callback method has parameters so they should exactly align
// in count and type with the parameters in the callback method
final ExecutableElement target = callback.getCallbackMethod();
final List<? extends VariableElement> targetParameters = target.getParameters();
if (targetParameters.size() != parameters.size()) {
throw new ReactProcessorException("The @Callback target has " + parameters.size() + " parameters " + "but the type parameter specified a callback with method type " + callback.getCallbackType().getQualifiedName() + " that has a " + "callback method with " + targetParameters.size() + " parameters. The " + "@Callback target should have zero parameters or match the number " + "of parameter in the target method " + target.getSimpleName() + ".", callback.getMethod());
}
for (int i = 0; i < parameters.size(); i++) {
final TypeMirror parameterType = parameters.get(i);
final VariableElement element = targetParameters.get(i);
final TypeMirror targetParameterType = element.asType();
final TypeMirror targetErased = processingEnv.getTypeUtils().erasure(targetParameterType);
final TypeMirror parameterErased = processingEnv.getTypeUtils().erasure(parameterType);
if (!processingEnv.getTypeUtils().isAssignable(targetErased, parameterErased)) {
throw new ReactProcessorException("The @Callback target parameter named " + callback.getMethod().getParameters().get(i).getSimpleName() + " of type " + parameterType + " is not assignable from target type " + targetParameterType + " of parameter " + element.getSimpleName() + " in method " + callback.getCallbackType().getQualifiedName() + "." + target.getSimpleName() + ".", callback.getMethod());
}
}
}
}
descriptor.setCallbacks(callbacks);
}
use of javax.lang.model.type.ExecutableType in project react4j by react4j.
the class ReactProcessor method determineDefaultPropsMethods.
private void determineDefaultPropsMethods(@Nonnull final ComponentDescriptor descriptor) {
final Types typeUtils = processingEnv.getTypeUtils();
final List<ExecutableElement> defaultPropsMethods = ProcessorUtil.getMethods(descriptor.getElement(), typeUtils).stream().filter(m -> null != ProcessorUtil.findAnnotationByType(m, Constants.PROP_DEFAULT_ANNOTATION_CLASSNAME)).collect(Collectors.toList());
for (final ExecutableElement method : defaultPropsMethods) {
final String name = derivePropDefaultName(method);
final PropDescriptor prop = descriptor.findPropNamed(name);
if (null == prop) {
throw new ReactProcessorException("@PropDefault target for prop named '" + name + "' has no corresponding " + "@Prop annotated method.", method);
}
final ExecutableType methodType = (ExecutableType) typeUtils.asMemberOf(descriptor.getDeclaredType(), method);
if (!processingEnv.getTypeUtils().isAssignable(methodType.getReturnType(), prop.getMethodType().getReturnType())) {
throw new ReactProcessorException("@PropDefault target has a return type that is not assignable to the " + "return type of the associated @Prop annotated method.", method);
}
prop.setDefaultMethod(method);
}
}
use of javax.lang.model.type.ExecutableType in project react4j by react4j.
the class ReactProcessor method linkStateMethods.
private void linkStateMethods(@Nonnull final ComponentDescriptor descriptor) {
final List<ExecutableElement> candidates = ProcessorUtil.getMethods(descriptor.getElement(), processingEnv.getTypeUtils()).stream().filter(m -> m.getModifiers().contains(Modifier.ABSTRACT)).filter(m -> null == ProcessorUtil.findAnnotationByType(descriptor.getElement(), Constants.PROP_ANNOTATION_CLASSNAME) && null == ProcessorUtil.findAnnotationByType(descriptor.getElement(), Constants.STATE_ANNOTATION_CLASSNAME)).collect(Collectors.toList());
for (final ExecutableElement method : candidates) {
final ExecutableType methodType = (ExecutableType) processingEnv.getTypeUtils().asMemberOf(descriptor.getDeclaredType(), method);
if (method.getReturnType().getKind() == TypeKind.VOID && 1 == method.getParameters().size()) {
final String stateName = ProcessorUtil.getPropertyMutatorName(method, ProcessorUtil.SENTINEL_NAME);
final StateValueDescriptor stateValueNamed = descriptor.findStateValueNamed(stateName);
if (null != stateValueNamed && !stateValueNamed.hasSetter()) {
stateValueNamed.setSetter(method, methodType);
}
} else if (method.getReturnType().getKind() != TypeKind.VOID && 0 == method.getParameters().size()) {
final String stateName = ProcessorUtil.getPropertyAccessorName(method, ProcessorUtil.SENTINEL_NAME);
final StateValueDescriptor stateValueNamed = descriptor.findStateValueNamed(stateName);
if (null != stateValueNamed && !stateValueNamed.hasGetter()) {
stateValueNamed.setGetter(method, methodType);
}
}
}
}
use of javax.lang.model.type.ExecutableType in project react4j by react4j.
the class ReactProcessor method determineLifecycleMethods.
private void determineLifecycleMethods(@Nonnull final TypeElement typeElement, @Nonnull final ComponentDescriptor descriptor) {
/*
* Get the list of lifecycle methods that have been overridden by typeElement
* a parent class, or by a default method method implemented by typeElement or
* a parent class.
*/
final Collection<ExecutableElement> lifecycleMethods = getComponentLifecycleMethods().values();
final Elements elementUtils = processingEnv.getElementUtils();
final Types typeUtils = processingEnv.getTypeUtils();
final TypeElement componentType = elementUtils.getTypeElement(Constants.COMPONENT_CLASSNAME);
final List<MethodDescriptor> overriddenLifecycleMethods = // Get all methods on type parent classes, and default methods from interfaces
ProcessorUtil.getMethods(typeElement, processingEnv.getTypeUtils()).stream().filter(m -> lifecycleMethods.stream().anyMatch(l -> elementUtils.overrides(m, l, typeElement))).filter(m -> m.getEnclosingElement() != componentType).map(m -> new MethodDescriptor(m, (ExecutableType) typeUtils.asMemberOf(descriptor.getDeclaredType(), m))).collect(Collectors.toList());
descriptor.setLifecycleMethods(overriddenLifecycleMethods);
}
use of javax.lang.model.type.ExecutableType in project react4j by react4j.
the class Generator method buildPropMethod.
private static MethodSpec.Builder buildPropMethod(@Nonnull final ComponentDescriptor descriptor, @Nonnull final PropDescriptor prop) {
final ExecutableElement methodElement = prop.getMethod();
final ExecutableType methodType = prop.getMethodType();
final TypeMirror returnType = methodType.getReturnType();
final MethodSpec.Builder method = MethodSpec.methodBuilder(methodElement.getSimpleName().toString()).returns(TypeName.get(returnType));
ProcessorUtil.copyTypeParameters(methodType, method);
ProcessorUtil.copyAccessModifiers(methodElement, method);
ProcessorUtil.copyDocumentedAnnotations(methodElement, method);
method.addAnnotation(Override.class);
final String name = prop.getName();
if (descriptor.isArezComponent()) {
final AnnotationSpec.Builder annotation = AnnotationSpec.builder(OBSERVABLE_ANNOTATION_CLASSNAME).addMember("name", "$S", name).addMember("expectSetter", "false");
method.addAnnotation(annotation.build());
}
final Element propType = prop.getPropType();
if (null != propType && descriptor.isArezComponent() && ElementKind.CLASS == propType.getKind()) {
if (null != ProcessorUtil.findAnnotationByType(propType, Constants.AREZ_COMPONENT_ANNOTATION_CLASSNAME)) {
method.addAnnotation(AnnotationSpec.builder(AREZ_DEPENDENCY_CLASSNAME).build());
}
}
final String convertMethodName = getConverter(returnType, methodElement, "Prop");
final String key = "child".equals(name) ? "children" : name;
if (null == ProcessorUtil.findAnnotationByType(methodElement, Constants.NONNULL_ANNOTATION_CLASSNAME)) {
method.addStatement("return props().has( $S ) ? props().getAny( $S ).$N() : null", key, key, convertMethodName);
} else {
method.addStatement("return props().getAny( $S ).$N()", key, convertMethodName);
}
return method;
}
Aggregations