diff options
19 files changed, 347 insertions, 212 deletions
@@ -215,6 +215,7 @@ the common tasks and can be called on to run the main aspects of all the sub-scr <include name="lombok/experimental/**" /> <include name="lombok/extern/**" /> <include name="lombok/launch/**" /> + <include name="lombok/delombok/ant/Tasks*" /> </fileset> <mappedresources> <fileset dir="build/lombok"> @@ -223,6 +224,7 @@ the common tasks and can be called on to run the main aspects of all the sub-scr <exclude name="lombok/experimental/**" /> <exclude name="lombok/extern/**" /> <exclude name="lombok/launch/**" /> + <exclude name="lombok/delombok/ant/Tasks*" /> </fileset> <firstmatchmapper> <globmapper from="*.class" to="*.SCL.lombok" /> diff --git a/doc/changelog.markdown b/doc/changelog.markdown index 2fb167c7..b1005f5b 100644 --- a/doc/changelog.markdown +++ b/doc/changelog.markdown @@ -1,11 +1,14 @@ Lombok Changelog ---------------- -### v1.14.9 "Edgy, Shadowy Guinea Pig" +### v1.16.1 "Edgy Guinea Pig" +* BUGFIX: The ant `delombok` task was broken starting with v1.16.0. Note that the task def class has been changed; taskdef `lombok.delombok.ant.Tasks$Delombok` instead of the old `lombok.delombok.ant.DelombokTask`. [Issue #775](https://code.google.com/p/projectlombok/issues/detail?id=775). + +### v1.16.0 "Candid Duck" (January 26th, 2015) * BUGFIX: `@ExtensionMethod` was broken in Eclipse using java 8. [Issue #742](https://code.google.com/p/projectlombok/issues/detail?id=742), [Issue #747](https://code.google.com/p/projectlombok/issues/detail?id=747) * BUGFIX: delombok: Using exotic characters in your source files would overzealously backslash-u escape them. Now, all characters are printed unescaped, assuming your chosen encoding can support them. Otherwise, they are escaped. [Issue #759](https://code.google.com/p/projectlombok/issues/detail?id=759) -* PROMOTION: `@Builder` has graduated from experimental to the main package with a few changes (additional of `@Singular`, removal of the `fluent` and `chain` options). The old one still exists and has been deprecated. -* FEATURE: `@Builder` now supports adding the `@Singular` annotation to any field/parameter that represents a collection, which results in a method in the generated builder that takes in one element of that collection and adds it. Lombok takes care of generating the appropriate code to produce a compacted immutable version of the appropriate type. In this version, java.util collections and guava's ImmutableCollections are supported. See the [feature documentation](http://projectlombok.org/features/BuilderSingular.html) for more information. +* PROMOTION: `@Builder` has graduated from experimental to the main package with a few changes (addition of `@Singular`, removal of the `fluent` and `chain` options). The old one still exists and has been deprecated. +* FEATURE: `@Builder` now supports adding the `@Singular` annotation to any field/parameter that represents a collection, which results in a method in the generated builder that takes in one element of that collection and adds it. Lombok takes care of generating the appropriate code to produce a compacted immutable version of the appropriate type. In this version, java.util collections and guava's ImmutableCollections are supported. See the [feature documentation](http://projectlombok.org/features/Builder.html) for more information. * FEATURE: Added a launcher to the lombok boot process which removes the need for `-Xbootclasspath` to be in your `eclipse.ini` file, and removes all non-public API and third party dependencies (such as ASM) from the lombok jar, thus removing them from your IDE's auto complete offerings in any project that uses lombok. For those debugging lombok, the launcher enables hot code replace which makes debugging a lot easier, as previously one was required to shut down the IDE, rebuild the jar, and relaunch. Add `-Dshadow.override.lombok=/path/to/lombok/bin` to the launch target for hot code replace. ### v1.14.8 (September 15th, 2014) diff --git a/src/core/lombok/core/Version.java b/src/core/lombok/core/Version.java index 02bc1af0..b0f12916 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.14.9.shadow"; + private static final String VERSION = "1.16.1"; private static final String RELEASE_NAME = "Edgy Guinea Pig"; -// private static final String RELEASE_NAME = "Branching Cobra"; +// private static final String RELEASE_NAME = "Candid Duck"; private Version() { //Prevent instantiation diff --git a/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java b/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java index 426171c2..87e35269 100644 --- a/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java +++ b/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java @@ -411,19 +411,17 @@ public class EclipseHandlerUtil { } public static Annotation[] copyAnnotations(ASTNode source, Annotation[]... allAnnotations) { - boolean allNull = true; - - List<Annotation> result = new ArrayList<Annotation>(); + List<Annotation> result = null; for (Annotation[] annotations : allAnnotations) { if (annotations != null) { - allNull = false; for (Annotation annotation : annotations) { + if (result == null) result = new ArrayList<Annotation>(); result.add(copyAnnotation(annotation, source)); } } } - if (allNull) return null; - return result.toArray(new Annotation[0]); + + return result == null ? null : result.toArray(new Annotation[0]); } public static boolean hasAnnotation(Class<? extends java.lang.annotation.Annotation> type, EclipseNode node) { diff --git a/src/core/lombok/eclipse/handlers/HandleConstructor.java b/src/core/lombok/eclipse/handlers/HandleConstructor.java index d19e95e4..5bcc803a 100644 --- a/src/core/lombok/eclipse/handlers/HandleConstructor.java +++ b/src/core/lombok/eclipse/handlers/HandleConstructor.java @@ -333,8 +333,7 @@ public class HandleConstructor { Statement nullCheck = generateNullCheck(field, sourceNode); if (nullCheck != null) nullChecks.add(nullCheck); } - Annotation[] copiedAnnotations = copyAnnotations(source, nonNulls, nullables); - if (copiedAnnotations.length != 0) parameter.annotations = copiedAnnotations; + parameter.annotations = copyAnnotations(source, nonNulls, nullables); params.add(parameter); } @@ -348,10 +347,9 @@ public class HandleConstructor { constructorProperties = createConstructorProperties(source, fields); } - Annotation[] copiedAnnotations = copyAnnotations(source, + constructor.annotations = copyAnnotations(source, onConstructor.toArray(new Annotation[0]), constructorProperties); - if (copiedAnnotations.length != 0) constructor.annotations = copiedAnnotations; } constructor.traverse(new SetGeneratedByVisitor(source), typeDeclaration.scope); @@ -396,9 +394,7 @@ public class HandleConstructor { assigns.add(nameRef); Argument parameter = new Argument(field.name, fieldPos, copyType(field.type, source), Modifier.FINAL); - - Annotation[] copiedAnnotations = copyAnnotations(source, findAnnotations(field, NON_NULL_PATTERN), findAnnotations(field, NULLABLE_PATTERN)); - if (copiedAnnotations.length != 0) parameter.annotations = copiedAnnotations; + parameter.annotations = copyAnnotations(source, findAnnotations(field, NON_NULL_PATTERN), findAnnotations(field, NULLABLE_PATTERN)); params.add(parameter); } diff --git a/src/core/lombok/eclipse/handlers/HandleGetter.java b/src/core/lombok/eclipse/handlers/HandleGetter.java index 031fff82..14f2fb72 100644 --- a/src/core/lombok/eclipse/handlers/HandleGetter.java +++ b/src/core/lombok/eclipse/handlers/HandleGetter.java @@ -270,14 +270,12 @@ public class HandleGetter extends EclipseAnnotationHandler<Getter> { deprecated = new Annotation[] { generateDeprecatedAnnotation(source) }; } - Annotation[] copiedAnnotations = copyAnnotations(source, + method.annotations = copyAnnotations(source, onMethod.toArray(new Annotation[0]), findAnnotations(field, NON_NULL_PATTERN), findAnnotations(field, NULLABLE_PATTERN), findDelegatesAndMarkAsHandled(fieldNode), deprecated); - - if (copiedAnnotations.length != 0) method.annotations = copiedAnnotations; } method.traverse(new SetGeneratedByVisitor(source), parent.scope); diff --git a/src/core/lombok/eclipse/handlers/HandleSetter.java b/src/core/lombok/eclipse/handlers/HandleSetter.java index c22af676..1fcf751d 100644 --- a/src/core/lombok/eclipse/handlers/HandleSetter.java +++ b/src/core/lombok/eclipse/handlers/HandleSetter.java @@ -216,10 +216,7 @@ public class HandleSetter extends EclipseAnnotationHandler<Setter> { if (isFieldDeprecated(fieldNode)) { deprecated = new Annotation[] { generateDeprecatedAnnotation(source) }; } - Annotation[] copiedAnnotations = copyAnnotations(source, onMethod.toArray(new Annotation[0]), deprecated); - if (copiedAnnotations.length != 0) { - method.annotations = copiedAnnotations; - } + method.annotations = copyAnnotations(source, onMethod.toArray(new Annotation[0]), deprecated); Argument param = new Argument(field.name, p, copyType(field.type, source), Modifier.FINAL); param.sourceStart = pS; param.sourceEnd = pE; method.arguments = new Argument[] { param }; @@ -252,9 +249,7 @@ public class HandleSetter extends EclipseAnnotationHandler<Setter> { statements.add(returnThis); } method.statements = statements.toArray(new Statement[0]); - - Annotation[] copiedAnnotationsParam = copyAnnotations(source, nonNulls, nullables, onParam.toArray(new Annotation[0])); - if (copiedAnnotationsParam.length != 0) param.annotations = copiedAnnotationsParam; + param.annotations = copyAnnotations(source, nonNulls, nullables, onParam.toArray(new Annotation[0])); method.traverse(new SetGeneratedByVisitor(source), parent.scope); return method; diff --git a/src/core/lombok/eclipse/handlers/HandleWither.java b/src/core/lombok/eclipse/handlers/HandleWither.java index 8b038676..cb06d888 100644 --- a/src/core/lombok/eclipse/handlers/HandleWither.java +++ b/src/core/lombok/eclipse/handlers/HandleWither.java @@ -227,10 +227,7 @@ public class HandleWither extends EclipseAnnotationHandler<Wither> { if (isFieldDeprecated(fieldNode)) { deprecated = new Annotation[] { generateDeprecatedAnnotation(source) }; } - Annotation[] copiedAnnotations = copyAnnotations(source, onMethod.toArray(new Annotation[0]), deprecated); - if (copiedAnnotations.length != 0) { - method.annotations = copiedAnnotations; - } + method.annotations = copyAnnotations(source, onMethod.toArray(new Annotation[0]), deprecated); Argument param = new Argument(field.name, p, copyType(field.type, source), Modifier.FINAL); param.sourceStart = pS; param.sourceEnd = pE; method.arguments = new Argument[] { param }; @@ -283,8 +280,7 @@ public class HandleWither extends EclipseAnnotationHandler<Wither> { method.statements = statements.toArray(new Statement[0]); - Annotation[] copiedAnnotationsParam = copyAnnotations(source, nonNulls, nullables, onParam.toArray(new Annotation[0])); - if (copiedAnnotationsParam.length != 0) param.annotations = copiedAnnotationsParam; + param.annotations = copyAnnotations(source, nonNulls, nullables, onParam.toArray(new Annotation[0])); method.traverse(new SetGeneratedByVisitor(source), parent.scope); return method; diff --git a/src/delombok/lombok/delombok/ant/DelombokTask.java b/src/delombok/lombok/delombok/ant/DelombokTask.java index d5c17fe7..06bbe3e0 100644 --- a/src/delombok/lombok/delombok/ant/DelombokTask.java +++ b/src/delombok/lombok/delombok/ant/DelombokTask.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 The Project Lombok Authors. + * Copyright (C) 2009-2015 The Project Lombok Authors. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,142 +22,189 @@ package lombok.delombok.ant; import java.io.File; -import java.io.IOException; -import java.nio.charset.UnsupportedCharsetException; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; import java.util.ArrayList; -import java.util.Iterator; import java.util.List; -import lombok.delombok.Delombok; -import lombok.delombok.Delombok.InvalidFormatOptionException; +import lombok.Lombok; import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.Location; import org.apache.tools.ant.Task; import org.apache.tools.ant.types.FileSet; import org.apache.tools.ant.types.Path; import org.apache.tools.ant.types.Reference; -import org.apache.tools.ant.types.resources.FileResource; -public class DelombokTask extends Task { - private File fromDir, toDir; - private Path classpath; - private Path sourcepath; - private boolean verbose; - private String encoding; - private Path path; - private List<Format> formatOptions = new ArrayList<Format>(); - - public void setClasspath(Path classpath) { - if (this.classpath == null) { - this.classpath = classpath; - } else { - this.classpath.append(classpath); +@SuppressWarnings("unused") // we use reflection to transfer fields. +class Tasks { + public static class Format { + private String value; + + @Override public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((value == null) ? 0 : value.hashCode()); + return result; } - } - - public Path createClasspath() { - if (classpath == null) { - classpath = new Path(getProject()); + + @Override public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null) return false; + if (getClass() != obj.getClass()) return false; + Format other = (Format) obj; + if (value == null) { + if (other.value != null) return false; + } else if (!value.equals(other.value)) return false; + return true; } - return classpath.createPath(); - } - - public void setClasspathRef(Reference r) { - createClasspath().setRefid(r); - } - - public void setSourcepath(Path sourcepath) { - if (this.sourcepath == null) { - this.sourcepath = sourcepath; - } else { - this.sourcepath.append(sourcepath); + + @Override public String toString() { + return "FormatOption [value=" + value + "]"; } - } - - public Path createSourcepath() { - if (sourcepath == null) { - sourcepath = new Path(getProject()); + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; } - return sourcepath.createPath(); - } - - public void setSourcepathRef(Reference r) { - createSourcepath().setRefid(r); - } - - public void setFrom(File dir) { - this.fromDir = dir; - } - - public void setTo(File dir) { - this.toDir = dir; - } - - public void setVerbose(boolean verbose) { - this.verbose = verbose; - } - - public void setEncoding(String encoding) { - this.encoding = encoding; - } - - public void addFileset(FileSet set) { - if (path == null) path = new Path(getProject()); - path.add(set); - } - - public void addFormat(Format format) { - formatOptions.add(format); } - @Override - public void execute() throws BuildException { - if (fromDir == null && path == null) throw new BuildException("Either 'from' attribute, or nested <fileset> tags are required."); - if (fromDir != null && path != null) throw new BuildException("You can't specify both 'from' attribute and nested filesets. You need one or the other."); - if (toDir == null) throw new BuildException("The to attribute is required."); - - Delombok delombok = new Delombok(); - if (verbose) delombok.setVerbose(true); - try { - if (encoding != null) delombok.setCharset(encoding); - } catch (UnsupportedCharsetException e) { - throw new BuildException("Unknown charset: " + encoding, getLocation()); - } - - if (classpath != null) delombok.setClasspath(classpath.toString()); - if (sourcepath != null) delombok.setSourcepath(sourcepath.toString()); - - try { - List<String> fo = new ArrayList<String>(); - for (Format f : formatOptions) { - String v = f.getValue(); - if (v == null) throw new BuildException("'value' property required for <format>"); - fo.add(v); + public static class Delombok extends Task { + private File fromDir, toDir; + private Path classpath; + private Path sourcepath; + private boolean verbose; + private String encoding; + private Path path; + private List<Format> formatOptions = new ArrayList<Format>(); + + public void setClasspath(Path classpath) { + if (this.classpath == null) { + this.classpath = classpath; + } else { + this.classpath.append(classpath); + } + } + + public Path createClasspath() { + if (classpath == null) { + classpath = new Path(getProject()); } - delombok.setFormatPreferences(Delombok.formatOptionsToMap(fo)); - } catch (InvalidFormatOptionException e) { - throw new BuildException(e.getMessage() + " Run java -jar lombok.jar --format-help for detailed format help."); - } - - delombok.setOutput(toDir); - try { - if (fromDir != null) delombok.addDirectory(fromDir); - else { - Iterator<?> it = path.iterator(); - while (it.hasNext()) { - FileResource fileResource = (FileResource) it.next(); - File baseDir = fileResource.getBaseDir(); - if (baseDir == null) { - File file = fileResource.getFile(); - delombok.addFile(file.getParentFile(), file.getName()); + return classpath.createPath(); + } + + public void setClasspathRef(Reference r) { + createClasspath().setRefid(r); + } + + public void setSourcepath(Path sourcepath) { + if (this.sourcepath == null) { + this.sourcepath = sourcepath; + } else { + this.sourcepath.append(sourcepath); + } + } + + public Path createSourcepath() { + if (sourcepath == null) { + sourcepath = new Path(getProject()); + } + return sourcepath.createPath(); + } + + public void setSourcepathRef(Reference r) { + createSourcepath().setRefid(r); + } + + public void setFrom(File dir) { + this.fromDir = dir; + } + + public void setTo(File dir) { + this.toDir = dir; + } + + public void setVerbose(boolean verbose) { + this.verbose = verbose; + } + + public void setEncoding(String encoding) { + this.encoding = encoding; + } + + public void addFileset(FileSet set) { + if (path == null) path = new Path(getProject()); + path.add(set); + } + + public Format createFormat() { + return new Format(); + } + + public void addFormat(Format format) { + formatOptions.add(format); + } + + private static ClassLoader shadowLoader; + + public static Class<?> shadowLoadClass(String name) { + try { + if (shadowLoader == null) { + try { + Class.forName("lombok.core.LombokNode"); + // If we get here, then lombok is already available. + shadowLoader = Delombok.class.getClassLoader(); + } catch (ClassNotFoundException e) { + // If we get here, it isn't, and we should use the shadowloader. + Class<?> launcherMain = Class.forName("lombok.launch.Main"); + Method m = launcherMain.getDeclaredMethod("createShadowClassLoader"); + m.setAccessible(true); + shadowLoader = (ClassLoader) m.invoke(null); + } + } + + return Class.forName(name, true, shadowLoader); + } catch (Exception e) { + throw Lombok.sneakyThrow(e); + } + } + + @Override + public void execute() throws BuildException { + Location loc = getLocation(); + + try { + Object instance = shadowLoadClass("lombok.delombok.ant.DelombokTaskImpl").newInstance(); + for(Field selfField : getClass().getDeclaredFields()) { + if (selfField.isSynthetic() || Modifier.isStatic(selfField.getModifiers())) continue; + Field otherField = instance.getClass().getDeclaredField(selfField.getName()); + otherField.setAccessible(true); + selfField.setAccessible(true); + if (selfField.getName().equals("formatOptions")) { + List<String> rep = new ArrayList<String>(); + for (Format f : formatOptions) { + if (f.getValue() == null) throw new BuildException("'value' property required for <format>"); + rep.add(f.getValue()); + } + otherField.set(instance, rep); } else { - delombok.addFile(baseDir, fileResource.getName()); + otherField.set(instance, selfField.get(this)); } } + + Method m = instance.getClass().getMethod("execute", Location.class); + m.setAccessible(true); + m.invoke(instance, loc); + } catch (InvocationTargetException e) { + throw Lombok.sneakyThrow(e.getCause()); + } catch (Exception e) { + throw Lombok.sneakyThrow(e); } - delombok.delombok(); - } catch (IOException e) { - throw new BuildException("I/O problem during delombok", e, getLocation()); } } } diff --git a/src/delombok/lombok/delombok/ant/DelombokTaskImpl.java b/src/delombok/lombok/delombok/ant/DelombokTaskImpl.java new file mode 100644 index 00000000..470819cd --- /dev/null +++ b/src/delombok/lombok/delombok/ant/DelombokTaskImpl.java @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2009-2015 The Project Lombok Authors. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package lombok.delombok.ant; + +import java.io.File; +import java.io.IOException; +import java.nio.charset.UnsupportedCharsetException; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import lombok.delombok.Delombok; +import lombok.delombok.Delombok.InvalidFormatOptionException; + +import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.Location; +import org.apache.tools.ant.types.Path; +import org.apache.tools.ant.types.resources.FileResource; + +public class DelombokTaskImpl { + private File fromDir, toDir; + private Path classpath; + private Path sourcepath; + private boolean verbose; + private String encoding; + private Path path; + private List<String> formatOptions = new ArrayList<String>(); + + public void execute(Location location) throws BuildException { + if (fromDir == null && path == null) throw new BuildException("Either 'from' attribute, or nested <fileset> tags are required."); + if (fromDir != null && path != null) throw new BuildException("You can't specify both 'from' attribute and nested filesets. You need one or the other."); + if (toDir == null) throw new BuildException("The to attribute is required."); + + Delombok delombok = new Delombok(); + if (verbose) delombok.setVerbose(true); + try { + if (encoding != null) delombok.setCharset(encoding); + } catch (UnsupportedCharsetException e) { + throw new BuildException("Unknown charset: " + encoding, location); + } + + if (classpath != null) delombok.setClasspath(classpath.toString()); + if (sourcepath != null) delombok.setSourcepath(sourcepath.toString()); + + try { + delombok.setFormatPreferences(Delombok.formatOptionsToMap(formatOptions)); + } catch (InvalidFormatOptionException e) { + throw new BuildException(e.getMessage() + " Run java -jar lombok.jar --format-help for detailed format help."); + } + + delombok.setOutput(toDir); + try { + if (fromDir != null) delombok.addDirectory(fromDir); + else { + Iterator<?> it = path.iterator(); + while (it.hasNext()) { + FileResource fileResource = (FileResource) it.next(); + File baseDir = fileResource.getBaseDir(); + if (baseDir == null) { + File file = fileResource.getFile(); + delombok.addFile(file.getParentFile(), file.getName()); + } else { + delombok.addFile(baseDir, fileResource.getName()); + } + } + } + delombok.delombok(); + } catch (IOException e) { + throw new BuildException("I/O problem during delombok", e, location); + } + } +} diff --git a/src/delombok/lombok/delombok/ant/Format.java b/src/delombok/lombok/delombok/ant/Format.java deleted file mode 100644 index bb2b5e87..00000000 --- a/src/delombok/lombok/delombok/ant/Format.java +++ /dev/null @@ -1,35 +0,0 @@ -package lombok.delombok.ant; - -public class Format { - private String value; - - @Override public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((value == null) ? 0 : value.hashCode()); - return result; - } - - @Override public boolean equals(Object obj) { - if (this == obj) return true; - if (obj == null) return false; - if (getClass() != obj.getClass()) return false; - Format other = (Format) obj; - if (value == null) { - if (other.value != null) return false; - } else if (!value.equals(other.value)) return false; - return true; - } - - @Override public String toString() { - return "FormatOption [value=" + value + "]"; - } - - public String getValue() { - return value; - } - - public void setValue(String value) { - this.value = value; - } -} diff --git a/src/installer/lombok/installer/InstallerGUI.java b/src/installer/lombok/installer/InstallerGUI.java index 41832e5d..6b8a58ab 100644 --- a/src/installer/lombok/installer/InstallerGUI.java +++ b/src/installer/lombok/installer/InstallerGUI.java @@ -101,6 +101,7 @@ public class InstallerGUI { public InstallerGUI() { appWindow = new JFrame(String.format("Project Lombok v%s - Installer", Version.getVersion())); + appWindow.setLocationByPlatform(true); appWindow.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); appWindow.setResizable(false); appWindow.setIconImage(Toolkit.getDefaultToolkit().getImage(Installer.class.getResource("lombokIcon.png"))); diff --git a/usage_examples/BuilderExample_post.jpage b/usage_examples/BuilderExample_post.jpage index 0446a0dc..863ab19b 100644 --- a/usage_examples/BuilderExample_post.jpage +++ b/usage_examples/BuilderExample_post.jpage @@ -37,14 +37,18 @@ public class BuilderExample { if (this.occupations == null) { this.occupations = new java.util.ArrayList<String>(); } + this.occupations.add(occupation); + return this; } public BuilderExampleBuilder occupations(Collection<? extends String> occupations) { if (this.occupations == null) { this.occupations = new java.util.ArrayList<String>(); } + this.occupations.addAll(occupations); + return this; } public BuilderExample build() { diff --git a/usage_examples/BuilderExample_pre.jpage b/usage_examples/BuilderExample_pre.jpage index 374799ad..1557fff4 100644 --- a/usage_examples/BuilderExample_pre.jpage +++ b/usage_examples/BuilderExample_pre.jpage @@ -6,5 +6,5 @@ import java.util.Set; public class BuilderExample { private String name; private int age; - @Singular Set<String> occupations; + @Singular private Set<String> occupations; } diff --git a/usage_examples/Singular-snippetExample_post.jpage b/usage_examples/Singular-snippetExample_post.jpage index 689d97e8..4e2b0460 100644 --- a/usage_examples/Singular-snippetExample_post.jpage +++ b/usage_examples/Singular-snippetExample_post.jpage @@ -9,7 +9,7 @@ public class SingularExample<T extends Number> { private SortedMap<Integer, T> elves; private Collection<?> minutiae; - SingularExample(final Set<String> occupations, final ImmutableList<String> axes, final SortedMap<Integer, T> elves, final Collection<?> minutiae) { + SingularExample(Set<String> occupations, ImmutableList<String> axes, SortedMap<Integer, T> elves, Collection<?> minutiae) { this.occupations = occupations; this.axes = axes; this.elves = elves; @@ -26,7 +26,7 @@ public class SingularExample<T extends Number> { SingularExampleBuilder() { } - public SingularExampleBuilder<T> occupation(final String occupation) { + public SingularExampleBuilder<T> occupation(String occupation) { if (this.occupations == null) { this.occupations = new java.util.ArrayList<String>(); } @@ -36,7 +36,7 @@ public class SingularExample<T extends Number> { } @java.lang.SuppressWarnings("all") - public SingularExampleBuilder<T> occupations(final java.util.Collection<? extends String> occupations) { + public SingularExampleBuilder<T> occupations(java.util.Collection<? extends String> occupations) { if (this.occupations == null) { this.occupations = new java.util.ArrayList<String>(); } @@ -45,7 +45,7 @@ public class SingularExample<T extends Number> { return this; } - public SingularExampleBuilder<T> axis(final String axis) { + public SingularExampleBuilder<T> axis(String axis) { if (this.axes == null) { this.axes = com.google.common.collect.ImmutableList.builder(); } @@ -54,7 +54,7 @@ public class SingularExample<T extends Number> { return this; } - public SingularExampleBuilder<T> axes(final java.lang.Iterable<? extends String> axes) { + public SingularExampleBuilder<T> axes(java.lang.Iterable<? extends String> axes) { if (this.axes == null) { this.axes = com.google.common.collect.ImmutableList.builder(); } @@ -63,7 +63,7 @@ public class SingularExample<T extends Number> { return this; } - public SingularExampleBuilder<T> elf(final Integer elfKey, final T elfValue) { + public SingularExampleBuilder<T> elf(Integer elfKey, T elfValue) { if (this.elves$key == null) { this.elves$key = new java.util.ArrayList<Integer>(); this.elves$value = new java.util.ArrayList<T>(); @@ -74,20 +74,20 @@ public class SingularExample<T extends Number> { return this; } - public SingularExampleBuilder<T> elves(final java.util.Map<? extends Integer, ? extends T> elves) { + public SingularExampleBuilder<T> elves(java.util.Map<? extends Integer, ? extends T> elves) { if (this.elves$key == null) { this.elves$key = new java.util.ArrayList<Integer>(); this.elves$value = new java.util.ArrayList<T>(); } - for (final java.util.Map.Entry<? extends Integer, ? extends T> $lombokEntry : elves.entrySet()) { + for (java.util.Map.Entry<? extends Integer, ? extends T> $lombokEntry : elves.entrySet()) { this.elves$key.add($lombokEntry.getKey()); this.elves$value.add($lombokEntry.getValue()); } return this; } - public SingularExampleBuilder<T> minutia(final java.lang.Object minutia) { + public SingularExampleBuilder<T> minutia(java.lang.Object minutia) { if (this.minutiae == null) { this.minutiae = new java.util.ArrayList<java.lang.Object>(); } @@ -96,7 +96,7 @@ public class SingularExample<T extends Number> { return this; } - public SingularExampleBuilder<T> minutiae(final java.util.Collection<?> minutiae) { + public SingularExampleBuilder<T> minutiae(java.util.Collection<?> minutiae) { if (this.minutiae == null) { this.minutiae = new java.util.ArrayList<java.lang.Object>(); } diff --git a/website/features/Builder.html b/website/features/Builder.html index 5cf7c23e..b4731b07 100644 --- a/website/features/Builder.html +++ b/website/features/Builder.html @@ -83,12 +83,11 @@ are very complicated in order to guarantee the following properties: <ul> <li>When invoking <code>build()</code>, the produced collection will be immutable.</li> - <li>Repeatedly invoking <code>build()</code> works fine and does not corrupt any of the collections already generated.</li> - <li>Calling one of the 'adder' methods after invoking <code>build()</code> does not modify any already generated objects, and, if <code>build()</code> is later called again, + <li>Calling one of the 'adder' methods after invoking <code>build()</code> does not modify any already generated objects, and, if <code>build()</code> is later called again, another collection with all the elements added since the creation of the builder is generated.</li> <li>The produced collection will be compacted to the smallest feasible format while remaining efficient.</li> </ul> </p><p> - <code>@Singular</code> can only be applied to collection types for which lombok has a recipe to produce the singular methods. Currently, the supported types are: + <code>@Singular</code> can only be applied to collection types known to lombok. Currently, the supported types are: <ul> <li><a href="http://docs.oracle.com/javase/8/docs/api/java/util/package-summary.html"><code>java.util</code></a>:<ul> <li><code>Iterable</code>, <code>Collection</code>, and <code>List</code> (backed by a compacted unmodifiable <code>ArrayList</code> in the general case).</li> @@ -98,17 +97,14 @@ <li><a href="https://github.com/google/guava">Guava</a>'s <code>com.google.common.collect</code>:<ul> <li><code>ImmutableCollection</code> and <code>ImmutableList</code> (backed by the builder feature of <code>ImmutableList</code>).</li> <li><code>ImmutableSet</code> and <code>ImmutableSortedSet</code> (backed by the builder feature of those types).</li> - <li><code>ImmutableMap</code>, <code>ImmutableBiMap</code>, and ImmutableSortedMap</code> (backed by the builder feature of those types).</li> + <li><code>ImmutableMap</code>, <code>ImmutableBiMap</code>, and <code>ImmutableSortedMap</code> (backed by the builder feature of those types).</li> </ul></li> </ul> </p><p> - If your identifiers are written in common english, lombok assumes that any collection with <code>@Singular</code> on it is an english plural and will attempt to automatically - singularize it. If this is possible, the add-one method will use this name. For example, if your collection is called <code>statuses</code>, then the add-one method will automatically - be called <code>status</code>. If lombok cannot singularize your identifier, or it is ambiguous, lombok will generate an error and force you to explicitly specify the singular name. - To do this, just pass the singular name as string, like so: <code>@Singular("axis") List<Line> axes;</code>. - </p><p> - When using the <code>java.util</code> interfaces, lombok always uses <code>ArrayList</code> to store items added to the builder, because this is more efficient than adding them to a map or - set immediately, as lombok needs to compact and potentially duplicate the result. + If your identifiers are written in common english, lombok assumes that the name of any collection with <code>@Singular</code> on it is an english plural and will attempt to automatically + singularize that name. If this is possible, the add-one method will use this name. For example, if your collection is called <code>statuses</code>, then the add-one method will automatically + be called <code>status</code>. You can also specify the singular form of your identifier explictly by passing the singular form as argument to the annotation like so: <code>@Singular("axis") List<Line> axes;</code>.<br /> + If lombok cannot singularize your identifier, or it is ambiguous, lombok will generate an error and force you to explicitly specify the singular name. </p><p> The snippet below does not show what lombok generates for a <code>@Singular</code> field/parameter because it is rather complicated. You can view a snippet <a href="Singular-snippet.html">here</a>. @@ -132,9 +128,9 @@ <dt><code>lombok.builder.flagUsage</code> = [<code>warning</code> | <code>error</code>] (default: not set)</dt> <dd>Lombok will flag any usage of <code>@Builder</code> as a warning or error if configured.</dd> <dt><code>lombok.singular.useGuava</code> = [<code>true</code> | <code>false</code>] (default: false)</dt> - <dd>If <code>true</code>, lombok will use guava's <code>ImmutableX</code> builders and types to implement <code>java.util</code> collection interfaces, instead of creating - implementations based on <code>Collections.unmodifiableX</code>. You must ensure that guava is actually available on the classpath and buildpath if you use this setting. - Guava is used automatically if your field/parameter has one of the guava <code>ImmutableX</code> types. + <dd>If <code>true</code>, lombok will use guava's <code>ImmutableXxx</code> builders and types to implement <code>java.util</code> collection interfaces, instead of creating + implementations based on <code>Collections.unmodifiableXxx</code>. You must ensure that guava is actually available on the classpath and buildpath if you use this setting. + Guava is used automatically if your field/parameter has one of the guava <code>ImmutableXxx</code> types. <dt><code>lombok.singular.auto</code> = [<code>true</code> | <code>false</code>] (default: true)</dt> <dd>If <code>true</code> (which is the default), lombok automatically tries to singularize your identifier name by assuming that it is a common english plural. If <code>false</code>, you must always explicitly specify the singular name, and lombok will generate an error if you don't (useful if you write your code in a language other than english). @@ -146,9 +142,11 @@ @Singular support for <code>java.util.NavigableMap/Set</code> only works if you are compiling with JDK1.8 or higher. </p><p> You cannot manually provide some or all parts of a <code>@Singular</code> node; the code lombok generates is too complex for this. If you want to - manually control (part of) the builder nodes associated with some field or parameter, don't use @Singular and add everything you need manually. + manually control (part of) the builder code associated with some field or parameter, don't use <code>@Singular</code> and add everything you need manually. </p><p> The sorted collections (java.util: <code>SortedSet</code>, <code>NavigableSet</code>, <code>SortedMap</code>, <code>NavigableMap</code> and guava: <code>ImmutableSortedSet</code>, <code>ImmutableSortedMap</code>) require that the type argument of the collection has natural order (implements <code>java.util.Comparable</code>). There is no way to pass an explicit <code>Comparator</code> to use in the builder. + </p><p> + An <code>ArrayList</code> is used to store added elements as call methods of a <code>@Singular</code> marked field, if the target collection is from the <code>java.util</code> package, <em>even if the collection is a set or map</em>. Because lombok ensures that generated collections are compacted, a new backing instance of a set or map must be constructed anyway, and storing the data as an <code>ArrayList</code> during the build process is more efficient that storing it as a map or set. This behaviour is not externally visible, an an implementation detail of the current implementation of the <code>java.util</code> recipes for <code>@Singular @Builder</code>. </p> </div> </div> diff --git a/website/features/delombok.html b/website/features/delombok.html index 30f21c04..dbd7b51f 100644 --- a/website/features/delombok.html +++ b/website/features/delombok.html @@ -41,7 +41,7 @@ <code>lombok.jar</code> includes an ant task which can apply delombok for you. For example, to create javadoc for your project, your <code>build.xml</code> file would look something like: <div class="snippet"><pre><target name="javadoc"> - <taskdef classname="lombok.delombok.ant.DelombokTask" classpath="lib/lombok.jar" name="delombok" /> + <taskdef classname="lombok.delombok.ant.Tasks$Delombok" classpath="lib/lombok.jar" name="delombok" /> <mkdir dir="build/src-delomboked" /> <strong><delombok verbose="true" encoding="UTF-8" to="build/src-delomboked" from="src"></strong> <strong><format value="suppressWarnings:skip" /></strong> diff --git a/website/features/experimental/Value.html b/website/features/experimental/Value.html new file mode 100644 index 00000000..c2b335e6 --- /dev/null +++ b/website/features/experimental/Value.html @@ -0,0 +1,36 @@ +<!DOCTYPE html> +<html><head> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> + <link rel="stylesheet" type="text/css" href="../../logi/reset.css" /> + <link rel="stylesheet" type="text/css" href="../features.css" /> + <link rel="shortcut icon" href="../../favicon.ico" type="image/x-icon" /> + <meta name="description" content="Spice up your java" /> + <title>EXPERIMENTAL - @Value</title> +</head><body><div id="pepper"> + <div class="minimumHeight"></div> + <div class="meat"> + <div class="header"><a href="../../index.html">Project Lombok</a></div> + <h1>@Value</h1> + <div class="byline">Immutable classes made very easy.</div> + <div class="moved"> + @Value has been promoted to the core package in lombok release v1.12.0.<br /> + The documentation has been moved here: <a href="../Value.html">@lombok.Value</a>. + </div> + <div class="footer"> + <a href="index.html">Back to experimental features</a><br /> + <a href="../../credits.html" class="creditsLink">credits</a> | <span class="copyright">Copyright © 2009-2015 The Project Lombok Authors, licensed under the <a href="http://www.opensource.org/licenses/mit-license.php">MIT license</a>.</span> + </div> + <div style="clear: both;"></div> + </div> +</div> +<script type="text/javascript"> + var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www."); + document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E")); +</script> +<script type="text/javascript"> + try { + var pageTracker = _gat._getTracker("UA-9884254-1"); + pageTracker._trackPageview(); + } catch(err) {} +</script> +</body></html> diff --git a/website/mavenrepo/index.html b/website/mavenrepo/index.html index 01227bbd..29716920 100644 --- a/website/mavenrepo/index.html +++ b/website/mavenrepo/index.html @@ -60,6 +60,11 @@ You can use lombok with ivy by adding the following to your <strong>ivy.xml</strong>: <div class="snippet"><dependency org="org.projectlombok" name="lombok" rev="@VERSION@" conf="build" /></div> </div> + <h2>SBT</h2> + <div> + You can use lombok with SBT by adding the following to your <strong>build.sbt</strong>: + <div class="snippet">libraryDependencies += "org.projectlombok" % "lombok" % "@VERSION@"</div> + </div> <h2>Gradle</h2> <div> You can use lombok with gradle by adding the following to your <strong>build.gradle</strong> in the <strong>dependencies</strong> block: |