lombok.javac.apt.Processor Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of lombok Show documentation
Show all versions of lombok Show documentation
Spice up your java: Automatic Resource Management, automatic generation of getters, setters, equals, hashCode and toString, and more!
/*
* Copyright (C) 2015 The Project Lombok Authors.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package lombok.javac.apt;
import static javax.tools.StandardLocation.*;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.StringWriter;
import java.lang.reflect.Field;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.Filer;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.TypeElement;
import javax.tools.Diagnostic;
import javax.tools.JavaFileManager;
import com.sun.tools.javac.processing.JavacFiler;
import com.sun.tools.javac.processing.JavacProcessingEnvironment;
import com.sun.tools.javac.util.Options;
import lombok.permit.Permit;
/**
* This processor should not be used. It used to be THE processor. This class is only there to warn people that something went wrong, and for the
* lombok developers to see if what the reason for those failures is.
*/
@Deprecated
@SupportedAnnotationTypes("*")
public class Processor extends AbstractProcessor {
/** {@inheritDoc} */
@Override public void init(ProcessingEnvironment procEnv) {
super.init(procEnv);
if (System.getProperty("lombok.disable") != null) {
return;
}
procEnv.getMessager().printMessage(Diagnostic.Kind.WARNING, "Wrong usage of 'lombok.javac.apt.Processor'. " + report(procEnv));
}
private String report(ProcessingEnvironment procEnv) {
String data = collectData(procEnv);
try {
return writeFile(data);
} catch (Exception e) {
return "Report:\n\n" + data;
}
}
private String writeFile(String data) throws IOException {
File file = File.createTempFile("lombok-processor-report-", ".txt");
OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(file));
writer.write(data);
writer.close();
return "Report written to '" + file.getCanonicalPath() + "'\n";
}
private String collectData(ProcessingEnvironment procEnv) {
StringBuilder message = new StringBuilder();
message.append("Problem report for usages of 'lombok.javac.apt.Processor'\n\n");
listOptions(message, procEnv);
findServices(message, procEnv.getFiler());
addStacktrace(message);
listProperties(message);
return message.toString();
}
private void listOptions(StringBuilder message, ProcessingEnvironment procEnv) {
try {
JavacProcessingEnvironment environment = (JavacProcessingEnvironment) procEnv;
Options instance = Options.instance(environment.getContext());
Field field = Permit.getField(Options.class, "values");
@SuppressWarnings("unchecked") Map values = (Map) field.get(instance);
if (values.isEmpty()) {
message.append("Options: empty\n\n");
return;
}
message.append("Compiler Options:\n");
for (Map.Entry value : values.entrySet()) {
message.append("- ");
string(message, value.getKey());
message.append(" = ");
string(message, value.getValue());
message.append("\n");
}
message.append("\n");
} catch (Exception e) {
message.append("No options available\n\n");
}
}
private void findServices(StringBuilder message, Filer filer) {
try {
Field filerFileManagerField = Permit.getField(JavacFiler.class, "fileManager");
JavaFileManager jfm = (JavaFileManager) filerFileManagerField.get(filer);
ClassLoader processorClassLoader = jfm.hasLocation(ANNOTATION_PROCESSOR_PATH) ? jfm.getClassLoader(ANNOTATION_PROCESSOR_PATH) : jfm.getClassLoader(CLASS_PATH);
Enumeration resources = processorClassLoader.getResources("META-INF/services/javax.annotation.processing.Processor");
if (!resources.hasMoreElements()) {
message.append("No processors discovered\n\n");
return;
}
message.append("Discovered processors:\n");
while (resources.hasMoreElements()) {
URL processorUrl = resources.nextElement();
message.append("- '").append(processorUrl).append("'");
InputStream content = (InputStream) processorUrl.getContent();
if (content != null) try {
InputStreamReader reader = new InputStreamReader(content, "UTF-8");
StringWriter sw = new StringWriter();
char[] buffer = new char[8192];
int read = 0;
while ((read = reader.read(buffer))!= -1) {
sw.write(buffer, 0, read);
}
String wholeFile = sw.toString();
if (wholeFile.contains("lombok.javac.apt.Processor")) {
message.append(" <= problem\n");
} else {
message.append(" (ok)\n");
}
message.append(" ").append(wholeFile.replace("\n", "\n ")).append("\n");
} finally {
content.close();
}
}
} catch (Exception e) {
message.append("Filer information unavailable\n");
}
message.append("\n");
}
private void addStacktrace(StringBuilder message) {
StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace();
if (stackTraceElements != null) {
message.append("Called from\n");
for (int i = 1; i < stackTraceElements.length; i++) {
StackTraceElement element = stackTraceElements[i];
if (!element.getClassName().equals("lombok.javac.apt.Processor")) message.append("- ").append(element).append("\n");
}
} else {
message.append("No stacktrace available\n");
}
message.append("\n");
}
private void listProperties(StringBuilder message) {
Properties properties = System.getProperties();
ArrayList propertyNames = new ArrayList(properties.stringPropertyNames());
Collections.sort(propertyNames);
message.append("Properties: \n");
for (String propertyName : propertyNames) {
if (propertyName.startsWith("user.")) continue;
message.append("- ").append(propertyName).append(" = ");
string(message, System.getProperty(propertyName));
message.append("\n");
}
message.append("\n");
}
private static void string(StringBuilder sb, String s) {
if (s == null) {
sb.append("null");
return;
}
sb.append("\"");
for (int i = 0; i < s.length(); i++) sb.append(escape(s.charAt(i)));
sb.append("\"");
}
private static String escape(char ch) {
switch (ch) {
case '\b': return "\\b";
case '\f': return "\\f";
case '\n': return "\\n";
case '\r': return "\\r";
case '\t': return "\\t";
case '\'': return "\\'";
case '\"': return "\\\"";
case '\\': return "\\\\";
default:
if (ch < 32) return String.format("\\%03o", (int) ch);
return String.valueOf(ch);
}
}
/**
* We just return the latest version of whatever JDK we run on. Stupid? Yeah, but it's either that or warnings on all versions but 1.
*/
@Override public SourceVersion getSupportedSourceVersion() {
return SourceVersion.latest();
}
@Override public boolean process(Set extends TypeElement> annotations, RoundEnvironment roundEnv) {
return false;
}
}