use of javax.lang.model.type.ExecutableType in project react4j by react4j.
the class ReactProcessor method determineStateValues.
private void determineStateValues(@Nonnull final ComponentDescriptor descriptor) {
final List<ExecutableElement> methods = ProcessorUtil.getMethods(descriptor.getElement(), processingEnv.getTypeUtils()).stream().filter(m -> null != ProcessorUtil.findAnnotationByType(m, Constants.STATE_ANNOTATION_CLASSNAME)).collect(Collectors.toList());
final Map<String, StateValueDescriptor> values = new HashMap<>();
for (final ExecutableElement method : methods) {
final ExecutableType methodType = (ExecutableType) processingEnv.getTypeUtils().asMemberOf(descriptor.getDeclaredType(), method);
parseStateValueMethod(method, methodType, values);
}
final ArrayList<StateValueDescriptor> stateValues = new ArrayList<>(values.values());
descriptor.setStateValues(stateValues);
linkStateMethods(descriptor);
for (final StateValueDescriptor stateValue : stateValues) {
if (!stateValue.hasGetter()) {
throw new ReactProcessorException("@State target defined setter but no getter was defined and no " + "getter could be automatically determined", stateValue.getSetter());
} else if (!stateValue.hasSetter()) {
throw new ReactProcessorException("@State target defined getter but no setter was defined and no " + "setter could be automatically determined", stateValue.getGetter());
}
}
for (final StateValueDescriptor stateValue : stateValues) {
final TypeMirror returnType = stateValue.getGetterType().getReturnType();
final TypeMirror parameterType = stateValue.getSetterType().getParameterTypes().get(0);
if (!processingEnv.getTypeUtils().isSameType(parameterType, returnType)) {
throw new ReactProcessorException("@State property defines a setter and getter with different types." + " Getter type: " + returnType + " Setter type: " + parameterType + ".", stateValue.getGetter());
}
}
}
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);
}
Aggregations