[configuration] Added @PrintConfiguration to print the combined interpreted configuration for a certain java file, improved problem reporting

This commit is contained in:
Roel Spilker committed 2014-01-17 21:13:37 +01:00
1 parent 610f250c1d
commit fee535eae9
9 files changed
+270 -27

No files matched your search

+49 -2
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2013 The Project Lombok Authors.
* Copyright (C) 2013-2014 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
@@ -21,7 +21,12 @@
*/
package lombok.core;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.List;
import lombok.core.configuration.BubblingConfigurationResolver;
import lombok.core.configuration.ConfigurationErrorReporter;
import lombok.core.configuration.ConfigurationErrorReporterFactory;
import lombok.core.configuration.ConfigurationKey;
import lombok.core.configuration.FileSystemSourceCache;
@@ -35,6 +40,48 @@ public class LombokConfiguration {
}
static <T> T read(ConfigurationKey<T> key, AST<?, ?, ?> ast) {
return new BubblingConfigurationResolver(cache.sourcesForJavaFile(ast.getAbsoluteFileLocation(), ConfigurationErrorReporterFactory.CONSOLE)).resolve(key);
return createResolver(ast, ConfigurationErrorReporterFactory.CONSOLE, cache).resolve(key);
}
public static void writeConfiguration(AST<?, ?, ?> ast, PrintStream stream) {
final List<String> problems = new ArrayList<String>();
ConfigurationErrorReporterFactory reporterFactory = new ConfigurationErrorReporterFactory() {
@Override public ConfigurationErrorReporter createFor(final String description) {
return new ConfigurationErrorReporter() {
@Override
public void report(String error, int lineNumber, String line) {
problems.add(String.format("%s (%s:%d)", error, description, lineNumber));
}
};
}
};
stream.printf("Combined lombok configuration for '%s'\n\n", ast.getAbsoluteFileLocation());
// create a new empty 'cache' to make sure all problems are reported
FileSystemSourceCache sourceCache = new FileSystemSourceCache();
BubblingConfigurationResolver resolver = createResolver(ast, reporterFactory, sourceCache);
for (ConfigurationKey<?> key : ConfigurationKey.registeredKeys()) {
Object value = resolver.resolve(key);
if (value == null || value instanceof List<?> && ((List<?>)value).isEmpty()) continue;
stream.printf("%s: %s\n", key.getKeyName(), value);
}
if (!problems.isEmpty()) {
stream.println();
stream.printf("Problems encountered during parsing: %d\n", problems.size());
int i = 1;
for (String problem : problems) {
stream.printf("%4d - %s\n", i, problem);
i++;
}
}
}
private static BubblingConfigurationResolver createResolver(AST<?, ?, ?> ast, ConfigurationErrorReporterFactory reporterFactory, FileSystemSourceCache sourceCache) {
return new BubblingConfigurationResolver(sourceCache.sourcesForJavaFile(ast.getAbsoluteFileLocation(), reporterFactory));
}
public static void main(String[] args) {
System.out.println(" \n \n ".trim().length());
}
}
@@ -0,0 +1,40 @@
/*
* Copyright (C) 2014 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.core;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Will print the combined interpreted configuration from 'lombok.config' files.
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.SOURCE)
public @interface PrintConfiguration {
/**
* Normally, the configuration is printed to standard out, but you can pick a filename instead. Useful for many IDEs
* which don't have a console unless you start them from the command line.
*/
String outfile() default "";
}
@@ -22,11 +22,5 @@
package lombok.core.configuration;
public interface ConfigurationErrorReporter {
ConfigurationErrorReporter CONSOLE = new ConfigurationErrorReporter() {
@Override public void report(String error) {
System.err.println(error);
}
};
void report(String error);
void report(String error, int lineNumber, String line);
}
@@ -27,8 +27,8 @@ public interface ConfigurationErrorReporterFactory {
public ConfigurationErrorReporter createFor(final String description) {
return new ConfigurationErrorReporter() {
@Override
public void report(String error) {
System.err.printf("Error in %s: %s\n", description, error);
public void report(String error, int lineNumber, String line) {
System.err.printf("%s (%s:%d)", error, description, lineNumber);
}
};
}
@@ -22,7 +22,9 @@
package lombok.core.configuration;
import java.util.Collections;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.TreeMap;
/**
@@ -48,7 +50,12 @@ public abstract class ConfigurationKey<T> {
registerKey(keyName, type);
}
private ConfigurationKey(String keyName, ConfigurationDataType type) {
this.keyName = keyName;
this.type = type;
}
public final String getKeyName() {
return keyName;
}
@@ -87,13 +94,41 @@ public abstract class ConfigurationKey<T> {
* Returns a copy of the currently registered keys.
*/
@SuppressWarnings("unchecked")
public static Map<String, ConfigurationDataType> registeredKeys() {
public static Map<String, ConfigurationDataType> registeredKeysAsMap() {
synchronized (registeredKeys) {
if (copy == null) copy = Collections.unmodifiableMap((Map<String, ConfigurationDataType>) registeredKeys.clone());
return copy;
}
}
public static Iterable<ConfigurationKey<?>> registeredKeys() {
class LocalConfigurationKey extends ConfigurationKey<Object> {
public LocalConfigurationKey(Entry<String, ConfigurationDataType> entry) {
super(entry.getKey(), entry.getValue());
}
}
final Map<String, ConfigurationDataType> map = registeredKeysAsMap();
return new Iterable<ConfigurationKey<?>>() {
@Override public Iterator<ConfigurationKey<?>> iterator() {
final Iterator<Entry<String, ConfigurationDataType>> entries = map.entrySet().iterator();
return new Iterator<ConfigurationKey<?>>() {
@Override
public boolean hasNext() {
return entries.hasNext();
}
@Override public ConfigurationKey<?> next() {
return new LocalConfigurationKey(entries.next());
}
@Override public void remove() {
throw new UnsupportedOperationException();
}
};
}
};
}
private static void registerKey(String keyName, ConfigurationDataType type) {
synchronized (registeredKeys) {
ConfigurationDataType existingType = registeredKeys.get(keyName);
@@ -114,7 +114,7 @@ public class FileSystemSourceCache {
try {
return StringConfigurationSource.forString(fileToString(configFile), reporter);
} catch (Exception e) {
reporter.report("Exception while reading file: " + e.getMessage());
reporter.report("Exception while reading file: " + e.getMessage(), 0, null);
return null;
}
}
@@ -36,17 +36,16 @@ public class StringConfigurationSource implements ConfigurationSource {
private final Map<String, Result<?>> values;
public static ConfigurationSource forString(String content) {
return forString(content, ConfigurationErrorReporter.CONSOLE);
}
public static ConfigurationSource forString(String content, ConfigurationErrorReporter reporter) {
if (reporter == null) throw new NullPointerException("reporter");
Map<String, Result<?>> values = new TreeMap<String, Result<?>>(String.CASE_INSENSITIVE_ORDER);
Map<String, ConfigurationDataType> registeredKeys = ConfigurationKey.registeredKeys();
for (String line : content.trim().split("\\s*\\n\\s*")) {
Map<String, ConfigurationDataType> registeredKeys = ConfigurationKey.registeredKeysAsMap();
int lineNumber = 0;
for (String line : content.split("\\n")) {
line = line.trim();
lineNumber++;
if (line.isEmpty() || line.startsWith("#")) continue;
Matcher matcher = LINE.matcher(line);
@@ -66,19 +65,19 @@ public class StringConfigurationSource implements ConfigurationSource {
}
ConfigurationDataType type = registeredKeys.get(keyName);
if (type == null) {
reporter.report("Unknown key '" + keyName + "' on line: " + line);
reporter.report("Unknown key '" + keyName + "'", lineNumber, line);
} else {
boolean listOperator = operator.equals("+=") || operator.equals("-=");
if (listOperator && !type.isList()) {
reporter.report("'" + keyName + "' is not a list and doesn't support " + operator + " (only = and clear): " + line);
reporter.report("'" + keyName + "' is not a list and doesn't support " + operator + " (only = and clear)", lineNumber, line);
} else if (operator.equals("=") && type.isList()) {
reporter.report("'" + keyName + "' is a list and cannot be assigned to (use +=, -= and clear instead): " + line);
reporter.report("'" + keyName + "' is a list and cannot be assigned to (use +=, -= and clear instead)", lineNumber, line);
} else {
processResult(values, keyName, operator, value, type, reporter);
processResult(values, keyName, operator, value, type, reporter, lineNumber, line);
}
}
} else {
reporter.report("No valid line: " + line);
reporter.report("No valid line", lineNumber, line);
}
}
@@ -97,12 +96,12 @@ public class StringConfigurationSource implements ConfigurationSource {
}
}
private static void processResult(Map<String, Result<?>> values, String keyName, String operator, String value, ConfigurationDataType type, ConfigurationErrorReporter reporter) {
private static void processResult(Map<String, Result<?>> values, String keyName, String operator, String value, ConfigurationDataType type, ConfigurationErrorReporter reporter, int lineNumber, String line) {
Object element = null;
if (value != null) try {
element = type.getParser().parse(value);
} catch (Exception e) {
reporter.report("Error while parsing the value for '" + keyName + "' value '" + value + "' (should be a " + type.getParser().description() + ")");
reporter.report("Error while parsing the value for '" + keyName + "' value '" + value + "' (should be a " + type.getParser().description() + ")", lineNumber, line);
return;
}
@@ -0,0 +1,63 @@
/*
* Copyright (C) 2014 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.eclipse.handlers;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.PrintStream;
import lombok.Lombok;
import lombok.core.AnnotationValues;
import lombok.core.LombokConfiguration;
import lombok.core.PrintConfiguration;
import lombok.eclipse.EclipseAnnotationHandler;
import lombok.eclipse.EclipseNode;
import org.eclipse.jdt.internal.compiler.ast.Annotation;
import org.mangosdk.spi.ProviderFor;
/**
* Handles the {@code lombok.core.PrintConfiguration} annotation for eclipse.
*/
@ProviderFor(EclipseAnnotationHandler.class)
public class HandlePrintConfiguration extends EclipseAnnotationHandler<PrintConfiguration> {
public void handle(AnnotationValues<PrintConfiguration> annotation, Annotation ast, EclipseNode annotationNode) {
PrintStream stream = System.out;
String fileName = annotation.getInstance().outfile();
if (fileName.length() > 0) try {
stream = new PrintStream(new File(fileName));
} catch (FileNotFoundException e) {
Lombok.sneakyThrow(e);
}
try {
LombokConfiguration.writeConfiguration(annotationNode.getAst(), stream);
} finally {
if (stream != System.out) {
try {
stream.close();
} catch (Exception e) {
Lombok.sneakyThrow(e);
}
}
}
}
}
@@ -0,0 +1,65 @@
/*
* Copyright (C) 2014 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.handlers;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.PrintStream;
import lombok.Lombok;
import lombok.core.AnnotationValues;
import lombok.core.LombokConfiguration;
import lombok.core.PrintConfiguration;
import lombok.javac.JavacAnnotationHandler;
import lombok.javac.JavacNode;
import org.mangosdk.spi.ProviderFor;
import com.sun.tools.javac.tree.JCTree.JCAnnotation;
/**
* Handles the {@code lombok.core.PrintConfiguration} annotation for javac.
*/
@ProviderFor(JavacAnnotationHandler.class)
public class HandlePrintConfiguration extends JavacAnnotationHandler<PrintConfiguration> {
@Override public void handle(AnnotationValues<PrintConfiguration> annotation, JCAnnotation ast, JavacNode annotationNode) {
PrintStream stream = System.out;
String fileName = annotation.getInstance().outfile();
if (fileName.length() > 0) try {
stream = new PrintStream(new File(fileName));
} catch (FileNotFoundException e) {
Lombok.sneakyThrow(e);
}
try {
LombokConfiguration.writeConfiguration(annotationNode.getAst(), stream);
} finally {
if (stream != System.out) {
try {
stream.close();
} catch (Exception e) {
Lombok.sneakyThrow(e);
}
}
}
}
}