package org.wikbook.template.processing; import org.wikbook.template.processing.metamodel.TemplateAnnotation; import org.wikbook.template.processing.metamodel.ModelContext; import org.wikbook.template.processing.metamodel.TemplateElement; import org.wikbook.template.processing.metamodel.TemplateType; import javax.lang.model.element.Element; import javax.lang.model.element.ElementVisitor; import javax.lang.model.element.ExecutableElement; import javax.lang.model.element.PackageElement; import javax.lang.model.element.TypeElement; import javax.lang.model.element.TypeParameterElement; import javax.lang.model.element.VariableElement; import javax.lang.model.element.ElementKind; import javax.lang.model.type.ArrayType; import javax.lang.model.type.DeclaredType; import javax.lang.model.type.TypeMirror; import java.io.BufferedReader; import java.io.IOException; import java.io.StringReader; import java.lang.annotation.Annotation; import java.util.ArrayList; import java.util.List; /** * @author <a href="mailto:alain.defrance@exoplatform.com">Alain Defrance</a> * @version $Revision$ */ public class TemplateElementVisitor implements ElementVisitor<List<TemplateElement>, ModelContext> { public List<TemplateElement> visit(Element element, ModelContext ctx) { return null; } public List<TemplateElement> visit(Element element) { return null; } public List<TemplateElement> visitPackage(PackageElement packageElement, ModelContext ctx) { List<TemplateElement> elements = new ArrayList<TemplateElement>(); TemplateElement pkgTmplElement = new TemplateElement(packageElement.getQualifiedName().toString()); applyDoc(packageElement, pkgTmplElement, ctx); for (Class clazz : ctx.getAnnotations()) { Annotation a = packageElement.getAnnotation(clazz); if (a != null) { TemplateAnnotation annotation = ProcessingUtils.createAnnotation(a, pkgTmplElement); pkgTmplElement.addAnnotation(annotation); if (!elements.contains(pkgTmplElement)) { elements.add(pkgTmplElement); } for (Element el : packageElement.getEnclosedElements()) { for (TemplateElement te : el.accept(this, ctx)) { pkgTmplElement.addElement(te); } } } } return elements; } public List<TemplateElement> visitType(TypeElement typeElement, ModelContext ctx) { TypeMirror paramType = typeElement.asType(); TemplateType type = buildTemplateType(paramType, ctx); TemplateElement classElement = new TemplateElement(typeElement.getSimpleName().toString(), type); applyDoc(typeElement, classElement, ctx); if (ctx == null) { throw new NullPointerException(); } List<TemplateElement> elements = new ArrayList<TemplateElement>(); ctx.setTypeElement(classElement); for (Class clazz : ctx.getAnnotations()) { Annotation a = typeElement.getAnnotation(clazz); if (a != null) { TemplateAnnotation annotation = ProcessingUtils.createAnnotation(a, classElement); classElement.addAnnotation(annotation); if (!elements.contains(classElement)) { elements.add(classElement); } for (Element child : typeElement.getEnclosedElements()) { if (child.getKind().equals(ElementKind.METHOD)) { child.accept(this, ctx); } } } } return elements; } public List<TemplateElement> visitVariable(VariableElement variableElement, ModelContext ctx) { TypeMirror paramType = variableElement.asType(); TemplateType type = buildTemplateType(paramType, ctx); TemplateElement paramElement = new TemplateElement(variableElement.getSimpleName().toString(), type); TemplateElement methodElement = ctx.getExecutableElement(); for (Class clazz : ctx.getAnnotations()) { Annotation a = variableElement.getAnnotation(clazz); TemplateAnnotation annotation = ProcessingUtils.createAnnotation(a, paramElement); if (annotation != null) { for (String key : methodElement.getJavadoc().keySet()) { if ("param".equals(key)) { List<List<String>> paramsDoc = methodElement.getJavadoc().get(key); docParam(annotation, variableElement, paramsDoc); } } paramElement.addAnnotation(annotation); if (!methodElement.getElements().contains(paramElement)) { methodElement.addElement(paramElement); } } } return null; } public List<TemplateElement> visitExecutable(ExecutableElement executableElement, ModelContext ctx) { TypeMirror returnType = executableElement.getReturnType(); TemplateType type = buildTemplateType(returnType, ctx); String executableName = executableElement.getSimpleName().toString(); TemplateElement methodElement = new TemplateElement(executableName, type); TemplateElement typeElement = ctx.getTypeElement(); applyDoc(executableElement, methodElement, ctx); for (Class clazz : ctx.getAnnotations()) { Annotation a = executableElement.getAnnotation(clazz); TemplateAnnotation annotation = ProcessingUtils.createAnnotation(a, methodElement); if (annotation != null) { methodElement.addAnnotation(annotation); if (!typeElement.getElements().contains(methodElement)) { typeElement.addElement(methodElement); ctx.setExecutableElement(methodElement); for (VariableElement e : executableElement.getParameters()) { e.accept(this, ctx); } } } } return null; } public List<TemplateElement> visitTypeParameter(TypeParameterElement typeParameterElement, ModelContext ctx) { return null; } public List<TemplateElement> visitUnknown(Element element, ModelContext ctx) { return null; } private void doc(TemplateElement tel, String name, List<String> l) { if (name == null) { tel.getJavadoc(null).add(new ArrayList<String>(l)); } else { if (l.size() == 0) { l.add(name.substring(1)); } tel.getJavadoc(name.substring(1)).add(new ArrayList<String>(l)); } l.clear(); } private void applyDoc(Element el, TemplateElement tel, ModelContext ctx) { // String documentation = ctx.getElementsUtils().getDocComment(el); if (documentation == null) return; // BufferedReader br = new BufferedReader(new StringReader(documentation)); String currentName = null; List<String> l = new ArrayList<String>(); try { String line; while ((line = br.readLine()) != null) { line = cleanLeft(line); if (line.startsWith("@")) { doc(tel, currentName, l); int delimiterPos = line.indexOf(" "); if (delimiterPos != -1) { currentName = line.substring(0, delimiterPos); l.add(line.substring(delimiterPos + 1)); } else { currentName = line; } } else { l.add(line); } } } catch (IOException e) { throw new RuntimeException(e); } doc(tel, currentName, l); } private void docParam(TemplateAnnotation annotation, VariableElement variableElement, List<List<String>> paramsDoc) { for (List<String> docValue : paramsDoc) { if (docValue.size() > 0) { String elementName = variableElement.getSimpleName().toString(); if (docValue.get(0).startsWith(elementName)) { int pos = elementName.length() + 1; if (pos < docValue.get(0).length()) { docValue.set(0, docValue.get(0).substring(pos)); annotation.getJavadoc(null).add(docValue); } else { annotation.getJavadoc(null).add(new ArrayList<String>()); } } } } } private TemplateType buildTemplateType(TypeMirror typeMirror, ModelContext ctx) { switch (typeMirror.getKind()) { case ARRAY: ArrayType arrayType = (ArrayType) typeMirror; DeclaredType componentDeclaredType = (DeclaredType) arrayType.getComponentType(); TemplateType templateType = buildTemplateType(componentDeclaredType, ctx); return new TemplateType( templateType.getName(), templateType.getFqn(), true, templateType.getParameters()); case DECLARED: DeclaredType declaredType = (DeclaredType) typeMirror; TypeElement declaredTypeElement = (TypeElement) declaredType.asElement(); List<TemplateType> typeParameters = new ArrayList<TemplateType>(); for (TypeMirror mirror : declaredType.getTypeArguments()) { typeParameters.add(buildTemplateType(mirror, ctx)); } return new TemplateType( declaredTypeElement.getSimpleName().toString(), declaredTypeElement.getQualifiedName().toString(), false, typeParameters.toArray(new TemplateType[]{})); default: return new TemplateType("", "", false, new TemplateType[]{}); } } private String cleanLeft(String newJavadocEntry) { for (int i = 0; i < newJavadocEntry.length(); ++i) { switch (newJavadocEntry.charAt(i)) { case ' ': continue; case '@': return newJavadocEntry.substring(i); default: return newJavadocEntry; } } return ""; } }