aboutsummaryrefslogtreecommitdiff
path: root/src/lombok/core
diff options
context:
space:
mode:
Diffstat (limited to 'src/lombok/core')
-rw-r--r--src/lombok/core/AST.java177
-rw-r--r--src/lombok/core/AnnotationValues.java95
-rw-r--r--src/lombok/core/PrintAST.java36
-rw-r--r--src/lombok/core/SpiLoadUtil.java60
-rw-r--r--src/lombok/core/TransformationsUtil.java73
-rw-r--r--src/lombok/core/TypeLibrary.java40
-rw-r--r--src/lombok/core/TypeResolver.java33
-rw-r--r--src/lombok/core/Version.java30
8 files changed, 522 insertions, 22 deletions
diff --git a/src/lombok/core/AST.java b/src/lombok/core/AST.java
index 24e128b2..ef752d1a 100644
--- a/src/lombok/core/AST.java
+++ b/src/lombok/core/AST.java
@@ -1,3 +1,24 @@
+/*
+ * Copyright © 2009 Reinier Zwitserloot and Roel Spilker.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
package lombok.core;
import static lombok.Lombok.sneakyThrow;
@@ -14,7 +35,15 @@ import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
+/**
+ * Lombok wraps the AST produced by a target platform into its own AST system, mostly because both eclipse and javac
+ * do not allow upward traversal (from a method to its owning type, for example).
+ *
+ * @param N The common type of all AST nodes in the internal representation of the target platform.
+ * For example, JCTree for javac, and ASTNode for eclipse.
+ */
public abstract class AST<N> {
+ /** The kind of node represented by a given AST.Node object. */
public enum Kind {
COMPILATION_UNIT, TYPE, FIELD, INITIALIZER, METHOD, ANNOTATION, ARGUMENT, LOCAL, STATEMENT;
}
@@ -28,29 +57,52 @@ public abstract class AST<N> {
this.fileName = fileName == null ? "(unknown).java" : fileName;
}
+ /** Set the node object that wraps the internal Compilation Unit node. */
protected void setTop(Node top) {
this.top = top;
}
+ /**
+ * Return the content of the package declaration on this AST's top (Compilation Unit) node.
+ *
+ * Example: "java.util".
+ */
public abstract String getPackageDeclaration();
+ /**
+ * Return the contents of each non-static import statement on this AST's top (Compilation Unit) node.
+ *
+ * Example: "java.util.IOException".
+ */
public abstract Collection<String> getImportStatements();
- protected <T extends Node> T putInMap(T parent) {
- nodeMap.put(parent.get(), parent);
- identityDetector.put(parent.get(), null);
- return parent;
+ /**
+ * Puts the given node in the map so that javac/eclipse's own internal AST object can be translated to
+ * an AST.Node object. Also registers the object as visited to avoid endless loops.
+ */
+ protected <T extends Node> T putInMap(T node) {
+ nodeMap.put(node.get(), node);
+ identityDetector.put(node.get(), null);
+ return node;
}
+ /** Returns the node map, that can map javac/eclipse internal AST objects to AST.Node objects. */
protected Map<N, Node> getNodeMap() {
return nodeMap;
}
+ /** Clears the registry that avoids endless loops, and empties the node map. The existing node map
+ * object is left untouched, and instead a new map is created. */
protected void clearState() {
identityDetector = new IdentityHashMap<N, Void>();
nodeMap = new IdentityHashMap<N, Node>();
}
+ /**
+ * Marks the stated node as handled (to avoid endless loops if 2 nodes refer to each other, or a node
+ * refers to itself). Will then return true if it was already set as handled before this call - in which
+ * case you should do nothing lest the AST build process loops endlessly.
+ */
protected boolean setAndGetAsHandled(N node) {
if ( identityDetector.containsKey(node) ) return true;
identityDetector.put(node, null);
@@ -61,10 +113,12 @@ public abstract class AST<N> {
return fileName;
}
+ /** The AST.Node object representing the Compilation Unit. */
public Node top() {
return top;
}
+ /** Maps a javac/eclipse internal AST Node to the appropriate AST.Node object. */
public Node get(N node) {
return nodeMap.get(node);
}
@@ -86,14 +140,33 @@ public abstract class AST<N> {
return targetNode;
}
+ /** An instance of this class wraps an eclipse/javac internal node object. */
public abstract class Node {
protected final Kind kind;
protected final N node;
protected final List<? extends Node> children;
protected Node parent;
+
+ /** This flag has no specified meaning; you can set and retrieve it.
+ *
+ * In practice, for annotation nodes it means: Some AnnotationHandler finished whatever changes were required,
+ * and for all other nodes it means: This node was made by a lombok operation.
+ */
protected boolean handled;
+
+ /** structurally significant are those nodes that can be annotated in java 1.6 or are method-like toplevels,
+ * so fields, local declarations, method arguments, methods, types, the Compilation Unit itself, and initializers. */
protected boolean isStructurallySignificant;
+ /**
+ * Creates a new Node object that represents the provided node.
+ *
+ * Make sure you manually set the parent correctly.
+ *
+ * @param node The AST object in the target parser's own internal AST tree that this node object will represent.
+ * @param children A list of child nodes. Passing in null results in the children list being empty, not null.
+ * @param kind The kind of node represented by this object.
+ */
protected Node(N node, List<? extends Node> children, Kind kind) {
this.kind = kind;
this.node = node;
@@ -102,29 +175,57 @@ public abstract class AST<N> {
this.isStructurallySignificant = calculateIsStructurallySignificant();
}
+ /** {@inheritDoc} */
@Override public String toString() {
return String.format("NODE %s (%s) %s%s",
kind, node == null ? "(NULL)" : node.getClass(), handled ? "[HANDLED]" : "", node == null ? "" : node);
}
+ /**
+ * Convenient shortcut to the owning JavacAST object's getPackageDeclaration method.
+ *
+ * @see AST#getPackageDeclaration()
+ */
public String getPackageDeclaration() {
return AST.this.getPackageDeclaration();
}
+ /**
+ * Convenient shortcut to the owning JavacAST object's getImportStatements method.
+ *
+ * @see AST#getImportStatements()
+ */
public Collection<String> getImportStatements() {
return AST.this.getImportStatements();
}
+ /**
+ * See {@link #isStructurallySignificant}.
+ */
protected abstract boolean calculateIsStructurallySignificant();
+ /**
+ * Convenient shortcut to the owning JavacAST object's getNodeFor method.
+ *
+ * @see AST#getNodeFor()
+ */
public Node getNodeFor(N obj) {
return AST.this.get(obj);
}
+ /**
+ * @return The javac/eclipse internal AST object wrapped by this AST.Node object.
+ */
public N get() {
return node;
}
+ /**
+ * Replaces the AST node represented by this node object with the provided node. This node must
+ * have a parent, obviously, for this to work.
+ *
+ * Also affects the underlying (eclipse/javac) AST.
+ */
@SuppressWarnings("unchecked")
public Node replaceWith(N newN, Kind kind) {
Node newNode = buildTree(newN, kind);
@@ -137,6 +238,11 @@ public abstract class AST<N> {
return newNode;
}
+ /**
+ * Replaces the stated node with a new one. The old node must be a direct child of this node.
+ *
+ * Also affects the underlying (eclipse/javac) AST.
+ */
public void replaceChildNode(N oldN, N newN) {
replaceStatementInNode(get(), oldN, newN);
}
@@ -169,27 +275,58 @@ public abstract class AST<N> {
return parent;
}
+ /**
+ * Returns all children nodes.
+ *
+ * A copy is created, so changing the list has no effect. Also, while iterating through this list,
+ * you may add, remove, or replace children without causing ConcurrentModificationExceptions.
+ */
public Collection<? extends Node> down() {
return new ArrayList<Node>(children);
}
+ /**
+ * returns the value of the 'handled' flag.
+ *
+ * @see #handled
+ */
public boolean isHandled() {
return handled;
}
+ /**
+ * Sets the handled flag, then returns 'this'.
+ *
+ * @see #handled
+ */
public Node setHandled() {
this.handled = true;
return this;
}
+ /**
+ * Convenient shortcut to the owning JavacAST object's top method.
+ *
+ * @see AST#top()
+ */
public Node top() {
return top;
}
+ /**
+ * Convenient shortcut to the owning JavacAST object's getFileName method.
+ *
+ * @see AST#getFileName()
+ */
public String getFileName() {
return fileName;
}
+ /**
+ * Adds the stated node as a direct child of this node.
+ *
+ * Does not change the underlying (javac/eclipse) AST, only the wrapped view.
+ */
@SuppressWarnings("unchecked") public Node add(N newChild, Kind kind) {
Node n = buildTree(newChild, kind);
if ( n == null ) return null;
@@ -221,18 +358,30 @@ public abstract class AST<N> {
nodeMap.remove(get());
}
+ /**
+ * Removes the stated node, which must be a direct child of this node, from the AST.
+ *
+ * Does not change the underlying (javac/eclipse) AST, only the wrapped view.
+ */
public void removeChild(Node child) {
children.remove(child);
}
+ /**
+ * Sets the handled flag on this node, and all child nodes, then returns this.
+ *
+ * @see #handled
+ */
public Node recursiveSetHandled() {
this.handled = true;
for ( Node child : children ) child.recursiveSetHandled();
return this;
}
+ /** Generate a compiler error on this node. */
public abstract void addError(String message);
+ /** Generate a compiler warning on this node. */
public abstract void addWarning(String message);
/**
@@ -245,10 +394,16 @@ public abstract class AST<N> {
}
}
+ /** Build an AST.Node object for the stated internal (javac/eclipse) AST Node object. */
protected abstract Node buildTree(N item, Kind kind);
+ /**
+ * Represents a field that contains AST children.
+ */
protected static class FieldAccess {
+ /** The actual field. */
public final Field field;
+ /** Dimensions of the field. Works for arrays, or for java.util.collections. */
public final int dim;
FieldAccess(Field field, int dim) {
@@ -258,6 +413,11 @@ public abstract class AST<N> {
}
private static Map<Class<?>, Collection<FieldAccess>> fieldsOfASTClasses = new HashMap<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.
+ */
protected Collection<FieldAccess> fieldsOf(Class<?> c) {
Collection<FieldAccess> fields = fieldsOfASTClasses.get(c);
if ( fields != null ) return fields;
@@ -305,14 +465,23 @@ public abstract class AST<N> {
} else 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();
+ /**
+ * buildTree implementation that uses reflection to find all child nodes by way of inspecting
+ * the fields. */
protected <T extends Node> Collection<T> buildWithField(Class<T> nodeType, N statement, FieldAccess fa) {
List<T> list = new ArrayList<T>();
buildWithField0(nodeType, statement, fa, list);
return list;
}
+ /**
+ * Uses reflection to find the given direct child on the given statement, and replace it with a new child.
+ */
protected boolean replaceStatementInNode(N statement, N oldN, N newN) {
for ( FieldAccess fa : fieldsOf(statement.getClass()) ) {
if ( replaceStatementInField(fa, statement, oldN, newN) ) return true;
diff --git a/src/lombok/core/AnnotationValues.java b/src/lombok/core/AnnotationValues.java
index 432d507f..ee434f1f 100644
--- a/src/lombok/core/AnnotationValues.java
+++ b/src/lombok/core/AnnotationValues.java
@@ -1,3 +1,24 @@
+/*
+ * Copyright © 2009 Reinier Zwitserloot and Roel Spilker.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
package lombok.core;
import java.lang.annotation.Annotation;
@@ -10,13 +31,23 @@ import java.util.Collections;
import java.util.List;
import java.util.Map;
+/**
+ * Represents a single annotation in a source file and can be used to query the parameters present on it.
+ */
public class AnnotationValues<A extends Annotation> {
private final Class<A> type;
private final Map<String, AnnotationValue> values;
private final AST<?>.Node ast;
-
+
+ /**
+ * Represents a single method on the annotation class. For example, the value() method on the Getter annotation.
+ */
public static class AnnotationValue {
+ /** A list of the raw expressions. List is size 1 unless an array is provided. */
public final List<String> raws;
+
+ /** Guesses for each raw expression. If the raw expression is a literal expression, the guess will
+ * likely be right. If not, it'll be wrong. */
public final List<Object> valueGuesses;
private final AST<?>.Node node;
@@ -33,7 +64,9 @@ public class AnnotationValues<A extends Annotation> {
this.valueGuesses = Collections.singletonList(valueGuess);
}
- /** When the value is an array type. */
+ /**
+ * Like the other constructor, but used for when the annotation method is initialized with an array value.
+ */
public AnnotationValue(AST<?>.Node node, List<String> raws, List<Object> valueGuesses) {
this.node = node;
this.raws = raws;
@@ -52,21 +85,39 @@ public class AnnotationValues<A extends Annotation> {
node.addError(message);
}
+ /** {@inheritDoc} */
@Override public String toString() {
return "raws: " + raws + " valueGuesses: " + valueGuesses;
}
}
+ /**
+ * Creates a new AnnotationValues.
+ *
+ * @param type The annotation type. For example, "Getter.class"
+ * @param values a Map of method names to AnnotationValue instances, for example 'value -> annotationValue instance'.
+ * @param ast The Annotation node.
+ */
public AnnotationValues(Class<A> type, Map<String, AnnotationValue> values, AST<?>.Node ast) {
this.type = type;
this.values = values;
this.ast = ast;
}
+ /**
+ * Thrown on the fly if an actual annotation instance procured via the {@link #getInstance()} method is queried
+ * for a method for which this AnnotationValues instance either doesn't have a guess or can't manage to fit
+ * the guess into the required data type.
+ */
public static class AnnotationValueDecodeFail extends RuntimeException {
private static final long serialVersionUID = 1L;
+ /** The index into an array initializer (e.g. if the second value in an array initializer is
+ * an integer constant expression like '5+SomeOtherClass.CONSTANT', this exception will be thrown,
+ * and you'll get a '1' for idx. */
public final int idx;
+
+ /** The AnnotationValue object that goes with the annotation method for which the failure occurred. */
public final AnnotationValue owner;
public AnnotationValueDecodeFail(AnnotationValue owner, String msg, int idx) {
@@ -83,8 +134,15 @@ public class AnnotationValues<A extends Annotation> {
private A cachedInstance = null;
+ /**
+ * Creates an actual annotation instance. You can use this to query any annotation methods, except for
+ * those annotation methods with class literals, as those can most likely not be turned into Class objects.
+ *
+ * If some of the methods cannot be implemented, this method still works; it's only when you call a method
+ * that has a problematic value that an AnnotationValueDecodeFail exception occurs.
+ */
@SuppressWarnings("unchecked")
- public A getInstance() throws AnnotationValueDecodeFail {
+ public A getInstance() {
if ( cachedInstance != null ) return cachedInstance;
InvocationHandler invocations = new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
@@ -217,16 +275,32 @@ public class AnnotationValues<A extends Annotation> {
"Can't translate a " + guess.getClass() + " to the expected " + expected, pos);
}
+ /**
+ * Returns the raw expressions used for the provided annotationMethodName.
+ *
+ * You should use this method for annotation methods that return Class objects. Remember that
+ * class literals end in ".class" which you probably want to strip off.
+ */
public List<String> getRawExpressions(String annotationMethodName) {
AnnotationValue v = values.get(annotationMethodName);
return v == null ? Collections.<String>emptyList() : v.raws;
}
+ /**
+ * Convenience method to return the first result in a {@link getRawExpressions(String)} call.
+ *
+ * You should use this method if the annotation method is not an array type.
+ */
public String getRawExpression(String annotationMethodName) {
List<String> l = getRawExpressions(annotationMethodName);
return l.isEmpty() ? null : l.get(0);
}
+ /**
+ * Attempts to translate class literals to their fully qualified names, such as 'Throwable.class' to 'java.lang.Throwable'.
+ *
+ * This process is at best a guess, but it will take into account import statements.
+ */
public List<String> getProbableFQTypes(String annotationMethodName) {
List<String> result = new ArrayList<String>();
AnnotationValue v = values.get(annotationMethodName);
@@ -236,6 +310,16 @@ public class AnnotationValues<A extends Annotation> {
return result;
}
+ /**
+ * Convenience method to return the first result in a {@link getProbableFQType(String)} call.
+ *
+ * You should use this method if the annotation method is not an array type.
+ */
+ public String getProbableFQType(String annotationMethodName) {
+ List<String> l = getProbableFQTypes(annotationMethodName);
+ return l.isEmpty() ? null : l.get(0);
+ }
+
private String toFQ(String typeName) {
Class<?> c;
boolean fqn = typeName.indexOf('.') > -1;
@@ -279,9 +363,4 @@ public class AnnotationValues<A extends Annotation> {
return null;
}
}
-
- public String getProbableFQType(String annotationMethodName) {
- List<String> l = getProbableFQTypes(annotationMethodName);
- return l.isEmpty() ? null : l.get(0);
- }
}
diff --git a/src/lombok/core/PrintAST.java b/src/lombok/core/PrintAST.java
index 6d1eaafd..943bf298 100644
--- a/src/lombok/core/PrintAST.java
+++ b/src/lombok/core/PrintAST.java
@@ -1,3 +1,24 @@
+/*
+ * Copyright © 2009 Reinier Zwitserloot and Roel Spilker.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
package lombok.core;
import java.lang.annotation.ElementType;
@@ -5,14 +26,25 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
+/**
+ * Will print the tree structure of annotated node and all its children.
+ *
+ * This annotation is useful only for those working on Lombok, for example to test if a Lombok handlers is doing its
+ * job correctly, or to see what the imagined endresult of a transformation is supposed to look like.
+ */
@Target({ElementType.CONSTRUCTOR, ElementType.FIELD, ElementType.LOCAL_VARIABLE, ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.SOURCE)
public @interface PrintAST {
+ /**
+ * Normally, the AST is printed to standard out, but you can pick a filename instead. Useful for many IDEs
+ * which don't have a console unless you start them from the command line.
+ */
String outfile() default "";
/**
- * Normally, the printer will print each node focusing on the node (E.g. classname, and such). By setting printContent to true,
- * methods, initializers, and other statement-containing elements actually print their java code instead of element class names.
+ * Normally, the printer will print each node focusing on the node (E.g. classname, and such).
+ * By setting printContent to true, methods, initializers, and other statement-containing elements
+ * actually print their java code instead of a tree view of internal AST nodes.
*/
boolean printContent() default false;
}
diff --git a/src/lombok/core/SpiLoadUtil.java b/src/lombok/core/SpiLoadUtil.java
index b26dd747..b3b70f27 100644
--- a/src/lombok/core/SpiLoadUtil.java
+++ b/src/lombok/core/SpiLoadUtil.java
@@ -1,3 +1,24 @@
+/*
+ * Copyright © 2009 Reinier Zwitserloot and Roel Spilker.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
package lombok.core;
import java.io.BufferedReader;
@@ -16,13 +37,44 @@ import java.util.Set;
import lombok.Lombok;
+/**
+ * The java core libraries have a SPI discovery system, but it works only in Java 1.6 and up. For at least eclipse,
+ * lombok actually works in java 1.5, so we've rolled our own SPI discovery system.
+ *
+ * It is not API compatible with <code>ServiceLoader</code>.
+ *
+ * @see java.util.ServiceLoader
+ */
public class SpiLoadUtil {
- private SpiLoadUtil() {}
+ private SpiLoadUtil() {
+ //Prevent instantiation
+ }
+ /**
+ * Returns an iterator of instances that, at least according to the spi discovery file, are implementations
+ * of the stated class.
+ *
+ * Like ServiceLoader, each listed class is turned into an instance by calling the public no-args constructor.
+ *
+ * Convenience method that calls the more elaborate {@link #findServices(Class, ClassLoader)} method with
+ * this {@link java.lang.Thread}'s context class loader as <code>ClassLoader</code>.
+ *
+ * @param target class to find implementations for.
+ */
public static <C> Iterator<C> findServices(Class<C> target) throws IOException {
return findServices(target, Thread.currentThread().getContextClassLoader());
}
+ /**
+ * Returns an iterator of class objects that, at least according to the spi discovery file, are implementations
+ * of the stated class.
+ *
+ * Like ServiceLoader, each listed class is turned into an instance by calling the public no-args constructor.
+ *
+ * @param target class to find implementations for.
+ * @param loader The classloader object to use to both the spi discovery files, as well as the loader to use
+ * to make the returned instances.
+ */
public static <C> Iterator<C> findServices(final Class<C> target, final ClassLoader loader) throws IOException {
Enumeration<URL> resources = loader.getResources("META-INF/services/" + target.getName());
final Set<String> entries = new LinkedHashSet<String>();
@@ -70,6 +122,12 @@ public class SpiLoadUtil {
}
}
+ /**
+ * This method will find the <code>T</code> in <code>public class Foo extends BaseType&lt;T&gt;.
+ *
+ * It returns an annotation type because it is used exclusively to figure out which annotations are
+ * being handled by {@link lombok.eclipse.EclipseAnnotationHandler} and {@link lombok.javac.JavacAnnotationHandler}.
+ */
@SuppressWarnings("unchecked")
public static Class<? extends Annotation> findAnnotationClass(Class<?> c, Class<?> base) {
if ( c == Object.class || c == null ) return null;
diff --git a/src/lombok/core/TransformationsUtil.java b/src/lombok/core/TransformationsUtil.java
index 8aea09a4..6b454b51 100644
--- a/src/lombok/core/TransformationsUtil.java
+++ b/src/lombok/core/TransformationsUtil.java
@@ -1,8 +1,50 @@
+/*
+ * Copyright © 2009 Reinier Zwitserloot and Roel Spilker.
+ *
+ * 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;
+/**
+ * Container for static utility methods useful for some of the standard lombok transformations, regardless of
+ * target platform (e.g. useful for both javac and eclipse lombok implementations).
+ */
public class TransformationsUtil {
- private TransformationsUtil() {}
+ private TransformationsUtil() {
+ //Prevent instantiation
+ }
+ /**
+ * Generates a getter name from a given field name.
+ *
+ * Strategy:
+ *
+ * First, pick a prefix. 'get' normally, but 'is' if <code>isBoolean</code> is true.
+ *
+ * Then, check if the first character of the field is lowercase. If so, check if the second character
+ * exists and is title or upper case. If so, uppercase the first character. If not, titlecase the first character.
+ *
+ * return the prefix plus the possibly title/uppercased first character, and the rest of the field name.
+ *
+ * @param fieldName the name of the field.
+ * @param isBoolean if the field is of type 'boolean'. For fields of type 'java.lang.Boolean', you should provide <code>false</code>.
+ */
public static String toGetterName(CharSequence fieldName, boolean isBoolean) {
final String prefix = isBoolean ? "is" : "get";
@@ -11,16 +53,33 @@ public class TransformationsUtil {
return buildName(prefix, fieldName.toString());
}
+ /**
+ * Generates a getter name from a given field name.
+ *
+ * Strategy:
+ *
+ * Check if the first character of the field is lowercase. If so, check if the second character
+ * exists and is title or upper case. If so, uppercase the first character. If not, titlecase the first character.
+ *
+ * return "set" plus the possibly title/uppercased first character, and the rest of the field name.
+ *
+ * @param fieldName the name of the field.
+ */
+ public static String toSetterName(CharSequence fieldName) {
+ return buildName("set", fieldName.toString());
+ }
+
private static String buildName(String prefix, String suffix) {
if ( suffix.length() == 0 ) return prefix;
char first = suffix.charAt(0);
- if ( Character.isLowerCase(first) )
- suffix = String.format("%s%s", Character.toTitleCase(first), suffix.subSequence(1, suffix.length()));
+ if ( Character.isLowerCase(first) ) {
+ boolean useUpperCase = suffix.length() > 2 &&
+ (Character.isTitleCase(suffix.charAt(1)) || Character.isUpperCase(suffix.charAt(1)));
+ suffix = String.format("%s%s",
+ useUpperCase ? Character.toUpperCase(first) : Character.toTitleCase(first),
+ suffix.subSequence(1, suffix.length()));
+ }
return String.format("%s%s", prefix, suffix);
}
-
- public static String toSetterName(CharSequence fieldName) {
- return buildName("set", fieldName.toString());
- }
}
diff --git a/src/lombok/core/TypeLibrary.java b/src/lombok/core/TypeLibrary.java
index c6789d7e..41b70a68 100644
--- a/src/lombok/core/TypeLibrary.java
+++ b/src/lombok/core/TypeLibrary.java
@@ -1,3 +1,24 @@
+/*
+ * Copyright © 2009 Reinier Zwitserloot and Roel Spilker.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
package lombok.core;
import java.util.Collection;
@@ -7,9 +28,23 @@ import java.util.HashSet;
import java.util.Map;
import java.util.Set;
+/**
+ * Library of types, which can be used to look up potential matching types.
+ *
+ * For example, if you put 'foo.Spork' and 'bar.Spork' into the library, and then ask for
+ * all compatible types given the type 'Spork', you'll get both of them, but you'll only
+ * get the one if you ask for compatible types given 'foo.Spork'.
+ *
+ * Useful to 'guess' if a given annotation AST node matches an annotation handler's target annotation.
+ */
public class TypeLibrary {
private final Map<String, Set<String>> simpleToQualifiedMap = new HashMap<String, Set<String>>();
+ /**
+ * Add a type to the library.
+ *
+ * @param fullyQualifiedTypeName the FQN type name, such as 'java.lang.String'.
+ */
public void addType(String fullyQualifiedTypeName) {
int idx = fullyQualifiedTypeName.lastIndexOf('.');
if ( idx == -1 ) throw new IllegalArgumentException(
@@ -32,6 +67,11 @@ public class TypeLibrary {
return this;
}
+ /**
+ * Returns all items in the type library that may be a match to the provided type.
+ *
+ * @param typeReference something like 'String' or even 'java.lang.String'.
+ */
public Collection<String> findCompatible(String typeReference) {
Set<String> result = simpleToQualifiedMap.get(typeReference);
return result == null ? Collections.<String>emptySet() : result;
diff --git a/src/lombok/core/TypeResolver.java b/src/lombok/core/TypeResolver.java
index 1e356f89..3adc82ce 100644
--- a/src/lombok/core/TypeResolver.java
+++ b/src/lombok/core/TypeResolver.java
@@ -1,3 +1,24 @@
+/*
+ * Copyright © 2009 Reinier Zwitserloot and Roel Spilker.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
package lombok.core;
import java.util.Collection;
@@ -7,10 +28,17 @@ import java.util.Set;
import lombok.core.AST.Kind;
+/**
+ * Capable of resolving a simple type name such as 'String' into 'java.lang.String'.
+ */
public class TypeResolver {
private final TypeLibrary library;
private Collection<String> imports;
+ /**
+ * Creates a new TypeResolver that can be used to resolve types in a given library, encountered in
+ * a source file with the provided package and import statements.
+ */
public TypeResolver(TypeLibrary library, String packageString, Collection<String> importStrings) {
this.library = library;
this.imports = makeImportList(packageString, importStrings);
@@ -23,6 +51,11 @@ public class TypeResolver {
return imports;
}
+ /**
+ * Finds type matches for the stated type reference. The provided context is scanned for local type names
+ * that shadow type names listed in import statements. If such a shadowing occurs, no matches are returned
+ * for any shadowed types, as you would expect.
+ */
public Collection<String> findTypeMatches(AST<?>.Node context, String typeRef) {
Collection<String> potentialMatches = library.findCompatible(typeRef);
if ( potentialMatches.isEmpty() ) return Collections.emptyList();
diff --git a/src/lombok/core/Version.java b/src/lombok/core/Version.java
index cb349aaf..119dcc2e 100644
--- a/src/lombok/core/Version.java
+++ b/src/lombok/core/Version.java
@@ -1,5 +1,29 @@
+/*
+ * Copyright © 2009 Reinier Zwitserloot and Roel Spilker.
+ *
+ * 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;
+/**
+ * This class just holds lombok's current version.
+ */
public class Version {
private static final String VERSION = "0.4";
@@ -7,10 +31,16 @@ public class Version {
//Prevent instantiation
}
+ /**
+ * Prints the version followed by a newline, and exits.
+ */
public static void main(String[] args) {
System.out.println(VERSION);
}
+ /**
+ * Get the current Lombok version.
+ */
public static String getVersion() {
return VERSION;
}