private void processExecutableElement(String prefix, ExecutableElement element) { if (element.getModifiers().contains(Modifier.PUBLIC) && (TypeKind.VOID != element.getReturnType().getKind())) { Element returns = this.processingEnv.getTypeUtils().asElement(element.getReturnType()); if (returns instanceof TypeElement) { ItemMetadata group = ItemMetadata.newGroup( prefix, this.typeUtils.getType(returns), this.typeUtils.getType(element.getEnclosingElement()), element.toString()); if (this.metadataCollector.hasSimilarGroup(group)) { this.processingEnv .getMessager() .printMessage( Kind.ERROR, "Duplicate `@ConfigurationProperties` definition for prefix '" + prefix + "'", element); } else { this.metadataCollector.add(group); processTypeElement(prefix, (TypeElement) returns, element); } } } }
/** * Returns true if generated code can invoke {@code constructor}. That is, if the constructor is * non-private and its enclosing class is either a top-level class or a static nested class. */ public static boolean isCallableConstructor(ExecutableElement constructor) { if (constructor.getModifiers().contains(Modifier.PRIVATE)) { return false; } TypeElement type = (TypeElement) constructor.getEnclosingElement(); return type.getEnclosingElement().getKind() == ElementKind.PACKAGE || type.getModifiers().contains(Modifier.STATIC); }
/** * Build the comments for the method. Do nothing if {@link Configuration#nocomment} is set to * true. * * @param node the XML element that specifies which components to document * @param methodDocTree the content tree to which the documentation will be added */ public void buildMethodComments(XMLNode node, Content methodDocTree) { if (!configuration.nocomment) { ExecutableElement method = currentMethod; if (utils.getBody(currentMethod).isEmpty()) { DocFinder.Output docs = DocFinder.search(configuration, new DocFinder.Input(utils, currentMethod)); if (docs.inlineTags != null && !docs.inlineTags.isEmpty()) method = (ExecutableElement) docs.holder; } TypeMirror containingType = method.getEnclosingElement().asType(); writer.addComments(containingType, method, methodDocTree); } }
private ProcessorMetaModelMethod toMethodModel(ExecutableElement e, AnnotationMirror am) { // TypeMirror declaringType = e.getReceiverType(); final String declaringClassName = ((TypeElement) e.getEnclosingElement()).getQualifiedName().toString(); final String metamodelAnnotationName = getAnnotationClassName(am); final Map<String, String> metamodelAttributes = getAnnotationAttributes(am); return new ProcessorMetaModelMethod( e.getSimpleName().toString(), declaringClassName, getParamTypes(e), e.getReturnType().toString(), metamodelAnnotationName, metamodelAttributes); }
private void processRequestMappingMethod(ExecutableElement executableElement) { TypeElement cls = (TypeElement) executableElement.getEnclosingElement(); String path = getClassLevelUrlPath(cls); RequestMapping anno = executableElement.getAnnotation(RequestMapping.class); path = addMethodPathComponent(executableElement, cls, path, anno); RequestMethod meth = getRequestMethod(executableElement, cls, anno); RestDocumentation.Resource.Method doc = _docs.getResourceDocumentation(path).newMethodDocumentation(meth); String docComment = processingEnv.getElementUtils().getDocComment(executableElement); if (StringUtils.isNotBlank(docComment)) { MethodStructure methodStructure = generateMethodStructure(docComment); doc.setCommentText(generateJavaDocHTML(methodStructure)); doc.setCommentSummary(methodStructure.getDescription()); } buildParameterData(executableElement, doc); buildResponseFormat(executableElement.getReturnType(), doc); }
private void buildRequestBodies( ExecutableElement executableElement, RestDocumentation.Resource.Method doc) { List<VariableElement> requestBodies = new ArrayList<VariableElement>(); for (VariableElement var : executableElement.getParameters()) { if (var.getAnnotation(org.springframework.web.bind.annotation.RequestBody.class) != null) { requestBodies.add(var); } } if (requestBodies.size() > 1) { throw new IllegalStateException( String.format( "Method %s in class %s has multiple @RequestBody params", executableElement.getSimpleName(), executableElement.getEnclosingElement())); } if (requestBodies.size() == 1) { buildRequestBody(requestBodies.get(0), doc); } }
private int processConstructor(ExecutableElement constrElt) { if (constrElt.getModifiers().contains(Modifier.PUBLIC)) { Element ownerElt = constrElt.getEnclosingElement(); if (ownerElt.equals(modelElt)) { List<? extends VariableElement> parameters = constrElt.getParameters(); int size = parameters.size(); if (size == 1) { TypeInfo ti = typeFactory.create(parameters.get(0).asType()); if (ti instanceof ClassTypeInfo) { ClassTypeInfo cl = (ClassTypeInfo) ti; if (cl.getKind() == ClassKind.JSON_OBJECT) { return 2; } } } } } return 0; }
@Override public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { for (Element annotatedElt : roundEnv.getElementsAnnotatedWith(CodeTranslate.class)) { ExecutableElement methodElt = (ExecutableElement) annotatedElt; TypeElement typeElt = (TypeElement) methodElt.getEnclosingElement(); if (typeElt.getQualifiedName().toString().equals(fqn) && methodElt.getSimpleName().toString().equals(method)) { for (Lang lang : langs) { Result result; try { String translation = translator.translate(methodElt, lang); result = new Result.Source(translation); } catch (Exception e) { result = new Result.Failure(e); } results.put(lang, result); } } } return false; }
/** * Formats an ExecutableElement as if it were contained within the container, if the container is * present. */ public String format(ExecutableElement method, Optional<DeclaredType> container) { StringBuilder builder = new StringBuilder(); TypeElement type = MoreElements.asType(method.getEnclosingElement()); ExecutableType executableType = MoreTypes.asExecutable(method.asType()); if (container.isPresent()) { executableType = MoreTypes.asExecutable(types.asMemberOf(container.get(), method)); type = MoreElements.asType(container.get().asElement()); } // TODO(cgruber): AnnotationMirror formatter. List<? extends AnnotationMirror> annotations = method.getAnnotationMirrors(); if (!annotations.isEmpty()) { Iterator<? extends AnnotationMirror> annotationIterator = annotations.iterator(); for (int i = 0; annotationIterator.hasNext(); i++) { if (i > 0) { builder.append(' '); } builder.append(ErrorMessages.format(annotationIterator.next())); } builder.append(' '); } builder.append(nameOfType(executableType.getReturnType())); builder.append(' '); builder.append(type.getQualifiedName()); builder.append('.'); builder.append(method.getSimpleName()); builder.append('('); checkState(method.getParameters().size() == executableType.getParameterTypes().size()); Iterator<? extends VariableElement> parameters = method.getParameters().iterator(); Iterator<? extends TypeMirror> parameterTypes = executableType.getParameterTypes().iterator(); for (int i = 0; parameters.hasNext(); i++) { if (i > 0) { builder.append(", "); } appendParameter(builder, parameters.next(), parameterTypes.next()); } builder.append(')'); return builder.toString(); }
/** Returns a user-presentable string like {@code coffee.CoffeeModule}. */ public static String className(ExecutableElement method) { return ((TypeElement) method.getEnclosingElement()).getQualifiedName().toString(); }
private void writeProvidesAdapter( JavaWriter writer, ExecutableElement providerMethod, Map<ExecutableElement, String> methodToClassName, Map<String, AtomicInteger> methodNameToNextId) throws IOException { String methodName = providerMethod.getSimpleName().toString(); String moduleType = CodeGen.typeToString(providerMethod.getEnclosingElement().asType()); String className = bindingClassName(providerMethod, methodToClassName, methodNameToNextId); String returnType = CodeGen.typeToString(providerMethod.getReturnType()); List<? extends VariableElement> parameters = providerMethod.getParameters(); boolean dependent = !parameters.isEmpty(); writer.emitEmptyLine(); writer.emitJavadoc(binderTypeDocs(returnType, false, false, dependent)); writer.beginType( className, "class", PUBLIC | FINAL | STATIC, JavaWriter.type(Binding.class, returnType), JavaWriter.type(Provider.class, returnType)); writer.emitField(moduleType, "module", PRIVATE | FINAL); for (Element parameter : parameters) { TypeMirror parameterType = parameter.asType(); writer.emitField( JavaWriter.type(Binding.class, CodeGen.typeToString(parameterType)), parameterName(parameter), PRIVATE); } writer.emitEmptyLine(); writer.beginMethod(null, className, PUBLIC, moduleType, "module"); boolean singleton = providerMethod.getAnnotation(Singleton.class) != null; String key = JavaWriter.stringLiteral(GeneratorKeys.get(providerMethod)); String membersKey = null; writer.emitStatement( "super(%s, %s, %s, %s.class)", key, membersKey, (singleton ? "IS_SINGLETON" : "NOT_SINGLETON"), moduleType); writer.emitStatement("this.module = module"); writer.endMethod(); if (dependent) { writer.emitEmptyLine(); writer.emitJavadoc(ProcessorJavadocs.ATTACH_METHOD); writer.emitAnnotation(Override.class); writer.emitAnnotation(SuppressWarnings.class, JavaWriter.stringLiteral("unchecked")); writer.beginMethod("void", "attach", PUBLIC, Linker.class.getCanonicalName(), "linker"); for (VariableElement parameter : parameters) { String parameterKey = GeneratorKeys.get(parameter); writer.emitStatement( "%s = (%s) linker.requestBinding(%s, %s.class)", parameterName(parameter), writer.compressType( JavaWriter.type(Binding.class, CodeGen.typeToString(parameter.asType()))), JavaWriter.stringLiteral(parameterKey), writer.compressType(moduleType)); } writer.endMethod(); writer.emitEmptyLine(); writer.emitJavadoc(ProcessorJavadocs.GET_DEPENDENCIES_METHOD); writer.emitAnnotation(Override.class); String setOfBindings = JavaWriter.type(Set.class, "Binding<?>"); writer.beginMethod( "void", "getDependencies", PUBLIC, setOfBindings, "getBindings", setOfBindings, "injectMembersBindings"); for (Element parameter : parameters) { writer.emitStatement("getBindings.add(%s)", parameter.getSimpleName().toString()); } writer.endMethod(); } writer.emitEmptyLine(); writer.emitJavadoc(ProcessorJavadocs.GET_METHOD, returnType); writer.emitAnnotation(Override.class); writer.beginMethod(returnType, "get", PUBLIC); StringBuilder args = new StringBuilder(); boolean first = true; for (Element parameter : parameters) { if (!first) args.append(", "); else first = false; args.append(String.format("%s.get()", parameter.getSimpleName().toString())); } writer.emitStatement("return module.%s(%s)", methodName, args.toString()); writer.endMethod(); writer.endType(); }
private void processMethod( String name, ExecutableElement getterElt, ExecutableElement setterElt, ExecutableElement adderElt) { PropertyKind propKind = null; TypeInfo propType = null; TypeMirror propTypeMirror = null; // if (setterElt != null) { VariableElement paramElt = setterElt.getParameters().get(0); propTypeMirror = paramElt.asType(); propType = typeFactory.create(propTypeMirror); propKind = PropertyKind.forType(propType.getKind()); switch (propKind) { case LIST: case SET: propType = ((ParameterizedTypeInfo) propType).getArgs().get(0); propTypeMirror = ((DeclaredType) propTypeMirror).getTypeArguments().get(0); break; case MAP: propType = ((ParameterizedTypeInfo) propType).getArgs().get(1); propTypeMirror = ((DeclaredType) propTypeMirror).getTypeArguments().get(1); break; } } // if (getterElt != null) { TypeMirror getterTypeMirror = getterElt.getReturnType(); TypeInfo getterType = typeFactory.create(getterTypeMirror); PropertyKind getterKind = PropertyKind.forType(getterType.getKind()); switch (getterKind) { case LIST: case SET: getterType = ((ParameterizedTypeInfo) getterType).getArgs().get(0); getterTypeMirror = ((DeclaredType) getterTypeMirror).getTypeArguments().get(0); break; case MAP: getterType = ((ParameterizedTypeInfo) getterType).getArgs().get(1); getterTypeMirror = ((DeclaredType) getterTypeMirror).getTypeArguments().get(1); break; } if (propType != null) { if (propKind != getterKind) { throw new GenException( getterElt, name + " getter " + getterKind + " does not match the setter " + propKind); } if (!getterType.equals(propType)) { throw new GenException( getterElt, name + " getter type " + getterType + " does not match the setter type " + propType); } } else { propTypeMirror = getterTypeMirror; propType = getterType; propKind = getterKind; } } // if (adderElt != null) { switch (adderElt.getParameters().size()) { case 1: { VariableElement paramElt = adderElt.getParameters().get(0); TypeMirror adderTypeMirror = paramElt.asType(); TypeInfo adderType = typeFactory.create(adderTypeMirror); if (propTypeMirror != null) { if (propKind != PropertyKind.LIST && propKind != PropertyKind.SET) { throw new GenException( adderElt, name + "adder does not correspond to non list/set"); } if (!adderType.equals(propType)) { throw new GenException( adderElt, name + " adder type " + adderType + " does not match the property type " + propType); } } else { propTypeMirror = adderTypeMirror; propType = adderType; propKind = PropertyKind.LIST; } break; } case 2: { VariableElement paramElt = adderElt.getParameters().get(1); TypeMirror adderTypeMirror = paramElt.asType(); TypeInfo adderType = typeFactory.create(adderTypeMirror); if (propTypeMirror != null) { if (propKind != PropertyKind.MAP) { throw new GenException(adderElt, name + "adder does not correspond to non map"); } if (!adderType.equals(propType)) { throw new GenException( adderElt, name + " adder type " + adderType + " does not match the property type " + propType); } } else { propTypeMirror = adderTypeMirror; propType = adderType; propKind = PropertyKind.MAP; } break; } } } // boolean jsonifiable; switch (propType.getKind()) { case OBJECT: if (propKind == PropertyKind.VALUE) { return; } case PRIMITIVE: case BOXED_PRIMITIVE: case STRING: case API: case JSON_OBJECT: case JSON_ARRAY: case ENUM: jsonifiable = true; break; case DATA_OBJECT: Element propTypeElt = typeUtils.asElement(propTypeMirror); jsonifiable = propTypeElt.getAnnotation(DataObject.class) == null || Helper.isJsonifiable(elementUtils, typeUtils, (TypeElement) propTypeElt); break; default: return; } boolean declared = false; Doc doc = null; for (ExecutableElement methodElt : Arrays.asList(setterElt, adderElt, getterElt)) { if (methodElt != null) { // A stream that list all overriden methods from super types // the boolean control whether or not we want to filter only annotated // data objects Function<Boolean, Stream<ExecutableElement>> overridenMeths = (annotated) -> { Set<DeclaredType> ancestorTypes = Helper.resolveAncestorTypes(modelElt, true, true); return ancestorTypes .stream() .map(DeclaredType::asElement) .filter(elt -> !annotated || elt.getAnnotation(DataObject.class) != null) .flatMap(Helper.cast(TypeElement.class)) .flatMap(elt -> elementUtils.getAllMembers(elt).stream()) .flatMap(Helper.instanceOf(ExecutableElement.class)) .filter( executableElt -> executableElt.getKind() == ElementKind.METHOD && elementUtils.overrides(methodElt, executableElt, modelElt)); }; // if (doc == null) { doc = docFactory.createDoc(methodElt); if (doc == null) { Optional<Doc> first = overridenMeths .apply(false) .map(docFactory::createDoc) .filter(d -> d != null) .findFirst(); doc = first.orElse(null); } } // if (!declared) { Element ownerElt = methodElt.getEnclosingElement(); if (ownerElt.equals(modelElt)) { Object[] arr = overridenMeths .apply(true) .limit(1) .filter(elt -> !elt.getModifiers().contains(Modifier.ABSTRACT)) .toArray(); // Handle the case where this methods overrides from another data object declared = arr.length == 0; } else { declared = ownerElt.getAnnotation(DataObject.class) == null; } } } } PropertyInfo property = new PropertyInfo( declared, name, doc, propType, setterElt != null ? setterElt.getSimpleName().toString() : null, adderElt != null ? adderElt.getSimpleName().toString() : null, getterElt != null ? getterElt.getSimpleName().toString() : null, propKind, jsonifiable); propertyMap.put(property.name, property); }
private void processMethods(List<ExecutableElement> methodsElt) { Map<String, ExecutableElement> getters = new HashMap<>(); Map<String, ExecutableElement> setters = new HashMap<>(); Map<String, ExecutableElement> adders = new HashMap<>(); while (methodsElt.size() > 0) { ExecutableElement methodElt = methodsElt.remove(0); if (((TypeElement) methodElt.getEnclosingElement()) .getQualifiedName() .toString() .equals("java.lang.Object")) { continue; } String methodName = methodElt.getSimpleName().toString(); if (methodName.startsWith("get") && methodName.length() > 3 && Character.isUpperCase(methodName.charAt(3)) && methodElt.getParameters().isEmpty() && methodElt.getReturnType().getKind() != TypeKind.VOID) { String name = Helper.normalizePropertyName(methodName.substring(3)); getters.put(name, methodElt); } else if (methodName.startsWith("is") && methodName.length() > 2 && Character.isUpperCase(methodName.charAt(2)) && methodElt.getParameters().isEmpty() && methodElt.getReturnType().getKind() != TypeKind.VOID) { String name = Helper.normalizePropertyName(methodName.substring(2)); getters.put(name, methodElt); } else if ((methodName.startsWith("set") || methodName.startsWith("add")) && methodName.length() > 3 && Character.isUpperCase(methodName.charAt(3))) { String prefix = methodName.substring(0, 3); String name = Helper.normalizePropertyName(methodName.substring(3)); int numParams = methodElt.getParameters().size(); if ("add".equals(prefix)) { if (name.endsWith("s")) { throw new GenException(methodElt, "Option adder name must not terminate with 's' char"); } else { name += "s"; } TypeMirror t = methodElt.getParameters().get(0).asType(); if (numParams == 1 || (numParams == 2 && t.getKind() == TypeKind.DECLARED && ((TypeElement) ((DeclaredType) t).asElement()) .getQualifiedName() .toString() .equals("java.lang.String"))) { adders.put(name, methodElt); } } else { if (numParams == 1) { setters.put(name, methodElt); } } } } Set<String> names = new HashSet<>(); names.addAll(getters.keySet()); names.addAll(setters.keySet()); names.addAll(adders.keySet()); for (String name : names) { processMethod(name, getters.get(name), setters.get(name), adders.get(name)); } }