
br.com.objectos.way.code.AbstractAnnotationProcessor Maven / Gradle / Ivy
The newest version!
/*
* Copyright 2014 Objectos, Fábrica de Software LTDA.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package br.com.objectos.way.code;
import static com.google.common.collect.Lists.newArrayList;
import java.io.File;
import java.lang.annotation.Annotation;
import java.net.URL;
import java.security.CodeSource;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.RoundEnvironment;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.util.ElementFilter;
import javax.tools.Diagnostic;
import javax.tools.JavaCompiler;
import javax.tools.ToolProvider;
import br.com.objectos.way.core.io.Directory;
import br.com.objectos.way.core.util.IterableAction;
import br.com.objectos.way.core.util.WayIterables;
import com.google.common.base.Function;
import com.google.common.base.Joiner;
import com.google.common.base.Throwables;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
/**
* @author [email protected] (Marcio Endo)
*/
public abstract class AbstractAnnotationProcessor extends AbstractProcessor {
private Directory classOutput;
private Directory sourcePath;
private String compilerJarPath;
@Override
public Set getSupportedAnnotationTypes() {
Class extends Annotation> type = annotationType();
return ImmutableSet.of(type.getName());
}
@Override
public SourceVersion getSupportedSourceVersion() {
return SourceVersion.latestSupported();
}
@Override
public synchronized void init(ProcessingEnvironment processingEnv) {
super.init(processingEnv);
Map optionMap = processingEnv.getOptions();
String classOutput = optionMap.get("classOutput");
if (classOutput != null) {
this.classOutput = Directory.at(classOutput);
}
String sourcePath = optionMap.get("sourcePath");
if (sourcePath != null) {
this.sourcePath = Directory.at(sourcePath);
}
CodeSource codeSource = getClass().getProtectionDomain().getCodeSource();
URL jar = codeSource.getLocation();
compilerJarPath = jar.getPath();
}
@Override
public boolean process(Set extends TypeElement> typeElements, RoundEnvironment roundEnv) {
try {
processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, "Starting");
Set extends Element> elementSet;
elementSet = roundEnv.getElementsAnnotatedWith(annotationType());
if (shouldProcessMethods()) {
WayIterables.from(ElementFilter.methodsIn(elementSet))
.transformAndConcat(new ExecutableElementToArtifactList())
.execute(new CodeCanvasArtifactAction());
}
if (shouldProcessTypes()) {
WayIterables.from(ElementFilter.typesIn(elementSet))
.transformAndConcat(new TypeElementToArtifactList())
.execute(new CodeCanvasArtifactAction());
}
return processReturnOnSuccess(typeElements, roundEnv);
} catch (Throwable e) {
String stackTrace = Throwables.getStackTraceAsString(e);
String msg = Joiner.on("\n").join(e, stackTrace);
processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, name() + " processor threw an exception: " + msg);
return processReturnOnError(typeElements, roundEnv, e);
}
}
protected abstract Class extends Annotation> annotationType();
protected abstract boolean shouldProcessMethods();
protected abstract boolean shouldProcessTypes();
protected List toArtifactList(TypeInfo typeInfo) {
return ImmutableList.of();
}
protected List toArtifactList(TypeInfo typeInfo, MethodInfo methodInfo) {
return toArtifactList(typeInfo);
}
protected void beforeWrite(CodeCanvasArtifact artifact) {
}
protected Object compileAndInstantiate(SimpleTypeInfo typeInfo)
throws
ClassNotFoundException {
List options = newArrayList();
File sourceFile = typeInfo.fileAt(sourcePath);
options.add(sourceFile.getPath());
options.add("-d");
options.add(classOutput.getAbsolutePath());
options.add("-classpath");
options.add(compilerJarPath);
options.add("-proc:none");
JavaCompiler javac = ToolProvider.getSystemJavaCompiler();
javac.run(null, System.out, System.err, options.toArray(new String[] {}));
return typeInfo.newInstance();
}
protected void info(String msg) {
processingEnv.getMessager().printMessage(Diagnostic.Kind.WARNING, msg);
}
protected String name() {
return getClass().getSimpleName();
}
protected boolean processReturnOnError(Set extends TypeElement> typeElements, RoundEnvironment roundEnv, Throwable e) {
return false;
}
protected boolean processReturnOnSuccess(Set extends TypeElement> typeElements, RoundEnvironment roundEnv) {
return false;
}
private void reportError(String msg, Element e) {
processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, msg, e);
}
private class ExecutableElementToArtifactList extends ElementToArtifactList {
@Override
List applyTo(ExecutableElement element) {
List res = ImmutableList.of();
Element enclosingElement = element.getEnclosingElement();
if (Apt.isType(enclosingElement)) {
TypeInfo typeInfo = TypeInfoTypeElement.wrap(processingEnvironmentWrapper, (TypeElement) enclosingElement);
TypeParameterInfoMap typeParameterInfoMap = typeInfo.typeParameterInfoMap();
MethodInfo methodInfo;
methodInfo = MethodInfoExecutableElement.wrap(processingEnvironmentWrapper, element, typeParameterInfoMap);
res = toArtifactList(typeInfo, methodInfo);
}
return res;
}
}
private class TypeElementToArtifactList extends ElementToArtifactList {
@Override
List applyTo(TypeElement element) {
TypeInfo typeInfo = TypeInfoTypeElement.wrap(processingEnvironmentWrapper, element);
return toArtifactList(typeInfo);
}
}
private abstract class ElementToArtifactList implements Function> {
final ProcessingEnvironmentWrapper processingEnvironmentWrapper = ProcessingEnvironmentWrapper
.wrapperOf(processingEnv);
@Override
public final List apply(E element) {
try {
return applyTo(element);
} catch (Throwable e) {
String stackTrace = Throwables.getStackTraceAsString(e);
String msg = Joiner.on("\n").join(e, stackTrace);
reportError(name() + " processor threw an exception: " + msg, element);
return ImmutableList.of();
}
}
abstract List applyTo(E element);
}
protected class CodeCanvasArtifactAction implements IterableAction {
public CodeCanvasArtifactAction() {
}
@Override
public void execute(Iterable extends CodeCanvasArtifact> list) {
for (CodeCanvasArtifact artifact : list) {
beforeWrite(artifact);
artifact.write(processingEnv);
}
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy