diff options
Diffstat (limited to 'src')
65 files changed, 1099 insertions, 732 deletions
diff --git a/src/core/lombok/ConfigurationKeys.java b/src/core/lombok/ConfigurationKeys.java index 73caf295..ff17ca09 100644 --- a/src/core/lombok/ConfigurationKeys.java +++ b/src/core/lombok/ConfigurationKeys.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013-2014 The Project Lombok Authors. + * Copyright (C) 2013-2017 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 @@ -41,11 +41,32 @@ public class ConfigurationKeys { /** * lombok configuration: {@code lombok.addGeneratedAnnotation} = {@code true} | {@code false}. * - * If unset or {@code true}, lombok generates {@code @javax.annotation.Generated("lombok")} on all fields, methods, and types that are generated. + * If unset or {@code true}, lombok generates various annotations to mark generated code like {@code @javax.annotation.Generated("lombok")} and {@code @lombok.Generated}. + * + * @see ConfigurationKeys#ADD_JAVAX_GENERATED_ANNOTATIONS + * @see ConfigurationKeys#ADD_LOMBOK_GENERATED_ANNOTATIONS */ public static final ConfigurationKey<Boolean> ADD_GENERATED_ANNOTATIONS = new ConfigurationKey<Boolean>("lombok.addGeneratedAnnotation", "Generate @javax.annotation.Generated on all generated code (default: true).") {}; /** + * lombok configuration: {@code lombok.addJavaxGeneratedAnnotation} = {@code true} | {@code false}. + * + * If unset or {@code true}, lombok generates {@code @javax.annotation.Generated("lombok")} on all fields, methods, and types that are generated, unless {@code lombok.addGeneratedAnnotation} is set to {@code false}. + * + * @see ConfigurationKeys#ADD_GENERATED_ANNOTATIONS + */ + public static final ConfigurationKey<Boolean> ADD_JAVAX_GENERATED_ANNOTATIONS = new ConfigurationKey<Boolean>("lombok.addJavaxGeneratedAnnotation", "Generate @javax.annotation.Generated on all generated code (default: follow lombok.addGeneratedAnnotation).") {}; + + /** + * lombok configuration: {@code lombok.addLombokGeneratedAnnotation} = {@code true} | {@code false}. + * + * If unset or {@code true}, lombok generates {@code @lombok.Generated} on all fields, methods, and types that are generated, unless {@code lombok.addGeneratedAnnotation} is set to {@code false}. + * + * @see ConfigurationKeys#ADD_GENERATED_ANNOTATIONS + */ + public static final ConfigurationKey<Boolean> ADD_LOMBOK_GENERATED_ANNOTATIONS = new ConfigurationKey<Boolean>("lombok.addLombokGeneratedAnnotation", "Generate @lombok.Generated on all generated code (default: follow lombok.addGeneratedAnnotation).") {}; + + /** * lombok configuration: {@code lombok.extern.findbugs.addSuppressFBWarnings} = {@code true} | {@code false}. * * If {@code true}, lombok generates {@code edu.umd.cs.findbugs.annotations.SuppressFBWarnings} on all fields, methods, and types that are generated. @@ -283,7 +304,8 @@ public class ConfigurationKeys { * If set, <em>any</em> usage of {@code val} results in a warning / error. */ public static final ConfigurationKey<FlagUsageType> VAL_FLAG_USAGE = new ConfigurationKey<FlagUsageType>("lombok.val.flagUsage", "Emit a warning or error if 'val' is used.") {}; - + public static final ConfigurationKey<FlagUsageType> VAR_FLAG_USAGE = new ConfigurationKey<FlagUsageType>("lombok.var.flagUsage", "Emit a warning or error if 'var' is used.") {}; + // ##### Extern ##### // ----- Logging ----- @@ -337,6 +359,13 @@ public class ConfigurationKeys { public static final ConfigurationKey<FlagUsageType> LOG_XSLF4J_FLAG_USAGE = new ConfigurationKey<FlagUsageType>("lombok.log.xslf4j.flagUsage", "Emit a warning or error if @XSlf4j is used.") {}; /** + * lombok configuration: {@code lombok.log.jbosslog.flagUsage} = {@code WARNING} | {@code ERROR}. + * + * If set, <em>any</em> usage of {@code @JBossLog} results in a warning / error. + */ + public static final ConfigurationKey<FlagUsageType> LOG_JBOSSLOG_FLAG_USAGE = new ConfigurationKey<FlagUsageType>("lombok.log.jbosslog.flagUsage", "Emit a warning or error if @JBossLog is used.") {}; + + /** * lombok configuration: {@code lombok.log.fieldName} = <String: aJavaIdentifier> (Default: {@code log}). * * If set the various log annotations (which make a log field) will use the stated identifier instead of {@code log} as a name. diff --git a/src/core/lombok/Generated.java b/src/core/lombok/Generated.java index 18411b3d..b99a1b58 100644 --- a/src/core/lombok/Generated.java +++ b/src/core/lombok/Generated.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015 The Project Lombok Authors. + * Copyright (C) 2015-2016 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 @@ -27,7 +27,7 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** - * Lombok will eventually automatically add this annotation to all generated methods, fields, and classes. + * Lombok will eventually automatically add this annotation to all generated constructors, methods, fields, and types. * * You can mark the presence of this annotation as 'ignore it' for all code style and bug finding tools. * <p> @@ -35,7 +35,7 @@ import java.lang.annotation.Target; * it up so that lombok jars in widespread use start having this, which will make it easier to actually apply it * later on. */ -@Target({ElementType.FIELD, ElementType.METHOD, ElementType.TYPE}) +@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.FIELD, ElementType.TYPE}) @Retention(RetentionPolicy.CLASS) public @interface Generated { } diff --git a/src/core/lombok/Lombok.java b/src/core/lombok/Lombok.java index 07fd083d..164c47a8 100644 --- a/src/core/lombok/Lombok.java +++ b/src/core/lombok/Lombok.java @@ -71,4 +71,16 @@ public class Lombok { public static <T> T preventNullAnalysis(T value) { return value; } + + /** + * Ensures that the {@code value} is not {@code null}. + * @param value the value to test for null + * @param message the message of the {@link NullPointerException} + * @return the value if it is not null + * @throws NullPointerException with the {@code message} if the value is null + */ + public static <T> T checkNotNull(T value, String message) { + if (value == null) throw new NullPointerException(message); + return value; + } } diff --git a/src/core/lombok/Value.java b/src/core/lombok/Value.java index 2cecea63..39154226 100644 --- a/src/core/lombok/Value.java +++ b/src/core/lombok/Value.java @@ -31,7 +31,7 @@ import java.lang.annotation.Target; * <p> * Equivalent to {@code @Getter @FieldDefaults(makeFinal=true, level=AccessLevel.PRIVATE) @AllArgsConstructor @ToString @EqualsAndHashCode}. * <p> - * Complete documentation is found at <a href="https://projectlombok.org/features/experimental/Value.html">the project lombok features page for @Value</a>. + * Complete documentation is found at <a href="https://projectlombok.org/features/Value.html">the project lombok features page for @Value</a>. * * @see lombok.Getter * @see lombok.experimental.FieldDefaults @@ -49,7 +49,7 @@ public @interface Value { * We suggest the name: "of", like so: * * <pre> - * public @Data(staticConstructor = "of") class Point { final int x, y; } + * public @Value(staticConstructor = "of") class Point { final int x, y; } * </pre> * * Default: No static constructor, instead the normal constructor is public. diff --git a/src/core/lombok/core/AST.java b/src/core/lombok/core/AST.java index e6efe058..1142018f 100644 --- a/src/core/lombok/core/AST.java +++ b/src/core/lombok/core/AST.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2013 The Project Lombok Authors. + * Copyright (C) 2009-2016 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,7 @@ */ package lombok.core; -import static lombok.Lombok.*; +import static lombok.Lombok.sneakyThrow; import java.lang.reflect.Array; import java.lang.reflect.Field; @@ -31,10 +31,11 @@ import java.lang.reflect.Type; import java.net.URI; import java.util.ArrayList; import java.util.Collection; -import java.util.HashMap; import java.util.IdentityHashMap; import java.util.List; import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; import lombok.core.configuration.ConfigurationKey; import lombok.core.debug.HistogramTracker; @@ -61,12 +62,18 @@ public abstract class AST<A extends AST<A, L, N>, L extends LombokNode<A, L, N>, Map<N, N> identityDetector = new IdentityHashMap<N, N>(); private Map<N, L> nodeMap = new IdentityHashMap<N, L>(); private boolean changed = false; + + // The supertypes which are considered AST Node children. Usually, the Statement, and the Expression, + // though some platforms (such as Eclipse) group these under one common supertype. + private final Collection<Class<? extends N>> statementTypes; + private static final HistogramTracker configTracker = System.getProperty("lombok.timeConfig") == null ? null : new HistogramTracker("lombok.config"); - protected AST(String fileName, String packageDeclaration, ImportList imports) { + protected AST(String fileName, String packageDeclaration, ImportList imports, Collection<Class<? extends N>> statementTypes) { this.fileName = fileName == null ? "(unknown).java" : fileName; this.packageDeclaration = packageDeclaration; this.imports = imports; + this.statementTypes = statementTypes; } /** @@ -209,11 +216,11 @@ public abstract class AST<A extends AST<A, L, N>, L extends LombokNode<A, L, N>, } } - private static Map<Class<?>, Collection<FieldAccess>> fieldsOfASTClasses = new HashMap<Class<?>, Collection<FieldAccess>>(); + private static final ConcurrentMap<Class<?>, Collection<FieldAccess>> fieldsOfASTClasses = new ConcurrentHashMap<Class<?>, Collection<FieldAccess>>(); /** Returns FieldAccess objects for the stated class. Each field that contains objects of the kind returned by * {@link #getStatementTypes()}, either directly or inside of an array or java.util.collection (or array-of-arrays, - * or collection-of-collections, etcetera), is returned. + * or collection-of-collections, et cetera), is returned. */ protected Collection<FieldAccess> fieldsOf(Class<?> c) { Collection<FieldAccess> fields = fieldsOfASTClasses.get(c); @@ -221,8 +228,8 @@ public abstract class AST<A extends AST<A, L, N>, L extends LombokNode<A, L, N>, fields = new ArrayList<FieldAccess>(); getFields(c, fields); - fieldsOfASTClasses.put(c, fields); - return fields; + fieldsOfASTClasses.putIfAbsent(c, fields); + return fieldsOfASTClasses.get(c); } private void getFields(Class<?> c, Collection<FieldAccess> fields) { @@ -261,13 +268,8 @@ public abstract class AST<A extends AST<A, L, N>, L extends LombokNode<A, L, N>, return Object.class; } - /** - * The supertypes which are considered AST Node children. Usually, the Statement, and the Expression, - * though some platforms (such as Eclipse) group these under one common supertype. */ - protected abstract Collection<Class<? extends N>> getStatementTypes(); - - protected boolean shouldDrill(Class<?> parentType, Class<?> childType, String fieldName) { - for (Class<?> statementType : getStatementTypes()) { + private boolean shouldDrill(Class<?> parentType, Class<?> childType, String fieldName) { + for (Class<?> statementType : statementTypes) { if (statementType.isAssignableFrom(childType)) return true; } diff --git a/src/core/lombok/core/AnnotationProcessor.java b/src/core/lombok/core/AnnotationProcessor.java index ba5fd4f7..5531ad8e 100644 --- a/src/core/lombok/core/AnnotationProcessor.java +++ b/src/core/lombok/core/AnnotationProcessor.java @@ -103,7 +103,6 @@ public class AnnotationProcessor extends AbstractProcessor { URL selfUrl = new File(ClassRootFinder.findClassRootOfClass(AnnotationProcessor.class)).toURI().toURL(); m.invoke(environmentClassLoader, selfUrl); } - return environmentClassLoader; } ClassLoader ourClassLoader = JavacDescriptor.class.getClassLoader(); diff --git a/src/core/lombok/core/Version.java b/src/core/lombok/core/Version.java index 549db9e1..4fdb7216 100644 --- a/src/core/lombok/core/Version.java +++ b/src/core/lombok/core/Version.java @@ -30,9 +30,9 @@ public class Version { // ** CAREFUL ** - this class must always compile with 0 dependencies (it must not refer to any other sources or libraries). // Note: In 'X.Y.Z', if Z is odd, its a snapshot build built from the repository, so many different 0.10.3 versions can exist, for example. // Official builds always end in an even number. (Since 0.10.2). - private static final String VERSION = "1.16.8"; -// private static final String RELEASE_NAME = "Edgy Guinea Pig"; - private static final String RELEASE_NAME = "Candid Duck"; + private static final String VERSION = "1.16.13"; + private static final String RELEASE_NAME = "Edgy Guinea Pig"; +// private static final String RELEASE_NAME = "Candid Duck"; private Version() { //Prevent instantiation diff --git a/src/core/lombok/core/configuration/AllowHelper.java b/src/core/lombok/core/configuration/AllowHelper.java new file mode 100644 index 00000000..3873b055 --- /dev/null +++ b/src/core/lombok/core/configuration/AllowHelper.java @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2016 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.configuration; + +import java.util.Collection; +import java.util.Collections; + +import lombok.ConfigurationKeys; + +public final class AllowHelper { + private final static Collection<? extends ConfigurationKey<?>> ALLOWABLE = Collections.singleton(ConfigurationKeys.VAR_FLAG_USAGE); + + private AllowHelper() { + // Prevent instantiation + } + + public static boolean isAllowable(ConfigurationKey<?> key) { + return ALLOWABLE.contains(key); + } +} diff --git a/src/core/lombok/core/configuration/ConfigurationApp.java b/src/core/lombok/core/configuration/ConfigurationApp.java index e441b4de..efe57e38 100644 --- a/src/core/lombok/core/configuration/ConfigurationApp.java +++ b/src/core/lombok/core/configuration/ConfigurationApp.java @@ -198,7 +198,7 @@ public class ConfigurationApp extends LombokApp { if (paths.size() == 1) { if (!(argsPaths.size() == 1)) out.printf("Configuration for '%s'.%n%n", paths.iterator().next()); } else { - out.printf("Configuration for:%n", paths.iterator().next()); + out.printf("Configuration for:%n"); for (String path : paths) out.printf("- %s%n", path); out.println(); } diff --git a/src/core/lombok/core/configuration/ConfigurationParser.java b/src/core/lombok/core/configuration/ConfigurationParser.java index f0a9e142..e80793c1 100644 --- a/src/core/lombok/core/configuration/ConfigurationParser.java +++ b/src/core/lombok/core/configuration/ConfigurationParser.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014 The Project Lombok Authors. + * Copyright (C) 2014-2016 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 @@ -27,7 +27,7 @@ import java.util.regex.Pattern; public class ConfigurationParser { private static final Pattern LINE = Pattern.compile("(?:clear\\s+([^=]+))|(?:(\\S*?)\\s*([-+]?=)\\s*(.*?))"); - private static final Pattern NEWLINE_FINDER = Pattern.compile("^\\s*(.*?)\\s*$", Pattern.MULTILINE); + private static final Pattern NEWLINE_FINDER = Pattern.compile("^[\t ]*(.*?)[\t\r ]*$", Pattern.MULTILINE); private ConfigurationProblemReporter reporter; diff --git a/src/core/lombok/core/configuration/FlagUsageType.java b/src/core/lombok/core/configuration/FlagUsageType.java index b7053b7c..8717c22b 100644 --- a/src/core/lombok/core/configuration/FlagUsageType.java +++ b/src/core/lombok/core/configuration/FlagUsageType.java @@ -23,5 +23,5 @@ package lombok.core.configuration; /** Used for lombok configuration to flag usages of certain lombok feature. */ public enum FlagUsageType { - WARNING, ERROR; + WARNING, ERROR, ALLOW; } diff --git a/src/core/lombok/core/handlers/HandlerUtil.java b/src/core/lombok/core/handlers/HandlerUtil.java index a9a4be78..a05578d4 100644 --- a/src/core/lombok/core/handlers/HandlerUtil.java +++ b/src/core/lombok/core/handlers/HandlerUtil.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013-2015 The Project Lombok Authors. + * Copyright (C) 2013-2017 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 @@ -43,6 +43,7 @@ import lombok.core.AST; import lombok.core.AnnotationValues; import lombok.core.JavaIdentifiers; import lombok.core.LombokNode; +import lombok.core.configuration.AllowHelper; import lombok.core.configuration.ConfigurationKey; import lombok.core.configuration.FlagUsageType; import lombok.experimental.Accessors; @@ -97,13 +98,23 @@ public class HandlerUtil { public static void handleFlagUsage(LombokNode<?, ?, ?> node, ConfigurationKey<FlagUsageType> key, String featureName) { FlagUsageType fut = node.getAst().readConfiguration(key); + if (fut == null && AllowHelper.isAllowable(key)) { + node.addError("Use of " + featureName + " is disabled by default. Please add '" + key.getKeyName() + " = " + FlagUsageType.ALLOW + "' to 'lombok.config' if you want to enable is."); + } + if (fut != null) { String msg = "Use of " + featureName + " is flagged according to lombok configuration."; if (fut == FlagUsageType.WARNING) node.addWarning(msg); - else node.addError(msg); + else if (fut == FlagUsageType.ERROR) node.addError(msg); } } + public static boolean shouldAddGenerated(LombokNode<?, ?, ?> node, ConfigurationKey<Boolean> key) { + Boolean add = node.getAst().readConfiguration(key); + if (add != null) return add; + return !Boolean.FALSE.equals(node.getAst().readConfiguration(ConfigurationKeys.ADD_GENERATED_ANNOTATIONS)); + } + public static void handleExperimentalFlagUsage(LombokNode<?, ?, ?> node, ConfigurationKey<FlagUsageType> key, String featureName) { handleFlagUsage(node, key, featureName, ConfigurationKeys.EXPERIMENTAL_FLAG_USAGE, "any lombok.experimental feature"); } diff --git a/src/core/lombok/eclipse/EclipseAST.java b/src/core/lombok/eclipse/EclipseAST.java index 6741b33a..dc2c9843 100644 --- a/src/core/lombok/eclipse/EclipseAST.java +++ b/src/core/lombok/eclipse/EclipseAST.java @@ -62,7 +62,7 @@ public class EclipseAST extends AST<EclipseAST, EclipseNode, ASTNode> { * @param ast The compilation unit, which serves as the top level node in the tree to be built. */ public EclipseAST(CompilationUnitDeclaration ast) { - super(toFileName(ast), packageDeclaration(ast), new EclipseImportList(ast)); + super(toFileName(ast), packageDeclaration(ast), new EclipseImportList(ast), statementTypes()); this.compilationUnitDeclaration = ast; setTop(buildCompilationUnit(ast)); this.completeParse = isComplete(ast); @@ -477,9 +477,9 @@ public class EclipseAST extends AST<EclipseAST, EclipseNode, ASTNode> { return putInMap(new EclipseNode(this, statement, childNodes, Kind.STATEMENT)); } - /** For Eclipse, only Statement counts, as Expression is a subclass of it, even though this isn't + /* For Eclipse, only Statement counts, as Expression is a subclass of it, even though this isn't * entirely correct according to the JLS spec (only some expressions can be used as statements, not all of them). */ - @Override protected Collection<Class<? extends ASTNode>> getStatementTypes() { + private static Collection<Class<? extends ASTNode>> statementTypes() { return Collections.<Class<? extends ASTNode>>singleton(Statement.class); } diff --git a/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java b/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java index 0ff5a7f6..f822e095 100644 --- a/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java +++ b/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2015 The Project Lombok Authors. + * Copyright (C) 2009-2017 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 @@ -1168,9 +1168,8 @@ public class EclipseHandlerUtil { if (params < minArgs || params > maxArgs) continue; } - if (def.annotations != null) for (Annotation anno : def.annotations) { - if (typeMatches(Tolerate.class, node, anno.type)) continue top; - } + + if (isTolerate(node, def)) continue top; return getGeneratedBy(def) == null ? MemberExistsResult.EXISTS_BY_USER : MemberExistsResult.EXISTS_BY_LOMBOK; } @@ -1181,6 +1180,13 @@ public class EclipseHandlerUtil { return MemberExistsResult.NOT_EXISTS; } + public static boolean isTolerate(EclipseNode node, AbstractMethodDeclaration def) { + if (def.annotations != null) for (Annotation anno : def.annotations) { + if (typeMatches(Tolerate.class, node, anno.type)) return true; + } + return false; + } + /** * Checks if there is a (non-default) constructor. In case of multiple constructors (overloading), only * the first constructor decides if EXISTS_BY_USER or EXISTS_BY_LOMBOK is returned. @@ -1194,13 +1200,11 @@ public class EclipseHandlerUtil { if (node != null && node.get() instanceof TypeDeclaration) { TypeDeclaration typeDecl = (TypeDeclaration)node.get(); - if (typeDecl.methods != null) top: for (AbstractMethodDeclaration def : typeDecl.methods) { + if (typeDecl.methods != null) for (AbstractMethodDeclaration def : typeDecl.methods) { if (def instanceof ConstructorDeclaration) { if ((def.bits & ASTNode.IsDefaultConstructor) != 0) continue; - if (def.annotations != null) for (Annotation anno : def.annotations) { - if (typeMatches(Tolerate.class, node, anno.type)) continue top; - } + if (isTolerate(node, def)) continue; return getGeneratedBy(def) == null ? MemberExistsResult.EXISTS_BY_USER : MemberExistsResult.EXISTS_BY_LOMBOK; } @@ -1325,6 +1329,7 @@ public class EclipseHandlerUtil { private static final char[] GENERATED_CODE = "generated code".toCharArray(); private static final char[] LOMBOK = "lombok".toCharArray(); private static final char[][] JAVAX_ANNOTATION_GENERATED = Eclipse.fromQualifiedName("javax.annotation.Generated"); + private static final char[][] LOMBOK_GENERATED = Eclipse.fromQualifiedName("lombok.Generated"); private static final char[][] EDU_UMD_CS_FINDBUGS_ANNOTATIONS_SUPPRESSFBWARNINGS = Eclipse.fromQualifiedName("edu.umd.cs.findbugs.annotations.SuppressFBWarnings"); public static Annotation[] addSuppressWarningsAll(EclipseNode node, ASTNode source, Annotation[] originalAnnotationArray) { @@ -1339,24 +1344,29 @@ public class EclipseHandlerUtil { } public static Annotation[] addGenerated(EclipseNode node, ASTNode source, Annotation[] originalAnnotationArray) { - if (Boolean.FALSE.equals(node.getAst().readConfiguration(ConfigurationKeys.ADD_GENERATED_ANNOTATIONS))) return originalAnnotationArray; - return addAnnotation(source, originalAnnotationArray, JAVAX_ANNOTATION_GENERATED, new StringLiteral(LOMBOK, 0, 0, 0)); + Annotation[] result = originalAnnotationArray; + if (HandlerUtil.shouldAddGenerated(node, ConfigurationKeys.ADD_JAVAX_GENERATED_ANNOTATIONS)) { + result = addAnnotation(source, result, JAVAX_ANNOTATION_GENERATED, new StringLiteral(LOMBOK, 0, 0, 0)); + } + if (HandlerUtil.shouldAddGenerated(node, ConfigurationKeys.ADD_LOMBOK_GENERATED_ANNOTATIONS)) { + result = addAnnotation(source, result, LOMBOK_GENERATED, null); + } + return result; } private static Annotation[] addAnnotation(ASTNode source, Annotation[] originalAnnotationArray, char[][] annotationTypeFqn, ASTNode arg) { char[] simpleName = annotationTypeFqn[annotationTypeFqn.length - 1]; if (originalAnnotationArray != null) for (Annotation ann : originalAnnotationArray) { - char[] lastToken = null; - if (ann.type instanceof QualifiedTypeReference) { char[][] t = ((QualifiedTypeReference) ann.type).tokens; - lastToken = t[t.length - 1]; - } else if (ann.type instanceof SingleTypeReference) { - lastToken = ((SingleTypeReference) ann.type).token; + if (Arrays.deepEquals(t, annotationTypeFqn)) return originalAnnotationArray; } - if (lastToken != null && Arrays.equals(simpleName, lastToken)) return originalAnnotationArray; + if (ann.type instanceof SingleTypeReference) { + char[] lastToken = ((SingleTypeReference) ann.type).token; + if (Arrays.equals(lastToken, simpleName)) return originalAnnotationArray; + } } int pS = source.sourceStart, pE = source.sourceEnd; diff --git a/src/core/lombok/eclipse/handlers/HandleBuilder.java b/src/core/lombok/eclipse/handlers/HandleBuilder.java index 4e0c4218..afa03538 100644 --- a/src/core/lombok/eclipse/handlers/HandleBuilder.java +++ b/src/core/lombok/eclipse/handlers/HandleBuilder.java @@ -652,7 +652,7 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { for (int i = 0; i < len; i++) { if (!(existing[i] instanceof MethodDeclaration)) continue; char[] existingName = existing[i].selector; - if (Arrays.equals(name, existingName)) return; + if (Arrays.equals(name, existingName) && !isTolerate(fieldNode, existing[i])) return; } String setterName = fluent ? fieldNode.getName() : HandlerUtil.buildAccessorName("set", fieldNode.getName()); diff --git a/src/core/lombok/eclipse/handlers/HandleConstructor.java b/src/core/lombok/eclipse/handlers/HandleConstructor.java index 85d1d4ed..a3b0585d 100644 --- a/src/core/lombok/eclipse/handlers/HandleConstructor.java +++ b/src/core/lombok/eclipse/handlers/HandleConstructor.java @@ -48,6 +48,7 @@ import org.eclipse.jdt.internal.compiler.ast.AllocationExpression; import org.eclipse.jdt.internal.compiler.ast.Annotation; import org.eclipse.jdt.internal.compiler.ast.Argument; import org.eclipse.jdt.internal.compiler.ast.ArrayInitializer; +import org.eclipse.jdt.internal.compiler.ast.ArrayTypeReference; import org.eclipse.jdt.internal.compiler.ast.Assignment; import org.eclipse.jdt.internal.compiler.ast.CharLiteral; import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration; @@ -381,6 +382,8 @@ public class HandleConstructor { } private static Expression getDefaultExpr(TypeReference type, int s, int e) { + boolean array = type instanceof ArrayTypeReference; + if (array) return new NullLiteral(s, e); char[] lastToken = type.getLastToken(); if (Arrays.equals(TypeConstants.BOOLEAN, lastToken)) return new FalseLiteral(s, e); if (Arrays.equals(TypeConstants.CHAR, lastToken)) return new CharLiteral(new char[] {'\'', '\\', '0', '\''}, s, e); diff --git a/src/core/lombok/eclipse/handlers/HandleFieldDefaults.java b/src/core/lombok/eclipse/handlers/HandleFieldDefaults.java index 5ea5a210..702713fe 100644 --- a/src/core/lombok/eclipse/handlers/HandleFieldDefaults.java +++ b/src/core/lombok/eclipse/handlers/HandleFieldDefaults.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012-2014 The Project Lombok Authors. + * Copyright (C) 2012-2016 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 @@ -97,14 +97,16 @@ public class HandleFieldDefaults extends EclipseASTAdapter { if (level != null && level != AccessLevel.NONE) { if ((field.modifiers & (ClassFileConstants.AccPublic | ClassFileConstants.AccPrivate | ClassFileConstants.AccProtected)) == 0) { if (!hasAnnotation(PackagePrivate.class, fieldNode)) { - field.modifiers |= EclipseHandlerUtil.toEclipseModifier(level); + if ((field.modifiers & ClassFileConstants.AccStatic) == 0) { + field.modifiers |= EclipseHandlerUtil.toEclipseModifier(level); + } } } } if (makeFinal && (field.modifiers & ClassFileConstants.AccFinal) == 0) { if (!hasAnnotation(NonFinal.class, fieldNode)) { - if ((field.modifiers & ClassFileConstants.AccStatic) == 0 || field.initialization != null) { + if ((field.modifiers & ClassFileConstants.AccStatic) == 0) { field.modifiers |= ClassFileConstants.AccFinal; } } diff --git a/src/core/lombok/eclipse/handlers/HandleGetter.java b/src/core/lombok/eclipse/handlers/HandleGetter.java index 14f2fb72..77d678f2 100644 --- a/src/core/lombok/eclipse/handlers/HandleGetter.java +++ b/src/core/lombok/eclipse/handlers/HandleGetter.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2014 The Project Lombok Authors. + * Copyright (C) 2009-2016 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 @@ -183,6 +183,10 @@ public class HandleGetter extends EclipseAnnotationHandler<Getter> { errorNode.addError("'lazy' requires the field to be private and final."); return; } + if ((field.modifiers & ClassFileConstants.AccTransient) != 0) { + errorNode.addError("'lazy' is not supported on transient fields."); + return; + } if (field.initialization == null) { errorNode.addError("'lazy' requires field initialization."); return; diff --git a/src/core/lombok/eclipse/handlers/HandleLog.java b/src/core/lombok/eclipse/handlers/HandleLog.java index 830190a2..c49030d8 100644 --- a/src/core/lombok/eclipse/handlers/HandleLog.java +++ b/src/core/lombok/eclipse/handlers/HandleLog.java @@ -229,6 +229,17 @@ public class HandleLog { } } + /** + * Handles the {@link lombok.extern.jbosslog.JBossLog} annotation for Eclipse. + */ + @ProviderFor(EclipseAnnotationHandler.class) + public static class HandleJBossLog extends EclipseAnnotationHandler<lombok.extern.jbosslog.JBossLog> { + @Override public void handle(AnnotationValues<lombok.extern.jbosslog.JBossLog> annotation, Annotation source, EclipseNode annotationNode) { + handleFlagUsage(annotationNode, ConfigurationKeys.LOG_JBOSSLOG_FLAG_USAGE, "@JBossLog", ConfigurationKeys.LOG_ANY_FLAG_USAGE, "any @Log"); + processAnnotation(LoggingFramework.JBOSSLOG, annotation, source, annotationNode, annotation.getInstance().topic()); + } + } + enum LoggingFramework { // private static final org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog(TargetType.class); COMMONS("org.apache.commons.logging.Log", "org.apache.commons.logging.LogFactory", "getLog", "@CommonsLog"), @@ -264,7 +275,9 @@ public class HandleLog { // private static final org.slf4j.ext.XLogger log = org.slf4j.ext.XLoggerFactory.getXLogger(TargetType.class); XSLF4J("org.slf4j.ext.XLogger", "org.slf4j.ext.XLoggerFactory", "getXLogger", "@XSlf4j"), - + + // private static final org.jboss.logging.Logger log = org.jboss.logging.Logger.getLogger(TargetType.class); + JBOSSLOG("org.jboss.logging.Logger", "org.jboss.logging.Logger", "getLogger", "@JBossLog"), ; private final String loggerTypeName; diff --git a/src/core/lombok/eclipse/handlers/HandleVal.java b/src/core/lombok/eclipse/handlers/HandleVal.java index d4ae417c..d8901067 100644 --- a/src/core/lombok/eclipse/handlers/HandleVal.java +++ b/src/core/lombok/eclipse/handlers/HandleVal.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2014 The Project Lombok Authors. + * Copyright (C) 2010-2016 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,8 @@ */ package lombok.eclipse.handlers; -import static lombok.core.handlers.HandlerUtil.*; +import static lombok.core.handlers.HandlerUtil.handleFlagUsage; +import static lombok.eclipse.handlers.EclipseHandlerUtil.typeMatches; import lombok.ConfigurationKeys; import lombok.val; import lombok.core.HandlerPriority; @@ -29,11 +30,14 @@ import lombok.eclipse.DeferUntilPostDiet; import lombok.eclipse.EclipseASTAdapter; import lombok.eclipse.EclipseASTVisitor; import lombok.eclipse.EclipseNode; +import lombok.experimental.var; import org.eclipse.jdt.internal.compiler.ast.ArrayInitializer; import org.eclipse.jdt.internal.compiler.ast.ForStatement; import org.eclipse.jdt.internal.compiler.ast.ForeachStatement; import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration; +import org.eclipse.jdt.internal.compiler.ast.NullLiteral; +import org.eclipse.jdt.internal.compiler.ast.TypeReference; import org.mangosdk.spi.ProviderFor; /* @@ -44,8 +48,13 @@ import org.mangosdk.spi.ProviderFor; @HandlerPriority(65536) // 2^16; resolution needs to work, so if the RHS expression is i.e. a call to a generated getter, we have to run after that getter has been generated. public class HandleVal extends EclipseASTAdapter { @Override public void visitLocal(EclipseNode localNode, LocalDeclaration local) { - if (!EclipseHandlerUtil.typeMatches(val.class, localNode, local.type)) return; - handleFlagUsage(localNode, ConfigurationKeys.VAL_FLAG_USAGE, "val"); + TypeReference type = local.type; + boolean isVal = typeMatches(val.class, localNode, type); + boolean isVar = typeMatches(var.class, localNode, type); + if (!(isVal || isVar)) return; + + if (isVal) handleFlagUsage(localNode, ConfigurationKeys.VAL_FLAG_USAGE, "val"); + if (isVar) handleFlagUsage(localNode, ConfigurationKeys.VAR_FLAG_USAGE, "var"); boolean variableOfForEach = false; @@ -54,23 +63,30 @@ public class HandleVal extends EclipseASTAdapter { variableOfForEach = fs.elementVariable == local; } + String annotation = isVal ? "val" : "var"; if (local.initialization == null && !variableOfForEach) { - localNode.addError("'val' on a local variable requires an initializer expression"); + localNode.addError("'" + annotation + "' on a local variable requires an initializer expression"); return; } if (local.initialization instanceof ArrayInitializer) { - localNode.addError("'val' is not compatible with array initializer expressions. Use the full form (new int[] { ... } instead of just { ... })"); + localNode.addError("'" + annotation + "' is not compatible with array initializer expressions. Use the full form (new int[] { ... } instead of just { ... })"); return; } - if (localNode.directUp().get() instanceof ForStatement) { + if (isVal && localNode.directUp().get() instanceof ForStatement) { localNode.addError("'val' is not allowed in old-style for loops"); return; } if (local.initialization != null && local.initialization.getClass().getName().equals("org.eclipse.jdt.internal.compiler.ast.LambdaExpression")) { - localNode.addError("'val' is not allowed with lambda expressions."); + localNode.addError("'" + annotation + "' is not allowed with lambda expressions."); + return; + } + + if(isVar && local.initialization instanceof NullLiteral) { + localNode.addError("variable initializer is 'null'"); + return; } } } diff --git a/src/core/lombok/experimental/FieldDefaults.java b/src/core/lombok/experimental/FieldDefaults.java index dbc4993b..384abda5 100644 --- a/src/core/lombok/experimental/FieldDefaults.java +++ b/src/core/lombok/experimental/FieldDefaults.java @@ -33,9 +33,9 @@ import lombok.AccessLevel; * <p> * Complete documentation is found at <a href="https://projectlombok.org/features/experimental/FieldDefaults.html">the project lombok features page for @FieldDefaults</a>. * <p> - * If {@code makeFinal} is {@code true}, then each field that is not annotated with {@code @NonFinal} will have the {@code final} modifier added. + * If {@code makeFinal} is {@code true}, then each (instance) field that is not annotated with {@code @NonFinal} will have the {@code final} modifier added. * <p> - * If {@code level} is set, then each field that is package private (i.e. no access modifier) and does not have the {@code @PackagePrivate} annotation will + * If {@code level} is set, then each (instance) field that is package private (i.e. no access modifier) and does not have the {@code @PackagePrivate} annotation will * have the appropriate access level modifier added. */ @Target(ElementType.TYPE) diff --git a/src/core/lombok/experimental/NonFinal.java b/src/core/lombok/experimental/NonFinal.java index 0c31dd2a..12a45d22 100644 --- a/src/core/lombok/experimental/NonFinal.java +++ b/src/core/lombok/experimental/NonFinal.java @@ -28,7 +28,7 @@ import java.lang.annotation.Target; /** * Used to indicate the explicit intention for the annotated entity to <em>not</em> be {@code final}. - * Currently used by {@code FieldDefaults} to avoid having it make a field final. + * Currently used by {@code FieldDefaults} and {@code Value} to avoid having it make a field final. */ @Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.LOCAL_VARIABLE, ElementType.ANNOTATION_TYPE, ElementType.TYPE, ElementType.METHOD}) @Retention(RetentionPolicy.SOURCE) diff --git a/src/core/lombok/experimental/PackagePrivate.java b/src/core/lombok/experimental/PackagePrivate.java index bfe5638b..42002818 100644 --- a/src/core/lombok/experimental/PackagePrivate.java +++ b/src/core/lombok/experimental/PackagePrivate.java @@ -28,7 +28,7 @@ import java.lang.annotation.Target; /** * Used to indicate the explicit intention for the annotated entity to have the <em>package private</em> access level. - * Currently used by {@code FieldDefaults} to avoid having it make a field one of {@code public}, {@code protected}, or {@code private}. + * Currently used by {@code FieldDefaults} and {@code Value} to avoid having it make a field one of {@code public}, {@code protected}, or {@code private}. */ @Target({ElementType.TYPE, ElementType.FIELD, ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.ANNOTATION_TYPE}) @Retention(RetentionPolicy.SOURCE) diff --git a/src/core/lombok/experimental/var.java b/src/core/lombok/experimental/var.java new file mode 100644 index 00000000..d8de8b19 --- /dev/null +++ b/src/core/lombok/experimental/var.java @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2010-2013 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.experimental; + +/** + * like val but not final + */ +public @interface var { +} diff --git a/src/core/lombok/extern/apachecommons/CommonsLog.java b/src/core/lombok/extern/apachecommons/CommonsLog.java index 6e64d2d8..777f4b35 100644 --- a/src/core/lombok/extern/apachecommons/CommonsLog.java +++ b/src/core/lombok/extern/apachecommons/CommonsLog.java @@ -55,6 +55,7 @@ import java.lang.annotation.Target; * @see lombok.extern.log4j.Log4j2 @Log4j2 * @see lombok.extern.slf4j.Slf4j @Slf4j * @see lombok.extern.slf4j.XSlf4j @XSlf4j + * @see lombok.extern.jbosslog.JBossLog @JBossLog */ @Retention(RetentionPolicy.SOURCE) @Target(ElementType.TYPE) diff --git a/src/core/lombok/extern/java/Log.java b/src/core/lombok/extern/java/Log.java index d2cf8c17..d5515283 100644 --- a/src/core/lombok/extern/java/Log.java +++ b/src/core/lombok/extern/java/Log.java @@ -54,6 +54,7 @@ import java.lang.annotation.Target; * @see lombok.extern.log4j.Log4j2 @Log4j2 * @see lombok.extern.slf4j.Slf4j @Slf4j * @see lombok.extern.slf4j.XSlf4j @XSlf4j + * @see lombok.extern.jbosslog.JBossLog @JBossLog */ @Retention(RetentionPolicy.SOURCE) @Target(ElementType.TYPE) diff --git a/src/core/lombok/extern/jbosslog/JBossLog.java b/src/core/lombok/extern/jbosslog/JBossLog.java new file mode 100644 index 00000000..2735290c --- /dev/null +++ b/src/core/lombok/extern/jbosslog/JBossLog.java @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2016 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.extern.jbosslog; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Causes lombok to generate a logger field. + * <p> + * Complete documentation is found at <a href="https://projectlombok.org/features/Log.html">the project lombok features page for lombok log annotations</a>. + * <p> + * Example: + * <pre> + * @JBossLog + * public class LogExample { + * } + * </pre> + * + * will generate: + * + * <pre> + * public class LogExample { + * private static final org.jboss.logging.Logger log = org.jboss.logging.Logger.getLogger(LogExample.class); + * } + * </pre> + * + * This annotation is valid for classes and enumerations.<br /> + * @see org.jboss.logging.Logger org.jboss.logging.Logger + * @see org.jboss.logging.Logger#getLogger(java.lang.Class) org.jboss.logging.Logger.getLogger(Class target) + * @see lombok.extern.apachecommons.CommonsLog @CommonsLog + * @see lombok.extern.java.Log @Log + * @see lombok.extern.log4j.Log4j @Log4j + * @see lombok.extern.log4j.Log4j2 @Log4j2 + * @see lombok.extern.slf4j.XSlf4j @XSlf4j + * @see lombok.extern.jbosslog.JBossLog @JBossLog + * */ +@Retention(RetentionPolicy.SOURCE) +@Target(ElementType.TYPE) +public @interface JBossLog { + + /** + * Sets the category of the constructed Logger. By default, it will use the type where the annotation is placed. + */ + String topic() default ""; +} diff --git a/src/core/lombok/extern/log4j/Log4j.java b/src/core/lombok/extern/log4j/Log4j.java index 31fedbe7..6c6ef1da 100644 --- a/src/core/lombok/extern/log4j/Log4j.java +++ b/src/core/lombok/extern/log4j/Log4j.java @@ -55,6 +55,7 @@ import java.lang.annotation.Target; * @see lombok.extern.java.Log @Log * @see lombok.extern.slf4j.Slf4j @Slf4j * @see lombok.extern.slf4j.XSlf4j @XSlf4j + * @see lombok.extern.jbosslog.JBossLog @JBossLog */ @Retention(RetentionPolicy.SOURCE) @Target(ElementType.TYPE) diff --git a/src/core/lombok/extern/log4j/Log4j2.java b/src/core/lombok/extern/log4j/Log4j2.java index 96d793f7..a1b2e0e7 100644 --- a/src/core/lombok/extern/log4j/Log4j2.java +++ b/src/core/lombok/extern/log4j/Log4j2.java @@ -55,6 +55,7 @@ import java.lang.annotation.Target; * @see lombok.extern.java.Log @Log * @see lombok.extern.slf4j.Slf4j @Slf4j * @see lombok.extern.slf4j.XSlf4j @XSlf4j + * @see lombok.extern.jbosslog.JBossLog @JBossLog */ @Retention(RetentionPolicy.SOURCE) @Target(ElementType.TYPE) diff --git a/src/core/lombok/extern/slf4j/Slf4j.java b/src/core/lombok/extern/slf4j/Slf4j.java index 571ebd58..efa6105f 100644 --- a/src/core/lombok/extern/slf4j/Slf4j.java +++ b/src/core/lombok/extern/slf4j/Slf4j.java @@ -54,7 +54,8 @@ import java.lang.annotation.Target; * @see lombok.extern.log4j.Log4j @Log4j * @see lombok.extern.log4j.Log4j2 @Log4j2 * @see lombok.extern.slf4j.XSlf4j @XSlf4j - * */ + * @see lombok.extern.jbosslog.JBossLog @JBossLog + */ @Retention(RetentionPolicy.SOURCE) @Target(ElementType.TYPE) public @interface Slf4j { diff --git a/src/core/lombok/extern/slf4j/XSlf4j.java b/src/core/lombok/extern/slf4j/XSlf4j.java index 369728c4..ce23ab9e 100644 --- a/src/core/lombok/extern/slf4j/XSlf4j.java +++ b/src/core/lombok/extern/slf4j/XSlf4j.java @@ -54,6 +54,7 @@ import java.lang.annotation.Target; * @see lombok.extern.log4j.Log4j @Log4j * @see lombok.extern.log4j.Log4j2 @Log4j2 * @see lombok.extern.slf4j.Slf4j @Slf4j + * @see lombok.extern.jbosslog.JBossLog @JBossLog */ @Retention(RetentionPolicy.SOURCE) @Target(ElementType.TYPE) diff --git a/src/core/lombok/javac/JavacAST.java b/src/core/lombok/javac/JavacAST.java index da61361d..106a29ae 100644 --- a/src/core/lombok/javac/JavacAST.java +++ b/src/core/lombok/javac/JavacAST.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2015 The Project Lombok Authors. + * Copyright (C) 2009-2016 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 @@ -28,6 +28,8 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; import javax.annotation.processing.Messager; import javax.tools.Diagnostic; @@ -79,7 +81,7 @@ public class JavacAST extends AST<JavacAST, JavacNode, JCTree> { * @param top The compilation unit, which serves as the top level node in the tree to be built. */ public JavacAST(Messager messager, Context context, JCCompilationUnit top) { - super(sourceName(top), PackageName.getPackageName(top), new JavacImportList(top)); + super(sourceName(top), PackageName.getPackageName(top), new JavacImportList(top), statementTypes()); setTop(buildCompilationUnit(top)); this.context = context; this.messager = messager; @@ -315,7 +317,6 @@ public class JavacAST extends AST<JavacAST, JavacNode, JCTree> { // @Foo int x, y; is handled in javac by putting the same annotation node on 2 JCVariableDecls. return null; } - return putInMap(new JavacNode(this, annotation, null, Kind.ANNOTATION)); } @@ -333,12 +334,40 @@ public class JavacAST extends AST<JavacAST, JavacNode, JCTree> { if (statement instanceof JCClassDecl) return buildType((JCClassDecl)statement); if (statement instanceof JCVariableDecl) return buildLocalVar((JCVariableDecl)statement, Kind.LOCAL); if (statement instanceof JCTry) return buildTry((JCTry) statement); - + if (statement.getClass().getSimpleName().equals("JCLambda")) return buildLambda(statement); if (setAndGetAsHandled(statement)) return null; return drill(statement); } + private JavacNode buildLambda(JCTree jcTree) { + return buildStatementOrExpression(getBody(jcTree)); + } + + private JCTree getBody(JCTree jcTree) { + try { + return (JCTree) getBodyMethod(jcTree.getClass()).invoke(jcTree); + } catch (Exception e) { + throw Javac.sneakyThrow(e); + } + } + + private final static ConcurrentMap<Class<?>, Method> getBodyMethods = new ConcurrentHashMap<Class<?>, Method>(); + + private Method getBodyMethod(Class<?> c) { + Method m = getBodyMethods.get(c); + if (m != null) { + return m; + } + try { + m = c.getMethod("getBody"); + } catch (NoSuchMethodException e) { + throw Javac.sneakyThrow(e); + } + getBodyMethods.putIfAbsent(c, m); + return getBodyMethods.get(c); + } + private JavacNode drill(JCTree statement) { try { List<JavacNode> childNodes = new ArrayList<JavacNode>(); @@ -354,9 +383,8 @@ public class JavacAST extends AST<JavacAST, JavacNode, JCTree> { } } - /** For javac, both JCExpression and JCStatement are considered as valid children types. */ - @Override - protected Collection<Class<? extends JCTree>> getStatementTypes() { + /* For javac, both JCExpression and JCStatement are considered as valid children types. */ + private static Collection<Class<? extends JCTree>> statementTypes() { Collection<Class<? extends JCTree>> collection = new ArrayList<Class<? extends JCTree>>(3); collection.add(JCStatement.class); collection.add(JCExpression.class); diff --git a/src/core/lombok/javac/apt/LombokProcessor.java b/src/core/lombok/javac/apt/LombokProcessor.java index 128545c7..6547c143 100644 --- a/src/core/lombok/javac/apt/LombokProcessor.java +++ b/src/core/lombok/javac/apt/LombokProcessor.java @@ -273,14 +273,12 @@ public class LombokProcessor extends AbstractProcessor { if (newLevels.isEmpty()) return false; newLevels.retainAll(priorityLevelsRequiringResolutionReset); - if (newLevels.isEmpty()) { - // None of the new levels need resolution, so just keep going. - continue; - } else { + if (!newLevels.isEmpty()){ // Force a new round to reset resolution. The next round will cause this method (process) to be called again. forceNewRound((JavacFiler) processingEnv.getFiler()); return false; } + // None of the new levels need resolution, so just keep going. } } @@ -310,6 +308,6 @@ public class LombokProcessor extends AbstractProcessor { * 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.values()[SourceVersion.values().length - 1]; + return SourceVersion.latest(); } } diff --git a/src/core/lombok/javac/handlers/HandleBuilder.java b/src/core/lombok/javac/handlers/HandleBuilder.java index b83e3d5f..9c3c9d03 100644 --- a/src/core/lombok/javac/handlers/HandleBuilder.java +++ b/src/core/lombok/javac/handlers/HandleBuilder.java @@ -608,8 +608,9 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> { for (JavacNode child : builderType.down()) { if (child.getKind() != Kind.METHOD) continue; - Name existingName = ((JCMethodDecl) child.get()).name; - if (existingName.equals(fieldName)) return; + JCMethodDecl methodDecl = (JCMethodDecl) child.get(); + Name existingName = methodDecl.name; + if (existingName.equals(fieldName) && !isTolerate(fieldNode, methodDecl)) return; } String setterName = fluent ? fieldNode.getName() : HandlerUtil.buildAccessorName("set", fieldNode.getName()); diff --git a/src/core/lombok/javac/handlers/HandleDelegate.java b/src/core/lombok/javac/handlers/HandleDelegate.java index 680e7745..49bef769 100644 --- a/src/core/lombok/javac/handlers/HandleDelegate.java +++ b/src/core/lombok/javac/handlers/HandleDelegate.java @@ -312,7 +312,7 @@ public class HandleDelegate extends JavacAnnotationHandler<Delegate> { for (TypeMirror param : sig.type.getTypeVariables()) { Name name = ((TypeVar) param).tsym.name; - ListBuffer<JCExpression> bounds = types.getBounds((TypeVar) param).isEmpty() ? null : new ListBuffer<JCExpression>(); + ListBuffer<JCExpression> bounds = new ListBuffer<JCExpression>(); for (Type type : types.getBounds((TypeVar) param)) { bounds.append(JavacResolution.typeToJCTree(type, annotation.getAst(), true)); } diff --git a/src/core/lombok/javac/handlers/HandleFieldDefaults.java b/src/core/lombok/javac/handlers/HandleFieldDefaults.java index 12c22059..52f6c39c 100644 --- a/src/core/lombok/javac/handlers/HandleFieldDefaults.java +++ b/src/core/lombok/javac/handlers/HandleFieldDefaults.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012-2015 The Project Lombok Authors. + * Copyright (C) 2012-2016 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 @@ -84,14 +84,16 @@ public class HandleFieldDefaults extends JavacASTAdapter { if (level != null && level != AccessLevel.NONE) { if ((field.mods.flags & (Flags.PUBLIC | Flags.PRIVATE | Flags.PROTECTED)) == 0) { if (!hasAnnotationAndDeleteIfNeccessary(PackagePrivate.class, fieldNode)) { - field.mods.flags |= toJavacModifier(level); + if ((field.mods.flags & Flags.STATIC) == 0) { + field.mods.flags |= toJavacModifier(level); + } } } } if (makeFinal && (field.mods.flags & Flags.FINAL) == 0) { if (!hasAnnotationAndDeleteIfNeccessary(NonFinal.class, fieldNode)) { - if ((field.mods.flags & Flags.STATIC) == 0 || field.init != null) { + if ((field.mods.flags & Flags.STATIC) == 0) { field.mods.flags |= Flags.FINAL; } } diff --git a/src/core/lombok/javac/handlers/HandleGetter.java b/src/core/lombok/javac/handlers/HandleGetter.java index a330dbc1..0a2fe362 100644 --- a/src/core/lombok/javac/handlers/HandleGetter.java +++ b/src/core/lombok/javac/handlers/HandleGetter.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2014 The Project Lombok Authors. + * Copyright (C) 2009-2016 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 @@ -182,6 +182,10 @@ public class HandleGetter extends JavacAnnotationHandler<Getter> { source.addError("'lazy' requires the field to be private and final."); return; } + if ((fieldDecl.mods.flags & Flags.TRANSIENT) != 0) { + source.addError("'lazy' is not supported on transient fields."); + return; + } if (fieldDecl.init == null) { source.addError("'lazy' requires field initialization."); return; diff --git a/src/core/lombok/javac/handlers/HandleLog.java b/src/core/lombok/javac/handlers/HandleLog.java index 06b7c7ef..d0d709e3 100644 --- a/src/core/lombok/javac/handlers/HandleLog.java +++ b/src/core/lombok/javac/handlers/HandleLog.java @@ -175,6 +175,17 @@ public class HandleLog { } } + /** + * Handles the {@link lombok.extern.jbosslog.JBossLog} annotation for javac. + */ + @ProviderFor(JavacAnnotationHandler.class) + public static class HandleJBossLog extends JavacAnnotationHandler<lombok.extern.jbosslog.JBossLog> { + @Override public void handle(AnnotationValues<lombok.extern.jbosslog.JBossLog> annotation, JCAnnotation ast, JavacNode annotationNode) { + handleFlagUsage(annotationNode, ConfigurationKeys.LOG_JBOSSLOG_FLAG_USAGE, "@JBossLog", ConfigurationKeys.LOG_ANY_FLAG_USAGE, "any @Log"); + processAnnotation(LoggingFramework.JBOSSLOG, annotation, annotationNode, annotation.getInstance().topic()); + } + } + enum LoggingFramework { // private static final org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog(TargetType.class); COMMONS(lombok.extern.apachecommons.CommonsLog.class, "org.apache.commons.logging.Log", "org.apache.commons.logging.LogFactory.getLog"), @@ -200,6 +211,8 @@ public class HandleLog { // private static final org.slf4j.ext.XLogger log = org.slf4j.ext.XLoggerFactory.getXLogger(TargetType.class); XSLF4J(lombok.extern.slf4j.XSlf4j.class, "org.slf4j.ext.XLogger", "org.slf4j.ext.XLoggerFactory.getXLogger"), + // private static final org.jboss.logging.Logger log = org.jboss.logging.Logger.getLogger(TargetType.class); + JBOSSLOG(lombok.extern.jbosslog.JBossLog.class, "org.jboss.logging.Logger", "org.jboss.logging.Logger.getLogger") ; private final Class<? extends Annotation> annotationClass; diff --git a/src/core/lombok/javac/handlers/HandleVal.java b/src/core/lombok/javac/handlers/HandleVal.java index 337ab2d7..2976eabe 100644 --- a/src/core/lombok/javac/handlers/HandleVal.java +++ b/src/core/lombok/javac/handlers/HandleVal.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2015 The Project Lombok Authors. + * Copyright (C) 2010-2016 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,11 +21,12 @@ */ package lombok.javac.handlers; -import static lombok.core.handlers.HandlerUtil.*; +import static lombok.core.handlers.HandlerUtil.handleFlagUsage; import static lombok.javac.handlers.JavacHandlerUtil.*; import lombok.ConfigurationKeys; import lombok.val; import lombok.core.HandlerPriority; +import lombok.experimental.var; import lombok.javac.JavacASTAdapter; import lombok.javac.JavacASTVisitor; import lombok.javac.JavacNode; @@ -42,6 +43,7 @@ import com.sun.tools.javac.tree.JCTree.JCAnnotation; import com.sun.tools.javac.tree.JCTree.JCEnhancedForLoop; import com.sun.tools.javac.tree.JCTree.JCExpression; import com.sun.tools.javac.tree.JCTree.JCForLoop; +import com.sun.tools.javac.tree.JCTree.JCLiteral; import com.sun.tools.javac.tree.JCTree.JCNewArray; import com.sun.tools.javac.tree.JCTree.JCVariableDecl; import com.sun.tools.javac.util.List; @@ -50,21 +52,31 @@ import com.sun.tools.javac.util.List; @HandlerPriority(65536) // 2^16; resolution needs to work, so if the RHS expression is i.e. a call to a generated getter, we have to run after that getter has been generated. @ResolutionResetNeeded public class HandleVal extends JavacASTAdapter { - @Override public void visitLocal(JavacNode localNode, JCVariableDecl local) { + + private static boolean eq(String typeTreeToString, String key) { + return (typeTreeToString.equals(key) || typeTreeToString.equals("lombok." + key)); + } + + @Override + public void visitLocal(JavacNode localNode, JCVariableDecl local) { JCTree typeTree = local.vartype; if (typeTree == null) return; String typeTreeToString = typeTree.toString(); - if (!typeTreeToString.equals("val") && !typeTreeToString.equals("lombok.val")) return; - if (!typeMatches(val.class, localNode, typeTree)) return; - - handleFlagUsage(localNode, ConfigurationKeys.VAL_FLAG_USAGE, "val"); - + + if (!(eq(typeTreeToString, "val") || eq(typeTreeToString, "var"))) return; + boolean isVal = typeMatches(val.class, localNode, typeTree); + boolean isVar = typeMatches(var.class, localNode, typeTree); + if (!(isVal || isVar)) return; + + if (isVal) handleFlagUsage(localNode, ConfigurationKeys.VAL_FLAG_USAGE, "val"); + if (isVar) handleFlagUsage(localNode, ConfigurationKeys.VAR_FLAG_USAGE, "var"); + JCTree parentRaw = localNode.directUp().get(); - if (parentRaw instanceof JCForLoop) { + if (isVal && parentRaw instanceof JCForLoop) { localNode.addError("'val' is not allowed in old-style for loops"); return; } - + JCExpression rhsOfEnhancedForLoop = null; if (local.init == null) { if (parentRaw instanceof JCEnhancedForLoop) { @@ -72,21 +84,26 @@ public class HandleVal extends JavacASTAdapter { if (efl.var == local) rhsOfEnhancedForLoop = efl.expr; } } - + + final String annotation = typeTreeToString; if (rhsOfEnhancedForLoop == null && local.init == null) { - localNode.addError("'val' on a local variable requires an initializer expression"); + localNode.addError("'" + annotation + "' on a local variable requires an initializer expression"); return; + } - + if (local.init instanceof JCNewArray && ((JCNewArray)local.init).elemtype == null) { - localNode.addError("'val' is not compatible with array initializer expressions. Use the full form (new int[] { ... } instead of just { ... })"); + localNode.addError("'" + annotation + "' is not compatible with array initializer expressions. Use the full form (new int[] { ... } instead of just { ... })"); return; } - - if (localNode.shouldDeleteLombokAnnotations()) JavacHandlerUtil.deleteImportFromCompilationUnit(localNode, "lombok.val"); - - local.mods.flags |= Flags.FINAL; - + + if (localNode.shouldDeleteLombokAnnotations()) { + JavacHandlerUtil.deleteImportFromCompilationUnit(localNode, val.class.getName()); + JavacHandlerUtil.deleteImportFromCompilationUnit(localNode, var.class.getName()); + } + + if (isVal) local.mods.flags |= Flags.FINAL; + if (!localNode.shouldDeleteLombokAnnotations()) { JCAnnotation valAnnotation = recursiveSetGeneratedBy(localNode.getTreeMaker().Annotation(local.vartype, List.<JCExpression>nil()), typeTree, localNode.getContext()); local.mods.annotations = local.mods.annotations == null ? List.of(valAnnotation) : local.mods.annotations.append(valAnnotation); @@ -102,6 +119,9 @@ public class HandleVal extends JavacASTAdapter { try { if (rhsOfEnhancedForLoop == null) { if (local.init.type == null) { + if (isVar && local.init instanceof JCLiteral && ((JCLiteral) local.init).value == null) { + localNode.addError("variable initializer is 'null'"); + } JavacResolution resolver = new JavacResolution(localNode.getContext()); try { type = ((JCExpression) resolver.resolveMethodMember(localNode).get(local.init)).type; @@ -149,7 +169,7 @@ public class HandleVal extends JavacASTAdapter { } localNode.getAst().setChanged(); } catch (JavacResolution.TypeNotConvertibleException e) { - localNode.addError("Cannot use 'val' here because initializer expression does not have a representable type: " + e.getMessage()); + localNode.addError("Cannot use '" + annotation + "' here because initializer expression does not have a representable type: " + e.getMessage()); local.vartype = JavacResolution.createJavaLangObject(localNode.getAst()); } } catch (RuntimeException e) { diff --git a/src/core/lombok/javac/handlers/JavacHandlerUtil.java b/src/core/lombok/javac/handlers/JavacHandlerUtil.java index fdc8a262..1ea3fa92 100644 --- a/src/core/lombok/javac/handlers/JavacHandlerUtil.java +++ b/src/core/lombok/javac/handlers/JavacHandlerUtil.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2015 The Project Lombok Authors. + * Copyright (C) 2009-2017 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 @@ -605,10 +605,7 @@ public class JavacHandlerUtil { if (params < minArgs || params > maxArgs) continue; } - List<JCAnnotation> annotations = md.getModifiers().getAnnotations(); - if (annotations != null) for (JCAnnotation anno : annotations) { - if (typeMatches(Tolerate.class, node, anno.getAnnotationType())) continue top; - } + if (isTolerate(node, md)) continue top; return getGeneratedBy(def) == null ? MemberExistsResult.EXISTS_BY_USER : MemberExistsResult.EXISTS_BY_LOMBOK; } @@ -619,6 +616,14 @@ public class JavacHandlerUtil { return MemberExistsResult.NOT_EXISTS; } + public static boolean isTolerate(JavacNode node, JCTree.JCMethodDecl md) { + List<JCAnnotation> annotations = md.getModifiers().getAnnotations(); + if (annotations != null) for (JCTree.JCAnnotation anno : annotations) { + if (typeMatches(Tolerate.class, node, anno.getAnnotationType())) return true; + } + return false; + } + /** * Checks if there is a (non-default) constructor. In case of multiple constructors (overloading), only * the first constructor decides if EXISTS_BY_USER or EXISTS_BY_LOMBOK is returned. @@ -629,15 +634,12 @@ public class JavacHandlerUtil { node = upToTypeNode(node); if (node != null && node.get() instanceof JCClassDecl) { - top: for (JCTree def : ((JCClassDecl)node.get()).defs) { + for (JCTree def : ((JCClassDecl)node.get()).defs) { if (def instanceof JCMethodDecl) { JCMethodDecl md = (JCMethodDecl) def; if (md.name.contentEquals("<init>")) { if ((md.mods.flags & Flags.GENERATEDCONSTR) != 0) continue; - List<JCAnnotation> annotations = md.getModifiers().getAnnotations(); - if (annotations != null) for (JCAnnotation anno : annotations) { - if (typeMatches(Tolerate.class, node, anno.getAnnotationType())) continue top; - } + if (isTolerate(node, md)) continue; return getGeneratedBy(def) == null ? MemberExistsResult.EXISTS_BY_USER : MemberExistsResult.EXISTS_BY_LOMBOK; } } @@ -997,9 +999,12 @@ public class JavacHandlerUtil { public static void addGenerated(JCModifiers mods, JavacNode node, int pos, JCTree source, Context context) { if (!LombokOptionsFactory.getDelombokOptions(context).getFormatPreferences().generateGenerated()) return; - if (!Boolean.FALSE.equals(node.getAst().readConfiguration(ConfigurationKeys.ADD_GENERATED_ANNOTATIONS))) { + if (HandlerUtil.shouldAddGenerated(node, ConfigurationKeys.ADD_JAVAX_GENERATED_ANNOTATIONS)) { addAnnotation(mods, node, pos, source, context, "javax.annotation.Generated", node.getTreeMaker().Literal("lombok")); } + if (HandlerUtil.shouldAddGenerated(node, ConfigurationKeys.ADD_LOMBOK_GENERATED_ANNOTATIONS)) { + addAnnotation(mods, node, pos, source, context, "lombok.Generated", null); + } } private static void addAnnotation(JCModifiers mods, JavacNode node, int pos, JCTree source, Context context, String annotationTypeFqn, JCExpression arg) { @@ -1013,12 +1018,16 @@ public class JavacHandlerUtil { for (JCAnnotation ann : mods.annotations) { JCTree annType = ann.getAnnotationType(); - Name lastPart = null; - if (annType instanceof JCIdent) lastPart = ((JCIdent) annType).name; - else if (annType instanceof JCFieldAccess) lastPart = ((JCFieldAccess) annType).name; + if (annType instanceof JCIdent) { + Name lastPart = ((JCIdent) annType).name; + if (lastPart.contentEquals(simpleName)) return; + } - if (lastPart != null && lastPart.contentEquals(simpleName)) return; + if (annType instanceof JCFieldAccess) { + if (annType.toString().equals(annotationTypeFqn)) return; + } } + JavacTreeMaker maker = node.getTreeMaker(); JCExpression annType = isJavaLangBased ? genJavaLangTypeRef(node, simpleName) : chainDotsString(node, annotationTypeFqn); annType.pos = pos; diff --git a/src/delombok/lombok/delombok/FormatPreferences.java b/src/delombok/lombok/delombok/FormatPreferences.java index 5ba3b8cd..3861685d 100644 --- a/src/delombok/lombok/delombok/FormatPreferences.java +++ b/src/delombok/lombok/delombok/FormatPreferences.java @@ -44,7 +44,7 @@ public final class FormatPreferences { keys.put("finalParams", "Either 'generate' or 'skip'. generate means: All lombok-generated methods set all parameters to final. Default: 'generate'"); keys.put("constructorProperties", "Either 'generate' or 'skip'. generate means: All lombok-generated constructors with 1 or more arguments get an @ConstructorProperties annotation. Default: 'generate'"); keys.put("suppressWarnings", "Either 'generate' or 'skip'. generate means: All lombok-generated methods, types, and fields get a @SuppressWarnings annotation. Default: 'generate'"); - keys.put("generated", "Either 'generate' or 'skip'. generate means: All lombok-generated methods, types, and fields get a @Generated(\"lombok\") annotation. Default: 'generate'"); + keys.put("generated", "Either 'generate' or 'skip'. generate means: All lombok-generated methods, types, and fields get a @javax.annotation.Generated(\"lombok\") annotation. Default: 'generate'"); keys.put("danceAroundIdeChecks", "Either 'generate' or 'skip'. generate means: Lombok will intentionally obfuscate some generated code to avoid IDE warnings. Default: 'generate'"); keys.put("generateDelombokComment", "Either 'generate' or 'skip'. generate means: Any file modified by delombok will have a comment stating this at the top. Default: 'generate'"); keys.put("javaLangAsFQN", "Either 'generate' or 'skip'. generate means: Any generated reference to java.lang classes are prefixed with `java.lang.`. Default: 'generate'"); diff --git a/src/delombok/lombok/delombok/PrettyPrinter.java b/src/delombok/lombok/delombok/PrettyPrinter.java index 73d6ee90..b5064a33 100644 --- a/src/delombok/lombok/delombok/PrettyPrinter.java +++ b/src/delombok/lombok/delombok/PrettyPrinter.java @@ -1,3 +1,24 @@ +/* + * Copyright (C) 2016 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.delombok; import static com.sun.tools.javac.code.Flags.*; @@ -1054,6 +1075,7 @@ public class PrettyPrinter extends JCTree.Visitor { @Override public void visitForLoop(JCForLoop tree) { aPrint("for ("); if (tree.init.nonEmpty()) { + // ForInit is either a StatementExpressionList or a LocalVariableDeclaration if (tree.init.head instanceof JCVariableDecl) { boolean first = true; int dims = 0; @@ -1075,7 +1097,12 @@ public class PrettyPrinter extends JCTree.Visitor { first = false; } } else { - print(tree.init, ", "); + boolean first = true; + for (JCStatement exprStatement : tree.init) { + if (!first) print(", "); + first = false; + print(((JCExpressionStatement) exprStatement).expr); + } } } print("; "); diff --git a/src/eclipseAgent/lombok/eclipse/agent/EclipsePatcher.java b/src/eclipseAgent/lombok/eclipse/agent/EclipsePatcher.java index 336204a2..77f615b5 100644 --- a/src/eclipseAgent/lombok/eclipse/agent/EclipsePatcher.java +++ b/src/eclipseAgent/lombok/eclipse/agent/EclipsePatcher.java @@ -24,6 +24,8 @@ package lombok.eclipse.agent; import static lombok.patcher.scripts.ScriptBuilder.*; import java.lang.instrument.Instrumentation; +import java.net.URLClassLoader; +import java.security.ProtectionDomain; import java.util.Collection; import java.util.Collections; import java.util.List; @@ -31,6 +33,7 @@ import java.util.List; import org.eclipse.jdt.internal.corext.refactoring.SearchResultGroup; import lombok.core.AgentLauncher; +import lombok.patcher.Filter; import lombok.patcher.Hook; import lombok.patcher.MethodTarget; import lombok.patcher.ScriptManager; @@ -76,6 +79,15 @@ public class EclipsePatcher implements AgentLauncher.AgentLaunchable { private static void registerPatchScripts(Instrumentation instrumentation, boolean reloadExistingClasses, boolean ecjOnly, Class<?> launchingContext) { ScriptManager sm = new ScriptManager(); sm.registerTransformer(instrumentation); + sm.setFilter(new Filter() { + @Override public boolean shouldTransform(ClassLoader loader, String className, Class<?> classBeingDefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) { + if (!(loader instanceof URLClassLoader)) return true; + ClassLoader parent = loader.getParent(); + if (parent == null) return true; + return !parent.getClass().getName().startsWith("org.eclipse.jdt.apt.core.internal.AnnotationProcessorFactoryLoader"); + } + }); + final boolean forceBaseResourceNames = !"".equals(System.getProperty("shadow.override.lombok", "")); sm.setTransplantMapper(new TransplantMapper() { public String mapResourceName(int classFileFormatVersion, String resourceName) { diff --git a/src/eclipseAgent/lombok/eclipse/agent/PatchDelegate.java b/src/eclipseAgent/lombok/eclipse/agent/PatchDelegate.java index b1f5a43a..02760e35 100644 --- a/src/eclipseAgent/lombok/eclipse/agent/PatchDelegate.java +++ b/src/eclipseAgent/lombok/eclipse/agent/PatchDelegate.java @@ -699,7 +699,10 @@ public class PatchDelegate { } private static void addAllMethodBindings0(List<BindingTuple> list, TypeBinding binding, Set<String> banList, char[] fieldName, ASTNode responsible) throws DelegateRecursion { - if (binding instanceof SourceTypeBinding) ((SourceTypeBinding) binding).scope.environment().globalOptions.storeAnnotations = true; + if (binding instanceof SourceTypeBinding) { + ClassScope scope = ((SourceTypeBinding) binding).scope; + if (scope != null) scope.environment().globalOptions.storeAnnotations = true; + } if (binding == null) return; TypeBinding inner; @@ -721,42 +724,44 @@ public class PatchDelegate { } } - if (binding instanceof ReferenceBinding) { - ReferenceBinding rb = (ReferenceBinding) binding; - MethodBinding[] availableMethods = rb.availableMethods(); - FieldBinding[] availableFields = rb.availableFields(); - failIfContainsAnnotation(binding, availableMethods); - failIfContainsAnnotation(binding, availableFields); - - MethodBinding[] parameterizedSigs = availableMethods; - MethodBinding[] baseSigs = parameterizedSigs; - if (binding instanceof ParameterizedTypeBinding) { - baseSigs = ((ParameterizedTypeBinding)binding).genericType().availableMethods(); - if (baseSigs.length != parameterizedSigs.length) { - // The last known state of eclipse source says this can't happen, so we rely on it, - // but if this invariant is broken, better to go with 'arg0' naming instead of crashing. - baseSigs = parameterizedSigs; - } - } - for (int i = 0; i < parameterizedSigs.length; i++) { - MethodBinding mb = parameterizedSigs[i]; - String sig = printSig(mb); - if (mb.isStatic()) continue; - if (mb.isBridge()) continue; - if (mb.isConstructor()) continue; - if (mb.isDefaultAbstract()) continue; - if (!mb.isPublic()) continue; - if (mb.isSynthetic()) continue; - if (!banList.add(sig)) continue; // If add returns false, it was already in there. - BindingTuple pair = new BindingTuple(mb, baseSigs[i], fieldName, responsible); - list.add(pair); - } - addAllMethodBindings0(list, rb.superclass(), banList, fieldName, responsible); - ReferenceBinding[] interfaces = rb.superInterfaces(); - if (interfaces != null) { - for (ReferenceBinding iface : interfaces) addAllMethodBindings0(list, iface, banList, fieldName, responsible); + if (!(binding instanceof ReferenceBinding)) { + return; + } + + ReferenceBinding rb = (ReferenceBinding) binding; + MethodBinding[] availableMethods = rb.availableMethods(); + FieldBinding[] availableFields = rb.availableFields(); + failIfContainsAnnotation(binding, availableMethods); + failIfContainsAnnotation(binding, availableFields); + + MethodBinding[] parameterizedSigs = availableMethods; + MethodBinding[] baseSigs = parameterizedSigs; + if (binding instanceof ParameterizedTypeBinding) { + baseSigs = ((ParameterizedTypeBinding)binding).genericType().availableMethods(); + if (baseSigs.length != parameterizedSigs.length) { + // The last known state of eclipse source says this can't happen, so we rely on it, + // but if this invariant is broken, better to go with 'arg0' naming instead of crashing. + baseSigs = parameterizedSigs; } } + for (int i = 0; i < parameterizedSigs.length; i++) { + MethodBinding mb = parameterizedSigs[i]; + String sig = printSig(mb); + if (mb.isStatic()) continue; + if (mb.isBridge()) continue; + if (mb.isConstructor()) continue; + if (mb.isDefaultAbstract()) continue; + if (!mb.isPublic()) continue; + if (mb.isSynthetic()) continue; + if (!banList.add(sig)) continue; // If add returns false, it was already in there. + BindingTuple pair = new BindingTuple(mb, baseSigs[i], fieldName, responsible); + list.add(pair); + } + addAllMethodBindings0(list, rb.superclass(), banList, fieldName, responsible); + ReferenceBinding[] interfaces = rb.superInterfaces(); + if (interfaces != null) { + for (ReferenceBinding iface : interfaces) addAllMethodBindings0(list, iface, banList, fieldName, responsible); + } } private static final char[] STRING_LOMBOK = new char[] {'l', 'o', 'm', 'b', 'o', 'k'}; diff --git a/src/eclipseAgent/lombok/eclipse/agent/PatchVal.java b/src/eclipseAgent/lombok/eclipse/agent/PatchVal.java index 2b8dfbaa..e4dd7b26 100644 --- a/src/eclipseAgent/lombok/eclipse/agent/PatchVal.java +++ b/src/eclipseAgent/lombok/eclipse/agent/PatchVal.java @@ -21,11 +21,6 @@ */ package lombok.eclipse.agent; -import static lombok.eclipse.handlers.EclipseHandlerUtil.*; -import static lombok.eclipse.Eclipse.*; - -import java.lang.reflect.Field; - import org.eclipse.jdt.internal.compiler.ast.Annotation; import org.eclipse.jdt.internal.compiler.ast.Expression; import org.eclipse.jdt.internal.compiler.ast.ForeachStatement; @@ -43,6 +38,11 @@ import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; import org.eclipse.jdt.internal.compiler.lookup.TypeConstants; import org.eclipse.jdt.internal.compiler.lookup.TypeIds; +import java.lang.reflect.Field; + +import static lombok.eclipse.Eclipse.poss; +import static lombok.eclipse.handlers.EclipseHandlerUtil.makeType; + public class PatchVal { // This is half of the work for 'val' support - the other half is in PatchValEclipse. This half is enough for ecj. @@ -84,31 +84,44 @@ public class PatchVal { return true; } - public static boolean couldBeVal(TypeReference ref) { + public static boolean couldBe(String key, TypeReference ref) { + String[] keyParts = key.split("\\."); if (ref instanceof SingleTypeReference) { char[] token = ((SingleTypeReference)ref).token; - return matches("val", token); + return matches(keyParts[keyParts.length - 1], token); } if (ref instanceof QualifiedTypeReference) { char[][] tokens = ((QualifiedTypeReference)ref).tokens; - if (tokens == null || tokens.length != 2) return false; - return matches("lombok", tokens[0]) && matches("val", tokens[1]); + if (keyParts.length != tokens.length) return false; + for(int i = 0; i < tokens.length; ++i) { + String part = keyParts[i]; + char[] token = tokens[i]; + if (!matches(part, token)) return false; + } + return true; } return false; } - - private static boolean isVal(TypeReference ref, BlockScope scope) { - if (!couldBeVal(ref)) return false; - + + private static boolean is(TypeReference ref, BlockScope scope, String key) { + if (!couldBe(key, ref)) return false; + TypeBinding resolvedType = ref.resolvedType; if (resolvedType == null) resolvedType = ref.resolveType(scope, false); if (resolvedType == null) return false; char[] pkg = resolvedType.qualifiedPackageName(); char[] nm = resolvedType.qualifiedSourceName(); - return matches("lombok", pkg) && matches("val", nm); + int pkgFullLength = pkg.length > 0 ? pkg.length + 1: 0; + char[] fullName = new char[pkgFullLength + nm.length]; + if(pkg.length > 0) { + System.arraycopy(pkg, 0, fullName, 0, pkg.length); + fullName[pkg.length] = '.'; + } + System.arraycopy(nm, 0, fullName, pkgFullLength, nm.length); + return matches(key, fullName); } public static final class Reflection { @@ -132,13 +145,17 @@ public class PatchVal { if (local == null || !LocalDeclaration.class.equals(local.getClass())) return false; boolean decomponent = false; - if (!isVal(local.type, scope)) return false; + boolean val = isVal(local, scope); + boolean var = isVar(local, scope); + if (!(val || var)) return false; StackTraceElement[] st = new Throwable().getStackTrace(); for (int i = 0; i < st.length - 2 && i < 10; i++) { if (st[i].getClassName().equals("lombok.launch.PatchFixesHider$Val")) { - if (st[i + 1].getClassName().equals("org.eclipse.jdt.internal.compiler.ast.LocalDeclaration") && - st[i + 2].getClassName().equals("org.eclipse.jdt.internal.compiler.ast.ForStatement")) return false; + boolean valInForStatement = val && + st[i + 1].getClassName().equals("org.eclipse.jdt.internal.compiler.ast.LocalDeclaration") && + st[i + 2].getClassName().equals("org.eclipse.jdt.internal.compiler.ast.ForStatement"); + if (valInForStatement) return false; break; } } @@ -187,23 +204,33 @@ public class PatchVal { } } - local.modifiers |= ClassFileConstants.AccFinal; + if(val) local.modifiers |= ClassFileConstants.AccFinal; local.annotations = addValAnnotation(local.annotations, local.type, scope); local.type = replacement != null ? replacement : new QualifiedTypeReference(TypeConstants.JAVA_LANG_OBJECT, poss(local.type, 3)); return false; } + private static boolean isVar(LocalDeclaration local, BlockScope scope) { + return is(local.type, scope, "lombok.experimental.var"); + } + + private static boolean isVal(LocalDeclaration local, BlockScope scope) { + return is(local.type, scope, "lombok.val"); + } + public static boolean handleValForForEach(ForeachStatement forEach, BlockScope scope) { if (forEach.elementVariable == null) return false; - if (!isVal(forEach.elementVariable.type, scope)) return false; + boolean val = isVal(forEach.elementVariable, scope); + boolean var = isVar(forEach.elementVariable, scope); + if (!(val || var)) return false; TypeBinding component = getForEachComponentType(forEach.collection, scope); if (component == null) return false; TypeReference replacement = makeType(component, forEach.elementVariable.type, false); - forEach.elementVariable.modifiers |= ClassFileConstants.AccFinal; + if (val) forEach.elementVariable.modifiers |= ClassFileConstants.AccFinal; forEach.elementVariable.annotations = addValAnnotation(forEach.elementVariable.annotations, forEach.elementVariable.type, scope); forEach.elementVariable.type = replacement != null ? replacement : new QualifiedTypeReference(TypeConstants.JAVA_LANG_OBJECT, poss(forEach.elementVariable.type, 3)); diff --git a/src/eclipseAgent/lombok/eclipse/agent/PatchValEclipse.java b/src/eclipseAgent/lombok/eclipse/agent/PatchValEclipse.java index 7d5f36f4..505eb767 100644 --- a/src/eclipseAgent/lombok/eclipse/agent/PatchValEclipse.java +++ b/src/eclipseAgent/lombok/eclipse/agent/PatchValEclipse.java @@ -47,6 +47,7 @@ import org.eclipse.jdt.internal.compiler.ast.Annotation; import org.eclipse.jdt.internal.compiler.ast.ForeachStatement; import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration; import org.eclipse.jdt.internal.compiler.ast.SingleTypeReference; +import org.eclipse.jdt.internal.compiler.ast.TypeReference; import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; import org.eclipse.jdt.internal.compiler.parser.Parser; @@ -65,7 +66,9 @@ public class PatchValEclipse { ForeachStatement foreachDecl = (ForeachStatement) astStack[astPtr]; ASTNode init = foreachDecl.collection; if (init == null) return; - if (foreachDecl.elementVariable == null || !PatchVal.couldBeVal(foreachDecl.elementVariable.type)) return; + boolean val = couldBeVal(foreachDecl.elementVariable.type); + boolean var = couldBeVar(foreachDecl.elementVariable.type); + if (foreachDecl.elementVariable == null || !(val || var)) return; try { if (Reflection.iterableCopyField != null) Reflection.iterableCopyField.set(foreachDecl.elementVariable, init); @@ -88,7 +91,9 @@ public class PatchValEclipse { if (!(variableDecl instanceof LocalDeclaration)) return; ASTNode init = variableDecl.initialization; if (init == null) return; - if (!PatchVal.couldBeVal(variableDecl.type)) return; + boolean val = couldBeVal(variableDecl.type); + boolean var = couldBeVar(variableDecl.type); + if (!(val || var)) return; try { if (Reflection.initCopyField != null) Reflection.initCopyField.set(variableDecl, init); @@ -97,6 +102,10 @@ public class PatchValEclipse { } } + private static boolean couldBeVar(TypeReference type) { + return PatchVal.couldBe("lombok.experimental.var", type); + } + public static void addFinalAndValAnnotationToSingleVariableDeclaration(Object converter, SingleVariableDeclaration out, LocalDeclaration in) { @SuppressWarnings("unchecked") List<IExtendedModifier> modifiers = out.modifiers(); addFinalAndValAnnotationToModifierList(converter, modifiers, out.getAST(), in); @@ -115,7 +124,7 @@ public class PatchValEclipse { Annotation valAnnotation = null; for (Annotation ann : in.annotations) { - if (PatchVal.couldBeVal(ann.type)) { + if (couldBeVal(ann.type)) { found = true; valAnnotation = ann; break; @@ -167,6 +176,10 @@ public class PatchValEclipse { } } + private static boolean couldBeVal(TypeReference type) { + return PatchVal.couldBe("lombok.val", type); + } + public static Modifier createModifier(AST ast, ModifierKeyword keyword, int start, int end) { Modifier modifier = null; try { diff --git a/src/installer/lombok/installer/IdeLocation.java b/src/installer/lombok/installer/IdeLocation.java index 4e3a7e41..c3853867 100644 --- a/src/installer/lombok/installer/IdeLocation.java +++ b/src/installer/lombok/installer/IdeLocation.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2014 The Project Lombok Authors. + * Copyright (C) 2009-2016 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 @@ -25,7 +25,6 @@ import java.io.File; import java.io.IOException; import java.net.URL; -import lombok.installer.eclipse.EclipseFinder; import lombok.patcher.ClassRootFinder; /** @@ -46,7 +45,7 @@ public abstract class IdeLocation { * a jar that wasn't accessed via the file-system, or if its started via e.g. unpacking the jar. */ public static File findOurJar() { - return new File(ClassRootFinder.findClassRootOfClass(IdeFinder.class)); + return new File(ClassRootFinder.findClassRootOfClass(OsUtils.class)); } @Override public String toString() { @@ -70,7 +69,7 @@ public abstract class IdeLocation { private static final String LEGAL_PATH_CHARS_WINDOWS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-_/:\\ "; public static String escapePath(String path) { StringBuilder out = new StringBuilder(); - String legalChars = IdeFinder.getOS() == EclipseFinder.OS.UNIX ? LEGAL_PATH_CHARS : LEGAL_PATH_CHARS_WINDOWS; + String legalChars = OsUtils.getOS() == OsUtils.OS.UNIX ? LEGAL_PATH_CHARS : LEGAL_PATH_CHARS_WINDOWS; for (char c : path.toCharArray()) { if (legalChars.indexOf(c) == -1) out.append('\\'); out.append(c); diff --git a/src/installer/lombok/installer/IdeLocationProvider.java b/src/installer/lombok/installer/IdeLocationProvider.java index 933a5989..c4b64141 100644 --- a/src/installer/lombok/installer/IdeLocationProvider.java +++ b/src/installer/lombok/installer/IdeLocationProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 The Project Lombok Authors. + * Copyright (C) 2009-2016 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,20 +21,30 @@ */ package lombok.installer; +import java.util.List; import java.util.regex.Pattern; -import lombok.installer.IdeFinder.OS; - public interface IdeLocationProvider { /** * @throws CorruptedIdeLocationException * Only throw this exception if the location seems like a proper installation except there's something wrong with it. * Do not throw it (just return {@code null}) if there's nothing there or it looks absolutely nothing like your IDE. */ - public abstract IdeLocation create(String path) throws CorruptedIdeLocationException; + IdeLocation create(String path) throws CorruptedIdeLocationException; + + /** + * Return the usual name of the IDE executable or other obvious marker of an IDE installation on the current platform. + */ + Pattern getLocationSelectors(); /** - * Return the usual name of the IDE executable or other obvious marker of an IDE installation on the provided platform. + * Look for installations of your IDE in the usual places. + * + * @param locations Add to this list any valid locations that you found. + * @param problems + * Add to this list any locations that look like installations, + * but have problems that prevent you from installing/uninstalling from them. DONT add to this list + * any common locations that have no installation at all - only add near misses. */ - public abstract Pattern getLocationSelectors(OS os); + void findIdes(List<IdeLocation> locations, List<CorruptedIdeLocationException> problems); } diff --git a/src/installer/lombok/installer/Installer.java b/src/installer/lombok/installer/Installer.java index 7ae01d7a..94cc1a45 100644 --- a/src/installer/lombok/installer/Installer.java +++ b/src/installer/lombok/installer/Installer.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2010 The Project Lombok Authors. + * Copyright (C) 2009-2016 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 @@ -38,7 +38,7 @@ import lombok.Lombok; import lombok.core.LombokApp; import lombok.core.SpiLoadUtil; import lombok.core.Version; -import lombok.installer.IdeFinder.OS; +import lombok.installer.OsUtils.OS; import lombok.patcher.ClassRootFinder; import org.mangosdk.spi.ProviderFor; @@ -72,10 +72,9 @@ public class Installer { } static List<Pattern> getIdeExecutableNames() { - OS os = IdeFinder.getOS(); List<Pattern> list = new ArrayList<Pattern>(); for (IdeLocationProvider provider : locationProviders) { - Pattern p = provider.getLocationSelectors(os); + Pattern p = provider.getLocationSelectors(); if (p != null) list.add(p); } return list; @@ -91,12 +90,8 @@ public class Installer { } static void autoDiscover(List<IdeLocation> locations, List<CorruptedIdeLocationException> problems) { - try { - for (IdeFinder finder : SpiLoadUtil.findServices(IdeFinder.class)) { - finder.findIdes(locations, problems); - } - } catch (IOException e) { - throw Lombok.sneakyThrow(e); + for (IdeLocationProvider provider : locationProviders) { + provider.findIdes(locations, problems); } } @@ -160,7 +155,7 @@ public class Installer { } private static int guiInstaller() { - if (IdeFinder.getOS() == OS.MAC_OS_X) { + if (OsUtils.getOS() == OS.MAC_OS_X) { System.setProperty("com.apple.mrj.application.apple.menu.about.name", "Lombok Installer"); System.setProperty("com.apple.macos.use-file-dialog-packages", "true"); } diff --git a/src/installer/lombok/installer/InstallerGUI.java b/src/installer/lombok/installer/InstallerGUI.java index 6b8a58ab..ebdf2035 100644 --- a/src/installer/lombok/installer/InstallerGUI.java +++ b/src/installer/lombok/installer/InstallerGUI.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2010 The Project Lombok Authors. + * Copyright (C) 2009-2016 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 @@ -67,7 +67,7 @@ import javax.swing.SwingUtilities; import javax.swing.filechooser.FileFilter; import lombok.core.Version; -import lombok.installer.IdeFinder.OS; +import lombok.installer.OsUtils.OS; /** * The lombok GUI installer. @@ -313,7 +313,7 @@ public class InstallerGUI { final List<Pattern> exeNames = Installer.getIdeExecutableNames(); String file = null; - if (IdeFinder.getOS() == OS.MAC_OS_X) { + if (OsUtils.getOS() == OS.MAC_OS_X) { FileDialog chooser = new FileDialog(appWindow); chooser.setMode(FileDialog.LOAD); @@ -740,7 +740,7 @@ public class InstallerGUI { } catch (Exception e) { Runtime rt = Runtime.getRuntime(); try { - switch (IdeFinder.getOS()) { + switch (OsUtils.getOS()) { case WINDOWS: String[] cmd = new String[4]; cmd[0] = "cmd.exe"; @@ -781,7 +781,7 @@ public class InstallerGUI { */ public void show() { appWindow.setVisible(true); - if (IdeFinder.getOS() == OS.MAC_OS_X) { + if (OsUtils.getOS() == OS.MAC_OS_X) { try { AppleNativeLook.go(); } catch (Throwable ignore) { diff --git a/src/installer/lombok/installer/IdeFinder.java b/src/installer/lombok/installer/OsUtils.java index f68a0e4c..2da7de09 100644 --- a/src/installer/lombok/installer/IdeFinder.java +++ b/src/installer/lombok/installer/OsUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2011 The Project Lombok Authors. + * Copyright (C) 2009-2016 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 @@ -34,9 +34,13 @@ import lombok.core.Version; /** * Implement and provide this class to add auto-finding a certain brand of IDEs to the lombok installer. */ -public abstract class IdeFinder { +public final class OsUtils { private static final AtomicBoolean windowsDriveInfoLibLoaded = new AtomicBoolean(false); + private OsUtils() { + // Prevent instantiation + } + private static void loadWindowsDriveInfoLib() throws IOException { if (!windowsDriveInfoLibLoaded.compareAndSet(false, true)) return; @@ -63,7 +67,7 @@ public abstract class IdeFinder { } private static boolean unpackDLL(String dllName, File target) throws IOException { - InputStream in = IdeFinder.class.getResourceAsStream(dllName); + InputStream in = OsUtils.class.getResourceAsStream(dllName); try { try { FileOutputStream out = new FileOutputStream(target); @@ -130,15 +134,4 @@ public abstract class IdeFinder { return OS.UNIX; } - - /** - * Look for installations of your IDE in the usual places. - * - * @param locations Add to this list any valid locations that you found. - * @param problems - * Add to this list any locations that look like installations, - * but have problems that prevent you from installing/uninstalling from them. DONT add to this list - * any common locations that have no installation at all - only add near misses. - */ - public abstract void findIdes(List<IdeLocation> locations, List<CorruptedIdeLocationException> problems); } diff --git a/src/installer/lombok/installer/eclipse/EclipseLocationProvider.java b/src/installer/lombok/installer/eclipse/EclipseLocationProvider.java index 29716a1f..fa2ce958 100644 --- a/src/installer/lombok/installer/eclipse/EclipseLocationProvider.java +++ b/src/installer/lombok/installer/eclipse/EclipseLocationProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2011 The Project Lombok Authors. + * Copyright (C) 2009-2016 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,145 +21,24 @@ */ package lombok.installer.eclipse; -import static lombok.installer.IdeLocation.canonical; +import java.util.Collections; -import java.io.File; -import java.io.IOException; -import java.util.Arrays; -import java.util.List; -import java.util.regex.Pattern; - -import lombok.installer.IdeLocation; import lombok.installer.IdeLocationProvider; -import lombok.installer.CorruptedIdeLocationException; -import lombok.installer.IdeFinder.OS; import org.mangosdk.spi.ProviderFor; @ProviderFor(IdeLocationProvider.class) -public class EclipseLocationProvider implements IdeLocationProvider { - @Override public IdeLocation create(String path) throws CorruptedIdeLocationException { - return create0(path); - } - - protected List<String> getEclipseExecutableNames() { - return Arrays.asList("eclipse.app", "eclipse.exe", "eclipse"); - } - - protected String getIniName() { - return "eclipse.ini"; - } - - protected IdeLocation makeLocation(String name, File ini) throws CorruptedIdeLocationException { - return new EclipseLocation(name, ini); - } - - protected String getMacAppName() { - return "Eclipse.app"; - } - - protected String getUnixAppName() { - return "eclipse"; - } - - /** - * Create a new EclipseLocation by pointing at either the directory contains the Eclipse executable, or the executable itself, - * or an eclipse.ini file. - * - * @throws NotAnIdeLocationException - * If this isn't an Eclipse executable or a directory with an - * Eclipse executable. - */ - protected IdeLocation create0(String path) throws CorruptedIdeLocationException { - if (path == null) throw new NullPointerException("path"); - File p = new File(path); - - if (!p.exists()) return null; - if (p.isDirectory()) { - for (String possibleExeName : getEclipseExecutableNames()) { - File f = new File(p, possibleExeName); - if (f.exists()) return findEclipseIniFromExe(f, 0); - } - - File f = new File(p, getIniName()); - if (f.exists()) return new EclipseLocation(canonical(p), f); - } - - if (p.isFile()) { - if (p.getName().equalsIgnoreCase(getIniName())) { - return new EclipseLocation(canonical(p.getParentFile()), p); - } - } - - if (getEclipseExecutableNames().contains(p.getName().toLowerCase())) { - return findEclipseIniFromExe(p, 0); - } - - return null; - } - - private IdeLocation findEclipseIniFromExe(File exePath, int loopCounter) throws CorruptedIdeLocationException { - /* Try looking for eclipse.ini as sibling to the executable */ { - File ini = new File(exePath.getParentFile(), getIniName()); - if (ini.isFile()) return makeLocation(canonical(exePath), ini); - } - - /* Try looking for Eclipse.app/Contents/MacOS/eclipse.ini as sibling to executable; this works on Mac OS X. */ { - File ini = new File(exePath.getParentFile(), getMacAppName() + "/Contents/MacOS/" + getIniName()); - if (ini.isFile()) return makeLocation(canonical(exePath), ini); - } - - /* Starting with Eclipse Mars (with the oomph installer), the structure has changed, and it's now at Eclipse.app/Contents/Eclipse/eclipse.ini*/ { - File ini = new File(exePath.getParentFile(), getMacAppName() + "/Contents/Eclipse/" + getIniName()); - if (ini.isFile()) return makeLocation(canonical(exePath), ini); - } - - /* If executable is a soft link, follow it and retry. */ { - if (loopCounter < 50) { - try { - String oPath = exePath.getAbsolutePath(); - String nPath = exePath.getCanonicalPath(); - if (!oPath.equals(nPath)) try { - IdeLocation loc = findEclipseIniFromExe(new File(nPath), loopCounter + 1); - if (loc != null) return loc; - } catch (CorruptedIdeLocationException ignore) { - // Unlinking didn't help find an eclipse, so continue. - } - } catch (IOException ignore) { /* okay, that didn't work, assume it isn't a soft link then. */ } - } - } - - /* If executable is a linux LSB-style path, then look in the usual places that package managers like apt-get use.*/ { - String path = exePath.getAbsolutePath(); - try { - path = exePath.getCanonicalPath(); - } catch (IOException ignore) { /* We'll stick with getAbsolutePath()'s result then. */ } - - if (path.equals("/usr/bin/" + getUnixAppName()) || path.equals("/bin/" + getUnixAppName()) || path.equals("/usr/local/bin/" + getUnixAppName())) { - File ini = new File("/usr/lib/" + getUnixAppName() + "/" + getIniName()); - if (ini.isFile()) return makeLocation(path, ini); - ini = new File("/usr/local/lib/" + getUnixAppName() + "/" + getIniName()); - if (ini.isFile()) return makeLocation(path, ini); - ini = new File("/usr/local/etc/" + getUnixAppName() + "/" + getIniName()); - if (ini.isFile()) return makeLocation(path, ini); - ini = new File("/etc/" + getIniName()); - if (ini.isFile()) return makeLocation(path, ini); - } - } - - /* If we get this far, we lose. */ - return null; - } - - @Override public Pattern getLocationSelectors(OS os) { - switch (os) { - case MAC_OS_X: - return Pattern.compile("^(eclipse|eclipse\\.ini|eclipse\\.app)$", Pattern.CASE_INSENSITIVE); - case WINDOWS: - return Pattern.compile("^(eclipse\\.exe|eclipse\\.ini)$", Pattern.CASE_INSENSITIVE); - default: - case UNIX: - return Pattern.compile("^(eclipse|eclipse\\.ini)$", Pattern.CASE_INSENSITIVE); - } +public class EclipseLocationProvider extends EclipseProductLocationProvider { + + private static final EclipseProductDescriptor ECLIPSE = new StandardProductDescriptor( + "Eclipse", + "eclipse", + "eclipse", + EclipseLocationProvider.class.getResource("eclipse.png"), + Collections.<String>emptySet() + ); + + public EclipseLocationProvider() { + super(ECLIPSE); } } diff --git a/src/installer/lombok/installer/eclipse/STSLocation.java b/src/installer/lombok/installer/eclipse/EclipseProductDescriptor.java index 40ade40a..8f736a57 100644 --- a/src/installer/lombok/installer/eclipse/STSLocation.java +++ b/src/installer/lombok/installer/eclipse/EclipseProductDescriptor.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 The Project Lombok Authors. + * Copyright (C) 2016 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,25 +21,21 @@ */ package lombok.installer.eclipse; -import java.io.File; import java.net.URL; +import java.util.List; +import java.util.regex.Pattern; -import lombok.installer.CorruptedIdeLocationException; - -public class STSLocation extends EclipseLocation { - public STSLocation(String nameOfLocation, File pathToEclipseIni) throws CorruptedIdeLocationException { - super(nameOfLocation, pathToEclipseIni); - } - - @Override public URL getIdeIcon() { - return STSLocation.class.getResource("STS.png"); - } - - @Override protected String getIniFileName() { - return "STS.ini"; - } - - @Override protected String getTypeName() { - return "STS"; - } -} +public interface EclipseProductDescriptor { + String getProductName(); + String getWindowsExecutableName(); + String getUnixAppName(); + String getMacAppName(); + String getDirectoryName(); + List<String> getExecutableNames(); + List<String> getSourceDirsOnWindows(); + List<String> getSourceDirsOnMac(); + List<String> getSourceDirsOnUnix(); + String getIniFileName(); + Pattern getLocationSelectors(); + URL getIdeIcon(); +}
\ No newline at end of file diff --git a/src/installer/lombok/installer/eclipse/EclipseLocation.java b/src/installer/lombok/installer/eclipse/EclipseProductLocation.java index 6c63c48d..886e3e85 100644 --- a/src/installer/lombok/installer/eclipse/EclipseLocation.java +++ b/src/installer/lombok/installer/eclipse/EclipseProductLocation.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2012 The Project Lombok Authors. + * Copyright (C) 2009-2016 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 @@ -35,7 +35,7 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; import lombok.installer.CorruptedIdeLocationException; -import lombok.installer.IdeFinder; +import lombok.installer.OsUtils; import lombok.installer.IdeLocation; import lombok.installer.InstallException; import lombok.installer.Installer; @@ -46,23 +46,18 @@ import lombok.installer.UninstallException; * An instance can figure out if an Eclipse installation has been lombok-ified, and can * install and uninstall lombok from the Eclipse installation. */ -public class EclipseLocation extends IdeLocation { +public final class EclipseProductLocation extends IdeLocation { + + private static final String OS_NEWLINE = OsUtils.getOS().getLineEnding(); + + private final EclipseProductDescriptor descriptor; private final String name; private final File eclipseIniPath; private final String pathToLombokJarPrefix; - private volatile boolean hasLombok; - - private static final String OS_NEWLINE = IdeFinder.getOS().getLineEnding(); - - protected String getTypeName() { - return "eclipse"; - } - - protected String getIniFileName() { - return "eclipse.ini"; - } + private final boolean hasLombok; - EclipseLocation(String nameOfLocation, File pathToEclipseIni) throws CorruptedIdeLocationException { + EclipseProductLocation(EclipseProductDescriptor descriptor, String nameOfLocation, File pathToEclipseIni) throws CorruptedIdeLocationException { + this.descriptor = descriptor; this.name = nameOfLocation; this.eclipseIniPath = pathToEclipseIni; File p1 = pathToEclipseIni.getParentFile(); @@ -78,8 +73,8 @@ public class EclipseLocation extends IdeLocation { this.hasLombok = checkForLombok(eclipseIniPath); } catch (IOException e) { throw new CorruptedIdeLocationException( - "I can't read the configuration file of the " + getTypeName() + " installed at " + name + "\n" + - "You may need to run this installer with root privileges if you want to modify that " + getTypeName() + ".", getTypeName(), e); + "I can't read the configuration file of the " + descriptor.getProductName() + " installed at " + name + "\n" + + "You may need to run this installer with root privileges if you want to modify that " + descriptor.getProductName() + ".", descriptor.getProductName(), e); } } @@ -88,8 +83,8 @@ public class EclipseLocation extends IdeLocation { } @Override public boolean equals(Object o) { - if (!(o instanceof EclipseLocation)) return false; - return ((EclipseLocation)o).eclipseIniPath.equals(eclipseIniPath); + if (!(o instanceof EclipseProductLocation)) return false; + return ((EclipseProductLocation)o).eclipseIniPath.equals(eclipseIniPath); } /** @@ -108,13 +103,13 @@ public class EclipseLocation extends IdeLocation { return hasLombok; } - private final Pattern JAVA_AGENT_LINE_MATCHER = Pattern.compile( + private static final Pattern JAVA_AGENT_LINE_MATCHER = Pattern.compile( "^\\-javaagent\\:.*lombok.*\\.jar$", Pattern.CASE_INSENSITIVE); - private final Pattern BOOTCLASSPATH_LINE_MATCHER = Pattern.compile( + private static final Pattern BOOTCLASSPATH_LINE_MATCHER = Pattern.compile( "^\\-Xbootclasspath\\/a\\:(.*lombok.*\\.jar.*)$", Pattern.CASE_INSENSITIVE); - private boolean checkForLombok(File iniFile) throws IOException { + private static boolean checkForLombok(File iniFile) throws IOException { if (!iniFile.exists()) return false; FileInputStream fis = new FileInputStream(iniFile); try { @@ -206,7 +201,7 @@ public class EclipseLocation extends IdeLocation { File lombokJar = new File(dir, "lombok.jar"); if (lombokJar.exists()) { if (!lombokJar.delete()) { - if (IdeFinder.getOS() == IdeFinder.OS.WINDOWS && Installer.isSelf(lombokJar.getAbsolutePath())) { + if (OsUtils.getOS() == OsUtils.OS.WINDOWS && Installer.isSelf(lombokJar.getAbsolutePath())) { lombokJarsForWhichCantDeleteSelf.add(lombokJar); } else { throw new UninstallException( @@ -228,14 +223,14 @@ public class EclipseLocation extends IdeLocation { throw new UninstallException(true, String.format( "lombok.jar cannot delete itself on windows.\nHowever, lombok has been uncoupled from your %s.\n" + "You can safely delete this jar file. You can find it at:\n%s", - getTypeName(), lombokJarsForWhichCantDeleteSelf.get(0).getAbsolutePath()), null); + descriptor.getProductName(), lombokJarsForWhichCantDeleteSelf.get(0).getAbsolutePath()), null); } } private static String generateWriteErrorMessage() { String osSpecificError; - switch (IdeFinder.getOS()) { + switch (OsUtils.getOS()) { default: case MAC_OS_X: case UNIX: @@ -265,7 +260,7 @@ public class EclipseLocation extends IdeLocation { // If someone knows how to fix this, please do so, as this current hack solution (putting the absolute path // to the jar files in your eclipse.ini) means you can't move your eclipse around on linux without lombok // breaking it. NB: rerunning lombok.jar installer and hitting 'update' will fix it if you do that. - boolean fullPathRequired = IdeFinder.getOS() == EclipseFinder.OS.UNIX || System.getProperty("lombok.installer.fullpath") != null; + boolean fullPathRequired = OsUtils.getOS() == OsUtils.OS.UNIX || System.getProperty("lombok.installer.fullpath") != null; boolean installSucceeded = false; StringBuilder newContents = new StringBuilder(); @@ -303,7 +298,7 @@ public class EclipseLocation extends IdeLocation { "I can't read my own jar file. I think you've found a bug in this installer!\nI suggest you restart it " + "and use the 'what do I do' link, to manually install lombok. Also, tell us about this at:\n" + "http://groups.google.com/group/project-lombok - Thanks!", e); - throw new InstallException("I can't write to your " + getTypeName() + " directory at " + name + generateWriteErrorMessage(), e); + throw new InstallException("I can't write to your " + descriptor.getProductName() + " directory at " + name + generateWriteErrorMessage(), e); } } @@ -369,14 +364,14 @@ public class EclipseLocation extends IdeLocation { } if (!installSucceeded) { - throw new InstallException("I can't find the " + getIniFileName() + " file. Is this a real " + getTypeName() + " installation?", null); + throw new InstallException("I can't find the " + descriptor.getIniFileName() + " file. Is this a real " + descriptor.getProductName() + " installation?", null); } - return "If you start " + getTypeName() + " with a custom -vm parameter, you'll need to add:<br>" + + return "If you start " + descriptor.getProductName() + " with a custom -vm parameter, you'll need to add:<br>" + "<code>-vmargs -javaagent:lombok.jar</code><br>as parameter as well."; } @Override public URL getIdeIcon() { - return EclipseLocation.class.getResource("eclipse.png"); + return descriptor.getIdeIcon(); } } diff --git a/src/installer/lombok/installer/eclipse/EclipseFinder.java b/src/installer/lombok/installer/eclipse/EclipseProductLocationProvider.java index 8a1a689a..3710d7d9 100644 --- a/src/installer/lombok/installer/eclipse/EclipseFinder.java +++ b/src/installer/lombok/installer/eclipse/EclipseProductLocationProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2011 The Project Lombok Authors. + * Copyright (C) 2009-2016 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 @@ -22,109 +22,130 @@ package lombok.installer.eclipse; import static java.util.Arrays.asList; +import static lombok.installer.IdeLocation.canonical; import java.io.File; +import java.io.IOException; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; import java.util.List; +import java.util.regex.Pattern; -import lombok.installer.IdeFinder; -import lombok.installer.IdeLocation; import lombok.installer.CorruptedIdeLocationException; +import lombok.installer.OsUtils; +import lombok.installer.IdeLocation; +import lombok.installer.IdeLocationProvider; -import org.mangosdk.spi.ProviderFor; +public class EclipseProductLocationProvider implements IdeLocationProvider { + private final EclipseProductDescriptor descriptor; -@ProviderFor(IdeFinder.class) -public class EclipseFinder extends IdeFinder { - /** should be lowercase! */ - protected String getDirName() { - return "eclipse"; - } - - protected String getWindowsExecutableName() { - return "eclipse.exe"; - } - - protected String getUnixExecutableName() { - return "eclipse"; - } - - protected String getMacExecutableName() { - return "Eclipse.app"; + EclipseProductLocationProvider(EclipseProductDescriptor descriptor) { + this.descriptor = descriptor; } - protected IdeLocation createLocation(String guess) throws CorruptedIdeLocationException { - return new EclipseLocationProvider().create0(guess); - } - - protected List<String> getSourceDirsOnWindows() { - return Arrays.asList("\\", "\\Program Files", "\\Program Files (x86)", System.getProperty("user.home", ".")); + @Override public final IdeLocation create(String path) throws CorruptedIdeLocationException { + return create0(path); } /** - * Returns a list of paths of Eclipse installations. + * Create a new EclipseLocation by pointing at either the directory contains the Eclipse executable, or the executable itself, + * or an eclipse.ini file. * - * The search process works by scanning for each 'source dir' for either an eclipse installation or a folder containing the text returned - * by getDirName(). If such a folder is found, this process is applied recursively. On windows, this process is run on each drive letter - * which represents a physical hard disk. If the native windows API call to determine these drive letters fails, only 'C:' is checked. + * @throws NotAnIdeLocationException + * If this isn't an Eclipse executable or a directory with an + * Eclipse executable. */ - private List<String> getSourceDirsOnWindowsWithDriveLetters() { - List<String> driveLetters = asList("C"); - try { - driveLetters = getDrivesOnWindows(); - } catch (Throwable ignore) { - ignore.printStackTrace(); + private IdeLocation create0(String path) throws CorruptedIdeLocationException { + if (path == null) throw new NullPointerException("path"); + String iniName = descriptor.getIniFileName(); + File p = new File(path); + + if (!p.exists()) return null; + if (p.isDirectory()) { + for (String possibleExeName : descriptor.getExecutableNames()) { + File f = new File(p, possibleExeName); + if (f.exists()) return findEclipseIniFromExe(f, 0); + } + + File f = new File(p, iniName); + if (f.exists()) return makeLocation(canonical(p), f); } - List<String> sourceDirs = new ArrayList<String>(); - for (String letter : driveLetters) { - for (String possibleSource : getSourceDirsOnWindows()) { - if (!isDriveSpecificOnWindows(possibleSource)) { - sourceDirs.add(letter + ":" + possibleSource); - } + + if (p.isFile()) { + if (p.getName().equalsIgnoreCase(iniName)) { + return makeLocation(canonical(p.getParentFile()), p); } } - for (String possibleSource : getSourceDirsOnWindows()) { - if (isDriveSpecificOnWindows(possibleSource)) sourceDirs.add(possibleSource); + + if (descriptor.getExecutableNames().contains(p.getName().toLowerCase())) { + return findEclipseIniFromExe(p, 0); } - return sourceDirs; + return null; } - public boolean isDriveSpecificOnWindows(String path) { - return path.length() > 1 && path.charAt(1) == ':'; - } - - protected List<String> getSourceDirsOnMac() { - return Arrays.asList("/Applications", System.getProperty("user.home", ".")); - } - - protected List<String> getSourceDirsOnUnix() { - return Arrays.asList(System.getProperty("user.home", ".")); - } - - private List<File> transformToFiles(List<String> fileNames) { - List<File> files = new ArrayList<File>(); - for (String fileName : fileNames) { - files.add(new File(fileName)); + private IdeLocation findEclipseIniFromExe(File exePath, int loopCounter) throws CorruptedIdeLocationException { + String iniName = descriptor.getIniFileName(); + /* Try looking for eclipse.ini as sibling to the executable */ { + File ini = new File(exePath.getParentFile(), iniName); + if (ini.isFile()) return makeLocation(canonical(exePath), ini); } - return files; + + String macAppName = descriptor.getMacAppName(); + /* Try looking for Eclipse.app/Contents/MacOS/eclipse.ini as sibling to executable; this works on Mac OS X. */ { + File ini = new File(exePath.getParentFile(), macAppName + "/Contents/MacOS/" + iniName); + if (ini.isFile()) return makeLocation(canonical(exePath), ini); + } + + /* Starting with Eclipse Mars (with the oomph installer), the structure has changed, and it's now at Eclipse.app/Contents/Eclipse/eclipse.ini*/ { + File ini = new File(exePath.getParentFile(), macAppName + "/Contents/Eclipse/" + iniName); + if (ini.isFile()) return makeLocation(canonical(exePath), ini); + } + + /* If executable is a soft link, follow it and retry. */ { + if (loopCounter < 50) { + try { + String oPath = exePath.getAbsolutePath(); + String nPath = exePath.getCanonicalPath(); + if (!oPath.equals(nPath)) try { + IdeLocation loc = findEclipseIniFromExe(new File(nPath), loopCounter + 1); + if (loc != null) return loc; + } catch (CorruptedIdeLocationException ignore) { + // Unlinking didn't help find an eclipse, so continue. + } + } catch (IOException ignore) { /* okay, that didn't work, assume it isn't a soft link then. */ } + } + } + + /* If executable is a linux LSB-style path, then look in the usual places that package managers like apt-get use.*/ { + String path = exePath.getAbsolutePath(); + try { + path = exePath.getCanonicalPath(); + } catch (IOException ignore) { /* We'll stick with getAbsolutePath()'s result then. */ } + + String unixAppName = descriptor.getUnixAppName(); + if (path.equals("/usr/bin/" + unixAppName) || path.equals("/bin/" + unixAppName) || path.equals("/usr/local/bin/" + unixAppName)) { + File ini = new File("/usr/lib/" + unixAppName + "/" + iniName); + if (ini.isFile()) return makeLocation(path, ini); + ini = new File("/usr/local/lib/" + unixAppName + "/" + iniName); + if (ini.isFile()) return makeLocation(path, ini); + ini = new File("/usr/local/etc/" + unixAppName + "/" + iniName); + if (ini.isFile()) return makeLocation(path, ini); + ini = new File("/etc/" + iniName); + if (ini.isFile()) return makeLocation(path, ini); + } + } + + /* If we get this far, we lose. */ + return null; } - private List<File> getFlatSourceLocationsOnUnix() { - List<File> dirs = new ArrayList<File>(); - dirs.add(new File("/usr/bin/")); - dirs.add(new File("/usr/local/bin/")); - dirs.add(new File(System.getProperty("user.home", "."), "bin/")); - return dirs; + private IdeLocation makeLocation(String name, File ini) throws CorruptedIdeLocationException { + return new EclipseProductLocation(descriptor, name, ini); } - private List<File> getNestedSourceLocationOnUnix() { - List<File> dirs = new ArrayList<File>(); - dirs.add(new File("/usr/local/share")); - dirs.add(new File("/usr/local")); - dirs.add(new File("/usr/share")); - return dirs; + @Override public Pattern getLocationSelectors() { + return descriptor.getLocationSelectors(); } /** @@ -141,7 +162,7 @@ public class EclipseFinder extends IdeFinder { */ @Override public void findIdes(List<IdeLocation> locations, List<CorruptedIdeLocationException> problems) { - switch (getOS()) { + switch (OsUtils.getOS()) { case WINDOWS: new WindowsFinder().findEclipse(locations, problems); break; @@ -155,17 +176,74 @@ public class EclipseFinder extends IdeFinder { } } + private List<File> transformToFiles(List<String> fileNames) { + List<File> files = new ArrayList<File>(); + for (String fileName : fileNames) { + files.add(new File(fileName)); + } + return files; + } + + private List<File> getFlatSourceLocationsOnUnix() { + List<File> dirs = new ArrayList<File>(); + dirs.add(new File("/usr/bin/")); + dirs.add(new File("/usr/local/bin/")); + dirs.add(new File(System.getProperty("user.home", "."), "bin/")); + return dirs; + } + + private List<File> getNestedSourceLocationOnUnix() { + List<File> dirs = new ArrayList<File>(); + dirs.add(new File("/usr/local/share")); + dirs.add(new File("/usr/local")); + dirs.add(new File("/usr/share")); + return dirs; + } + private class UnixFinder extends DirectoryFinder { UnixFinder() { super(getNestedSourceLocationOnUnix(), getFlatSourceLocationsOnUnix()); } @Override protected String findEclipseOnPlatform(File dir) { - File possible = new File(dir, getUnixExecutableName()); + File possible = new File(dir, descriptor.getUnixAppName()); return (possible.exists()) ? possible.getAbsolutePath() : null; } } + /** + * Returns a list of paths of Eclipse installations. + * + * The search process works by scanning for each 'source dir' for either an eclipse installation or a folder containing the text returned + * by getDirName(). If such a folder is found, this process is applied recursively. On windows, this process is run on each drive letter + * which represents a physical hard disk. If the native windows API call to determine these drive letters fails, only 'C:' is checked. + */ + private List<String> getSourceDirsOnWindowsWithDriveLetters() { + List<String> driveLetters = asList("C"); + try { + driveLetters = OsUtils.getDrivesOnWindows(); + } catch (Throwable ignore) { + ignore.printStackTrace(); + } + List<String> sourceDirs = new ArrayList<String>(); + for (String letter : driveLetters) { + for (String possibleSource : descriptor.getSourceDirsOnWindows()) { + if (!isDriveSpecificOnWindows(possibleSource)) { + sourceDirs.add(letter + ":" + possibleSource); + } + } + } + for (String possibleSource : descriptor.getSourceDirsOnWindows()) { + if (isDriveSpecificOnWindows(possibleSource)) sourceDirs.add(possibleSource); + } + + return sourceDirs; + } + + private boolean isDriveSpecificOnWindows(String path) { + return path.length() > 1 && path.charAt(1) == ':'; + } + private class WindowsFinder extends DirectoryFinder { WindowsFinder() { super(transformToFiles(getSourceDirsOnWindowsWithDriveLetters()), Collections.<File>emptyList()); @@ -174,20 +252,20 @@ public class EclipseFinder extends IdeFinder { /** Checks if the provided directory contains 'eclipse.exe', and if so, returns the directory, otherwise null. */ @Override protected String findEclipseOnPlatform(File dir) { - File possible = new File(dir, getWindowsExecutableName()); + File possible = new File(dir, descriptor.getWindowsExecutableName()); return (possible.isFile()) ? dir.getAbsolutePath() : null; } } private class MacFinder extends DirectoryFinder { MacFinder() { - super(transformToFiles(getSourceDirsOnMac()), Collections.<File>emptyList()); + super(transformToFiles(descriptor.getSourceDirsOnMac()), Collections.<File>emptyList()); } protected String findEclipseOnPlatform(File dir) { - if (dir.getName().toLowerCase().equals(getMacExecutableName().toLowerCase())) return dir.getParent(); - if (dir.getName().toLowerCase().contains(getDirName())) { - if (new File(dir, getMacExecutableName()).exists()) return dir.toString(); + if (dir.getName().toLowerCase().equals(descriptor.getMacAppName().toLowerCase())) return dir.getParent(); + if (dir.getName().toLowerCase().contains(descriptor.getDirectoryName())) { + if (new File(dir, descriptor.getMacAppName()).exists()) return dir.toString(); } return null; } @@ -202,14 +280,14 @@ public class EclipseFinder extends IdeFinder { this.flatSourceDirs = flatSourceDirs; } - public void findEclipse(List<IdeLocation> locations, List<CorruptedIdeLocationException> problems) { + void findEclipse(List<IdeLocation> locations, List<CorruptedIdeLocationException> problems) { for (File dir : nestedSourceDirs) recurseDirectory(locations, problems, dir); for (File dir : flatSourceDirs) findEclipse(locations, problems, dir); } - protected abstract String findEclipseOnPlatform(File dir); + abstract String findEclipseOnPlatform(File dir); - protected void recurseDirectory(List<IdeLocation> locations, List<CorruptedIdeLocationException> problems, File dir) { + void recurseDirectory(List<IdeLocation> locations, List<CorruptedIdeLocationException> problems, File dir) { recurseDirectory0(locations, problems, dir, 0); } @@ -223,19 +301,19 @@ public class EclipseFinder extends IdeFinder { for (File dir : listFiles) { if (!dir.isDirectory()) continue; try { - if (dir.getName().toLowerCase().contains(getDirName())) { + if (dir.getName().toLowerCase().contains(descriptor.getDirectoryName())) { findEclipse(locations, problems, dir); if (loopCounter < 50) recurseDirectory0(locations, problems, dir, loopCounter + 1); } } catch (Exception ignore) {} } } - + private void findEclipse(List<IdeLocation> locations, List<CorruptedIdeLocationException> problems, File dir) { String eclipseLocation = findEclipseOnPlatform(dir); if (eclipseLocation != null) { try { - IdeLocation newLocation = createLocation(eclipseLocation); + IdeLocation newLocation = create(eclipseLocation); if (newLocation != null) locations.add(newLocation); } catch (CorruptedIdeLocationException e) { problems.add(e); diff --git a/src/installer/lombok/installer/eclipse/JbdsFinder.java b/src/installer/lombok/installer/eclipse/JbdsFinder.java deleted file mode 100644 index 2dfaacba..00000000 --- a/src/installer/lombok/installer/eclipse/JbdsFinder.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (C) 2013 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.installer.eclipse; - -import java.util.Arrays; -import java.util.List; - -import lombok.installer.CorruptedIdeLocationException; -import lombok.installer.IdeFinder; -import lombok.installer.IdeLocation; - -import org.mangosdk.spi.ProviderFor; - -/** - * JBDS (JBoss Developer Studio) is an eclipse variant. - * Other than different executable names, it's the same as eclipse, as far as lombok support goes. - */ -@ProviderFor(IdeFinder.class) -public class JbdsFinder extends EclipseFinder { - @Override protected IdeLocation createLocation(String guess) throws CorruptedIdeLocationException { - return new JbdsLocationProvider().create0(guess); - } - - @Override protected String getDirName() { - return "studio"; - } - - @Override protected String getMacExecutableName() { - return "jbdevstudio.app"; - } - - @Override protected String getUnixExecutableName() { - return "jbdevstudio"; - } - - @Override protected String getWindowsExecutableName() { - return "jbdevstudio.exe"; - } - - @Override protected List<String> getSourceDirsOnWindows() { - return Arrays.asList("\\", "\\Program Files", "\\Program Files (x86)", System.getProperty("user.home", ".")); - } - - @Override protected List<String> getSourceDirsOnMac() { - return Arrays.asList("/Applications", System.getProperty("user.home", ".")); - } - - @Override protected List<String> getSourceDirsOnUnix() { - return Arrays.asList(System.getProperty("user.home", ".")); - } -} diff --git a/src/installer/lombok/installer/eclipse/JbdsLocationProvider.java b/src/installer/lombok/installer/eclipse/JbdsLocationProvider.java index e6df0e43..635f304a 100644 --- a/src/installer/lombok/installer/eclipse/JbdsLocationProvider.java +++ b/src/installer/lombok/installer/eclipse/JbdsLocationProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 The Project Lombok Authors. + * Copyright (C) 2013-2016 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,49 +21,24 @@ */ package lombok.installer.eclipse; -import java.io.File; -import java.util.Arrays; -import java.util.List; -import java.util.regex.Pattern; +import java.util.Collections; -import lombok.installer.CorruptedIdeLocationException; -import lombok.installer.IdeLocation; import lombok.installer.IdeLocationProvider; -import lombok.installer.IdeFinder.OS; import org.mangosdk.spi.ProviderFor; @ProviderFor(IdeLocationProvider.class) -public class JbdsLocationProvider extends EclipseLocationProvider { - @Override protected List<String> getEclipseExecutableNames() { - return Arrays.asList("jbdevstudio.app", "jbdevstudio.exe", "jbdevstudioc.exe", "jbdevstudio"); - } - - @Override protected String getIniName() { - return "jbdevstudio.ini"; - } - - @Override protected IdeLocation makeLocation(String name, File ini) throws CorruptedIdeLocationException { - return new JbdsLocation(name, ini); - } - - @Override protected String getMacAppName() { - return "jbdevstudio.app"; - } +public class JbdsLocationProvider extends EclipseProductLocationProvider { - @Override protected String getUnixAppName() { - return "jbdevstudio"; - } + private static final EclipseProductDescriptor JBDS = new StandardProductDescriptor( + "JBoss Developer Studio", + "jbdevstudio", + "studio", + JbdsLocationProvider.class.getResource("jbds.png"), + Collections.<String>emptySet() + ); - @Override public Pattern getLocationSelectors(OS os) { - switch (os) { - case MAC_OS_X: - return Pattern.compile("^(jbdevstudio|jbdevstudio\\.ini|jbdevstudio\\.app)$", Pattern.CASE_INSENSITIVE); - case WINDOWS: - return Pattern.compile("^(jbdevstudioc?\\.exe|jbdevstudio\\.ini)$", Pattern.CASE_INSENSITIVE); - default: - case UNIX: - return Pattern.compile("^(jbdevstudio|jbdevstudio\\.ini)$", Pattern.CASE_INSENSITIVE); - } + public JbdsLocationProvider() { + super(JBDS); } } diff --git a/src/installer/lombok/installer/eclipse/JbdsLocation.java b/src/installer/lombok/installer/eclipse/MyEclipseLocationProvider.java index 81fb5261..298cabd6 100644 --- a/src/installer/lombok/installer/eclipse/JbdsLocation.java +++ b/src/installer/lombok/installer/eclipse/MyEclipseLocationProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 The Project Lombok Authors. + * Copyright (C) 2016 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,25 +21,24 @@ */ package lombok.installer.eclipse; -import java.io.File; -import java.net.URL; +import java.util.Collections; -import lombok.installer.CorruptedIdeLocationException; +import lombok.installer.IdeLocationProvider; -public class JbdsLocation extends EclipseLocation { - public JbdsLocation(String nameOfLocation, File pathToEclipseIni) throws CorruptedIdeLocationException { - super(nameOfLocation, pathToEclipseIni); - } - - @Override public URL getIdeIcon() { - return JbdsLocation.class.getResource("jbds.png"); - } +import org.mangosdk.spi.ProviderFor; + +@ProviderFor(IdeLocationProvider.class) +public class MyEclipseLocationProvider extends EclipseProductLocationProvider { - @Override protected String getIniFileName() { - return "jbdevstudio.ini"; - } + private static final EclipseProductDescriptor MY_ECLIPSE = new StandardProductDescriptor( + "MyEclipse", + "myeclipse", + "myeclipse", + MyEclipseLocationProvider.class.getResource("myeclipse.png"), + Collections.<String>emptySet() + ); - @Override protected String getTypeName() { - return "JBoss Developer Studio"; + public MyEclipseLocationProvider() { + super(MY_ECLIPSE); } } diff --git a/src/installer/lombok/installer/eclipse/RhdsLocationProvider.java b/src/installer/lombok/installer/eclipse/RhdsLocationProvider.java new file mode 100644 index 00000000..5e1d303d --- /dev/null +++ b/src/installer/lombok/installer/eclipse/RhdsLocationProvider.java @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2013-2016 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.installer.eclipse; + +import java.util.Collections; + +import lombok.installer.IdeLocationProvider; + +import org.mangosdk.spi.ProviderFor; + +@ProviderFor(IdeLocationProvider.class) +public class RhdsLocationProvider extends EclipseProductLocationProvider { + + private static final EclipseProductDescriptor RHDS = new StandardProductDescriptor( + "Red Hat JBoss Developer Studio", + "devstudio", + "studio", + RhdsLocationProvider.class.getResource("rhds.png"), + Collections.<String>emptySet() + ); + + public RhdsLocationProvider() { + super(RHDS); + } +} diff --git a/src/installer/lombok/installer/eclipse/STSFinder.java b/src/installer/lombok/installer/eclipse/STSFinder.java deleted file mode 100644 index 82bc9b80..00000000 --- a/src/installer/lombok/installer/eclipse/STSFinder.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (C) 2009 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.installer.eclipse; - -import java.util.Arrays; -import java.util.List; - -import lombok.installer.CorruptedIdeLocationException; -import lombok.installer.IdeFinder; -import lombok.installer.IdeLocation; - -import org.mangosdk.spi.ProviderFor; - -/** - * STS (Springsource Tool Suite) is an eclipse variant. - * Other than different executable names, it's the same as eclipse, as far as lombok support goes. - */ -@ProviderFor(IdeFinder.class) -public class STSFinder extends EclipseFinder { - @Override protected IdeLocation createLocation(String guess) throws CorruptedIdeLocationException { - return new STSLocationProvider().create0(guess); - } - - @Override protected String getDirName() { - return "sts"; - } - - @Override protected String getMacExecutableName() { - return "STS.app"; - } - - @Override protected String getUnixExecutableName() { - return "STS"; - } - - @Override protected String getWindowsExecutableName() { - return "STS.exe"; - } - - @Override protected List<String> getSourceDirsOnWindows() { - return Arrays.asList("\\", "\\springsource", "\\Program Files", "\\Program Files (x86)", "\\Program Files\\springsource", "\\Program Files (x86)\\springsource", System.getProperty("user.home", "."), System.getProperty("user.home", ".") + "\\springsource"); - } - - @Override protected List<String> getSourceDirsOnMac() { - return Arrays.asList("/Applications", "/Applications/springsource", System.getProperty("user.home", "."), System.getProperty("user.home", ".") + "/springsource"); - } - - @Override protected List<String> getSourceDirsOnUnix() { - return Arrays.asList(System.getProperty("user.home", "."), System.getProperty("user.home", ".") + "/springsource"); - } -} diff --git a/src/installer/lombok/installer/eclipse/STSLocationProvider.java b/src/installer/lombok/installer/eclipse/STSLocationProvider.java index 7d129838..d2efb956 100644 --- a/src/installer/lombok/installer/eclipse/STSLocationProvider.java +++ b/src/installer/lombok/installer/eclipse/STSLocationProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 The Project Lombok Authors. + * Copyright (C) 2009-2016 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,49 +21,23 @@ */ package lombok.installer.eclipse; -import java.io.File; -import java.util.Arrays; -import java.util.List; -import java.util.regex.Pattern; +import java.util.Collections; -import lombok.installer.CorruptedIdeLocationException; -import lombok.installer.IdeLocation; import lombok.installer.IdeLocationProvider; -import lombok.installer.IdeFinder.OS; import org.mangosdk.spi.ProviderFor; @ProviderFor(IdeLocationProvider.class) -public class STSLocationProvider extends EclipseLocationProvider { - @Override protected List<String> getEclipseExecutableNames() { - return Arrays.asList("sts.app", "sts.exe", "stsc.exe", "sts"); - } - - @Override protected String getIniName() { - return "STS.ini"; - } - - @Override protected IdeLocation makeLocation(String name, File ini) throws CorruptedIdeLocationException { - return new STSLocation(name, ini); - } - - @Override protected String getMacAppName() { - return "STS.app"; - } +public class STSLocationProvider extends EclipseProductLocationProvider { - @Override protected String getUnixAppName() { - return "STS"; - } + private static final EclipseProductDescriptor STS = new StandardProductDescriptor("STS", + "STS", + "sts", + STSLocationProvider.class.getResource("STS.png"), + Collections.singleton("springsource") + ); - @Override public Pattern getLocationSelectors(OS os) { - switch (os) { - case MAC_OS_X: - return Pattern.compile("^(sts|sts\\.ini|sts\\.app)$", Pattern.CASE_INSENSITIVE); - case WINDOWS: - return Pattern.compile("^(stsc?\\.exe|sts\\.ini)$", Pattern.CASE_INSENSITIVE); - default: - case UNIX: - return Pattern.compile("^(sts|sts\\.ini)$", Pattern.CASE_INSENSITIVE); - } + public STSLocationProvider() { + super(STS); } } diff --git a/src/installer/lombok/installer/eclipse/StandardProductDescriptor.java b/src/installer/lombok/installer/eclipse/StandardProductDescriptor.java new file mode 100644 index 00000000..47e103aa --- /dev/null +++ b/src/installer/lombok/installer/eclipse/StandardProductDescriptor.java @@ -0,0 +1,158 @@ +/* + * Copyright (C) 2016 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.installer.eclipse; + +import java.net.URL; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.regex.Pattern; + +import lombok.installer.OsUtils; + +public class StandardProductDescriptor implements EclipseProductDescriptor { + + private static final String USER_HOME = System.getProperty("user.home", "."); + private static final String[] WINDOWS_ROOTS = {"\\", "\\Program Files", "\\Program Files (x86)", USER_HOME}; + private static final String[] MAC_ROOTS = {"/Applications", USER_HOME}; + private static final String[] UNIX_ROOTS = {USER_HOME}; + + private final String productName; + private final String windowsName; + private final String unixName; + private final String macAppName; + private final List<String> executableNames; + private final List<String> sourceDirsOnWindows; + private final List<String> sourceDirsOnMac; + private final List<String> sourceDirsOnUnix; + private final String iniFileName; + private final Pattern locationSelectors; + private final String directoryName; + private final URL ideIcon; + + public StandardProductDescriptor(String productName, String baseName, String directoryName, URL ideIcon, Collection<String> alternativeDirectoryNames) { + this.productName = productName; + this.windowsName = baseName + ".exe"; + this.unixName = baseName; + this.macAppName = baseName + ".app"; + this.executableNames = executableNames(baseName); + this.sourceDirsOnWindows = generateAlternatives(WINDOWS_ROOTS, "\\", alternativeDirectoryNames); + this.sourceDirsOnMac = generateAlternatives(MAC_ROOTS, "/", alternativeDirectoryNames); + this.sourceDirsOnUnix = generateAlternatives(UNIX_ROOTS, "/", alternativeDirectoryNames); + this.iniFileName = baseName + ".ini"; + this.locationSelectors = getLocationSelectors(baseName); + this.directoryName = directoryName.toLowerCase(); + this.ideIcon = ideIcon; + } + + @Override public String getProductName() { + return productName; + } + + @Override public String getWindowsExecutableName() { + return windowsName; + } + + @Override public String getUnixAppName() { + return unixName; + } + + @Override public String getMacAppName() { + return macAppName; + } + + @Override public String getDirectoryName() { + return directoryName; + } + + @Override public List<String> getExecutableNames() { + return executableNames; + } + + @Override public List<String> getSourceDirsOnWindows() { + return sourceDirsOnWindows; + } + + @Override public List<String> getSourceDirsOnMac() { + return sourceDirsOnMac; + } + + @Override public List<String> getSourceDirsOnUnix() { + return sourceDirsOnUnix; + } + + @Override public String getIniFileName() { + return iniFileName; + } + + @Override public Pattern getLocationSelectors() { + return locationSelectors; + } + + @Override public URL getIdeIcon() { + return ideIcon; + } + + private static Pattern getLocationSelectors(String baseName) { + return Pattern.compile(String.format(platformPattern(), baseName.toLowerCase()), Pattern.CASE_INSENSITIVE); + } + + private static String platformPattern() { + switch (OsUtils.getOS()) { + case MAC_OS_X: + return "^(%s|%<s\\.ini|%<s\\.app)$"; + case WINDOWS: + return "^(%sc?\\.exe|%<s\\.ini)$"; + default: + case UNIX: + return "^(%s|%<s\\.ini)$"; + } + } + + private static List<String> executableNames(String baseName) { + String base = baseName.toLowerCase(); + return Collections.unmodifiableList(Arrays.asList(base, base + ".app", base + ".exe", base + "c.exe")); + } + + private static List<String> generateAlternatives(String[] roots, String pathSeparator, Collection<String> alternatives) { + List<String> result = new ArrayList<String>(); + for (String root : roots) { + result.add(concat(root, pathSeparator, "")); + for (String alternative : alternatives) { + result.add(concat(root, pathSeparator, alternative)); + } + } + return Collections.unmodifiableList(result); + } + + private static String concat(String base, String pathSeparator, String alternative) { + if (alternative.isEmpty()) { + return base; + } + if (base.endsWith(pathSeparator)) { + return base + alternative.replaceAll("[\\/]", "\\" + pathSeparator); + } + return base + pathSeparator + alternative.replaceAll("[\\/]", "\\" + pathSeparator); + } +} diff --git a/src/installer/lombok/installer/eclipse/myeclipse.png b/src/installer/lombok/installer/eclipse/myeclipse.png Binary files differnew file mode 100644 index 00000000..49c4fab3 --- /dev/null +++ b/src/installer/lombok/installer/eclipse/myeclipse.png diff --git a/src/installer/lombok/installer/eclipse/rhds.png b/src/installer/lombok/installer/eclipse/rhds.png Binary files differnew file mode 100644 index 00000000..ca7738e6 --- /dev/null +++ b/src/installer/lombok/installer/eclipse/rhds.png diff --git a/src/launch/lombok/launch/AnnotationProcessor.java b/src/launch/lombok/launch/AnnotationProcessor.java index 35c26b7c..93fba196 100644 --- a/src/launch/lombok/launch/AnnotationProcessor.java +++ b/src/launch/lombok/launch/AnnotationProcessor.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014 The Project Lombok Authors. + * Copyright (C) 2014-2016 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 @@ -27,6 +27,7 @@ import javax.annotation.processing.AbstractProcessor; import javax.annotation.processing.Completion; 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.AnnotationMirror; import javax.lang.model.element.Element; @@ -74,4 +75,15 @@ class AnnotationProcessorHider { } } } + + @SupportedAnnotationTypes("lombok.*") + public static class ClaimingProcessor extends AbstractProcessor { + @Override public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { + return true; + } + + @Override public SourceVersion getSupportedSourceVersion() { + return SourceVersion.latest(); + } + } } |