/******************************************************************************* * Copyright (c) 2007, 2009 BEA Systems, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * wharley@bea.com - initial API and implementation *******************************************************************************/ package org.eclipse.jdt.apt.pluggable.tests.processors.genclass6; import java.io.IOException; import java.io.PrintWriter; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import javax.annotation.processing.AbstractProcessor; import javax.annotation.processing.Filer; import javax.annotation.processing.Messager; import javax.annotation.processing.ProcessingEnvironment; import javax.annotation.processing.RoundEnvironment; import javax.annotation.processing.SupportedAnnotationTypes; import javax.annotation.processing.SupportedOptions; import javax.annotation.processing.SupportedSourceVersion; import javax.lang.model.SourceVersion; import javax.lang.model.element.Element; import javax.lang.model.element.TypeElement; import javax.tools.Diagnostic; import javax.tools.FileObject; import javax.tools.JavaFileObject; import javax.tools.StandardLocation; import org.eclipse.jdt.apt.pluggable.tests.annotations.GenClass6; /** * A processor that reads the GenClass6 annotation and produces the specified Java type */ @SupportedAnnotationTypes({ "org.eclipse.jdt.apt.pluggable.tests.annotations.GenClass6" }) @SupportedSourceVersion(SourceVersion.RELEASE_6) @SupportedOptions({}) public class GenClass6Proc extends AbstractProcessor { private ProcessingEnvironment _processingEnv; private Messager _messager; private Filer _filer; private Map<String, Element> _classesToSummarize; // map of generated name to element that produced it /* (non-Javadoc) * @see javax.annotation.processing.AbstractProcessor#init(javax.annotation.processing.ProcessingEnvironment) */ @Override public synchronized void init(ProcessingEnvironment processingEnv) { super.init(processingEnv); _processingEnv = processingEnv; _filer = _processingEnv.getFiler(); _messager = _processingEnv.getMessager(); _classesToSummarize = new HashMap<String, Element>(); } /* (non-Javadoc) * @see javax.annotation.processing.AbstractProcessor#process(java.util.Set, javax.annotation.processing.RoundEnvironment) */ @Override public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { if (roundEnv.processingOver() && !_classesToSummarize.isEmpty()) { summarize(); } else if (!annotations.isEmpty()) { round(annotations, roundEnv); } return true; } /** * Perform a round of processing */ private void round(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { TypeElement genClassAnno = annotations.iterator().next(); Set<? extends Element> annotatedEls = roundEnv.getElementsAnnotatedWith(genClassAnno); for (Element e : annotatedEls) { GenClass6 genClassMirror = e.getAnnotation(GenClass6.class); processType(genClassMirror, e); } } /** * @param genClassMirror */ private void processType(GenClass6 genClassMirror, Element annotatedEl) { // Collect and validate the parameters of the annotation String pkg = null; String name = null; String method = null; boolean summary = false; int rounds = 1; String[] options = null; try { pkg = genClassMirror.pkg(); name = genClassMirror.name(); method = genClassMirror.method(); summary = genClassMirror.summary(); rounds = genClassMirror.rounds(); options = genClassMirror.options(); } catch (Exception e) { _messager.printMessage(Diagnostic.Kind.WARNING, "Unable to read @GenClass6 annotation" + e.getLocalizedMessage(), annotatedEl); return; } // Options allow the processor to expose certain error conditions. if (null != options) { Set<String> optionSet = new HashSet<String>(Arrays.asList(options)); // See https://bugs.eclipse.org/269934: calling getEnclosedElements forces resolution of referenced types if (optionSet.contains("forceElementResolution")) { annotatedEl.getEnclosedElements(); } } if (name.length() == 0) { // User hasn't specified name yet _messager.printMessage(Diagnostic.Kind.WARNING, "The name attribute is missing", annotatedEl); return; } if (pkg == null) { pkg = ""; } String qname = (pkg.length() > 0) ? pkg + '.' + name : name; if (method == null) { method = ""; } // Get a writer JavaFileObject jfo = null; try { jfo = _filer.createSourceFile(qname, annotatedEl); } catch (IOException e) { _messager.printMessage(Diagnostic.Kind.WARNING, "Unable to open file for class " + qname, annotatedEl); return; } PrintWriter pw = null; try { pw = new PrintWriter(jfo.openWriter()); } catch (IOException e) { _messager.printMessage(Diagnostic.Kind.WARNING, "Unable to get writer for file " + jfo.getName()); return; } // Generate the class if (summary) { _classesToSummarize.put(qname, annotatedEl); } pw.println("// Generated by " + this.getClass().getName()); pw.println("package " + pkg + ";"); if (rounds > 1) { pw.println("import " + GenClass6.class.getCanonicalName() + ";"); StringBuilder sb = new StringBuilder(); sb.append("@GenClass6("); if (pkg.length() > 0) { sb.append("pkg = \""); sb.append(pkg); sb.append("\", "); } sb.append("name = \""); sb.append(name); sb.append("Gen\""); if (method.length() > 0) { sb.append(", method = \""); sb.append(method); sb.append("\""); } if (--rounds > 1) { sb.append(", rounds = "); sb.append(rounds); } if (summary) { sb.append(", summary = true"); } sb.append(")"); pw.println(sb.toString()); } pw.println("public class " + name + "{"); if (method != null && method.length() > 0) { pw.println("\tpublic String " + method + "() { return null; }"); } pw.println("}"); pw.close(); } /** * Generate the summary.txt file if requested */ protected void summarize() { PrintWriter pw = null; try { Element[] parents = new Element[_classesToSummarize.size()]; parents = _classesToSummarize.values().toArray(parents); FileObject summaryFile = _filer.createResource(StandardLocation.SOURCE_OUTPUT, "", "summary.txt", parents); pw = new PrintWriter(summaryFile.openWriter()); for (String clazz : _classesToSummarize.keySet()) { pw.println(clazz); } pw.flush(); } catch (IOException e) { _messager.printMessage(Diagnostic.Kind.ERROR, "Unable to create summary.txt: " + e.getLocalizedMessage()); } finally { if (pw != null) { pw.close(); } } } }