blob: 0b6f5f2f0ebca7d3cf236a394342876fc7859512 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2007 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();
}
}
}
}