Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: projectlombok/lombok
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: master
Choose a base ref
...
head repository: pbihler/lombok
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: master
Choose a head ref
Can’t automatically merge. Don’t worry, you can still create the pull request.
  • 6 commits
  • 24 files changed
  • 1 contributor

Commits on Jun 21, 2012

  1. Added NonEmpty annotation and a javac implementation. Eclipse

    Implementation still incomplete.
    pascal.bihler committed Jun 21, 2012
    Copy the full SHA
    8086a16 View commit details

Commits on Jun 22, 2012

  1. Added array handling for NonEmpty check

    pascal.bihler committed Jun 22, 2012
    Copy the full SHA
    74be34e View commit details
  2. Implemeted NonEmpty check for Eclipse and corrected overall NonEmpty

    implementation
    pascal.bihler committed Jun 22, 2012
    Copy the full SHA
    7ae60fb View commit details
  3. Fix for NonEmpty arrays

    pascal.bihler committed Jun 22, 2012
    Copy the full SHA
    a3fae18 View commit details

Commits on Jun 27, 2012

  1. Small fix

    pascal.bihler committed Jun 27, 2012
    Copy the full SHA
    65528fb View commit details
  2. Added documentation

    pascal.bihler committed Jun 27, 2012
    Copy the full SHA
    a4c2ac7 View commit details
1 change: 1 addition & 0 deletions AUTHORS
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
Lombok contributors in alphabetical order:

Jappe van der Hel <jappe.vanderhel@gmail.com>
Pascal Bihler <bihler@cs.uni-bonn.de>
Philipp Eichhorn <peichhor@web.de>
Reinier Zwitserloot <reinier@zwitserloot.com>
Robbert Jan Grootjans <grootjans@gmail.com>
45 changes: 45 additions & 0 deletions src/core/lombok/NonEmpty.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* 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;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
* Lombok is smart enough to use any annotation named {@code @NonEmpty} in any casing and
* with any package name to generate the appropriate empty checks in the setter and constructor.
*
* {@code @NonEmpty} defines that a marked collection/array must contain elements, any other marked object must not return an empty String when calling {@code toString()}.
*
* {@code @NonEmpty} does NOT imply {@code @NonNull}, i.e. it is possible to define fields that are {@code null} or anything not empty.
*
* WARNING: If the java community ever does decide on supporting a single {@code @NonEmpty} annotation , then
* this annotation will <strong>be deleted</strong> from the lombok package. If the need to update an import statement scares
* you, you should use your own annotation named {@code @NonEmpty} instead of this one.
*/
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.LOCAL_VARIABLE})
@Retention(RetentionPolicy.CLASS)
@Documented
public @interface NonEmpty {}
7 changes: 6 additions & 1 deletion src/core/lombok/core/TransformationsUtil.java
Original file line number Diff line number Diff line change
@@ -75,13 +75,18 @@ private static CharSequence removePrefix(CharSequence fieldName, String[] prefix
/* NB: 'notnull' is not part of the pattern because there are lots of @NotNull annotations out there that are crappily named and actually mean
something else, such as 'this field must not be null _when saved to the db_ but its perfectly okay to start out as such, and a no-args
constructor and the implied starts-out-as-null state that goes with it is in fact mandatory' which happens with javax.validation.constraints.NotNull.
Various problems with spring have also been reported. See issue #287, issue #271, and issue #43. */
Various problems with spring have also been reported. See issue #287, issue #271, and issue #43.
As the same is somehow true for NonEmpty, it duplicates the NonNull-approach. */

/** Matches the simple part of any annotation that lombok considers as indicative of NonNull status. */
public static final Pattern NON_NULL_PATTERN = Pattern.compile("^(?:nonnull)$", Pattern.CASE_INSENSITIVE);

/** Matches the simple part of any annotation that lombok considers as indicative of Nullable status. */
public static final Pattern NULLABLE_PATTERN = Pattern.compile("^(?:nullable|checkfornull)$", Pattern.CASE_INSENSITIVE);

/** Matches the simple part of any annotation that lombok considers as indicative of NonEmpty status. */
public static final Pattern NON_EMPTY_PATTERN = Pattern.compile("^(?:nonempty)$", Pattern.CASE_INSENSITIVE);

/**
* Generates a getter name from a given field name.
131 changes: 131 additions & 0 deletions src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java
Original file line number Diff line number Diff line change
@@ -22,6 +22,8 @@
package lombok.eclipse.handlers;

import static lombok.eclipse.Eclipse.*;
import static lombok.eclipse.handlers.EclipseHandlerUtil.*;
import static lombok.eclipse.handlers.EclipseHandlerUtil.setGeneratedBy;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
@@ -53,6 +55,7 @@
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Status;
import org.eclipse.jdt.internal.compiler.ast.AND_AND_Expression;
import org.eclipse.jdt.internal.compiler.ast.ASTNode;
import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
import org.eclipse.jdt.internal.compiler.ast.AbstractVariableDeclaration;
@@ -61,6 +64,8 @@
import org.eclipse.jdt.internal.compiler.ast.ArrayInitializer;
import org.eclipse.jdt.internal.compiler.ast.ArrayQualifiedTypeReference;
import org.eclipse.jdt.internal.compiler.ast.ArrayTypeReference;
import org.eclipse.jdt.internal.compiler.ast.Assignment;
import org.eclipse.jdt.internal.compiler.ast.Block;
import org.eclipse.jdt.internal.compiler.ast.CastExpression;
import org.eclipse.jdt.internal.compiler.ast.Clinit;
import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
@@ -70,14 +75,17 @@
import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration;
import org.eclipse.jdt.internal.compiler.ast.FieldReference;
import org.eclipse.jdt.internal.compiler.ast.IfStatement;
import org.eclipse.jdt.internal.compiler.ast.InstanceOfExpression;
import org.eclipse.jdt.internal.compiler.ast.IntLiteral;
import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration;
import org.eclipse.jdt.internal.compiler.ast.MarkerAnnotation;
import org.eclipse.jdt.internal.compiler.ast.MemberValuePair;
import org.eclipse.jdt.internal.compiler.ast.MessageSend;
import org.eclipse.jdt.internal.compiler.ast.MethodDeclaration;
import org.eclipse.jdt.internal.compiler.ast.NameReference;
import org.eclipse.jdt.internal.compiler.ast.NormalAnnotation;
import org.eclipse.jdt.internal.compiler.ast.NullLiteral;
import org.eclipse.jdt.internal.compiler.ast.OR_OR_Expression;
import org.eclipse.jdt.internal.compiler.ast.OperatorIds;
import org.eclipse.jdt.internal.compiler.ast.ParameterizedQualifiedTypeReference;
import org.eclipse.jdt.internal.compiler.ast.ParameterizedSingleTypeReference;
@@ -105,6 +113,8 @@
import org.eclipse.jdt.internal.compiler.lookup.WildcardBinding;
import org.osgi.framework.Bundle;

import com.sun.org.apache.xpath.internal.operations.UnaryOperation;

/**
* Container for static utility methods useful to handlers written for eclipse.
*/
@@ -1289,6 +1299,127 @@ public static Statement generateNullCheck(AbstractVariableDeclaration variable,
setGeneratedBy(ifStatement, source);
return ifStatement;
}

/**
* Generates a new statement that checks if the given variable is empty, and if so, throws a {@code InvalidArgumentException} with the
* variable name as message.
*/
public static Statement generateEmptyCheck(AbstractVariableDeclaration variable, ASTNode source) {
int pS = source.sourceStart, pE = source.sourceEnd;
long p = (long)pS << 32 | pE;

if (isPrimitive(variable.type)) return null;
AllocationExpression exception = new AllocationExpression();
setGeneratedBy(exception, source);
exception.type = new QualifiedTypeReference(TypeConstants.JAVA_LANG_ILLEGALARGUMENTEXCEPTION, new long[]{p, p, p});
setGeneratedBy(exception.type, source);
exception.arguments = new Expression[] { new StringLiteral((new String(variable.name) + " must not be empty.").toCharArray(), pS, pE, 0)};
setGeneratedBy(exception.arguments[0], source);
ThrowStatement throwStatement = new ThrowStatement(exception, pS, pE);
setGeneratedBy(throwStatement, source);

SingleNameReference varName = new SingleNameReference(variable.name, p);
setGeneratedBy(varName, source);

NullLiteral nullLiteral = new NullLiteral(pS, pE);
setGeneratedBy(nullLiteral, source);

EqualExpression nullCheck = new EqualExpression(varName, nullLiteral, OperatorIds.NOT_EQUAL);
nullCheck.sourceStart = pS; nullCheck.statementEnd = nullCheck.sourceEnd = pE;
setGeneratedBy(nullCheck, source);

if (isArray(variable.type)) {
FieldReference lengthRef = new FieldReference("length".toCharArray(), 0);
lengthRef.receiver = new SingleNameReference(variable.name, p);
setGeneratedBy(lengthRef, source);
setGeneratedBy(lengthRef.receiver, source);

IntLiteral zeroLiteral = makeIntLiteral("0".toCharArray(),source);
zeroLiteral.sourceStart = pS; zeroLiteral.sourceEnd = pE;
setGeneratedBy(zeroLiteral, source);

EqualExpression equalExpression = new EqualExpression(lengthRef, zeroLiteral, OperatorIds.EQUAL_EQUAL);
equalExpression.sourceStart = pS; equalExpression.statementEnd = equalExpression.sourceEnd = pE;
setGeneratedBy(equalExpression, source);


AND_AND_Expression andExpression = new AND_AND_Expression(nullCheck, equalExpression, OperatorIds.AND_AND);
andExpression.sourceStart = pS; andExpression.statementEnd = andExpression.sourceEnd = pE;
setGeneratedBy(andExpression, source);

IfStatement ifStatement = new IfStatement(andExpression, throwStatement, 0, 0);
setGeneratedBy(ifStatement, source);
return ifStatement;
} else {
MessageSend toStringInvocation = new MessageSend();
toStringInvocation.arguments = new Expression[] {};
toStringInvocation.receiver = new SingleNameReference(variable.name, p);
toStringInvocation.selector = "toString".toCharArray();
setGeneratedBy(toStringInvocation, source);
setGeneratedBy(toStringInvocation.receiver, source);

StringLiteral emptyString = new StringLiteral("".toCharArray(), pS, pE, 0);
setGeneratedBy(emptyString, source);

MessageSend equalsInvocation = new MessageSend();
equalsInvocation.arguments = new Expression[] {toStringInvocation};
equalsInvocation.receiver = emptyString;
equalsInvocation.selector = "equals".toCharArray();
setGeneratedBy(equalsInvocation, source);

SingleNameReference varNameForCast = new SingleNameReference(variable.name, p);
setGeneratedBy(varNameForCast, source);

TypeReference objectTypeReference = new QualifiedTypeReference(TypeConstants.JAVA_LANG_OBJECT, new long[]{p, p, p});
setGeneratedBy(objectTypeReference, source);
CastExpression objectCast = makeCastExpression(varNameForCast, objectTypeReference,source);
setGeneratedBy(objectCast, source);

TypeReference collectionTypeReference = new QualifiedTypeReference(TypeConstants.JAVA_UTIL_COLLECTION, new long[]{p, p, p});
setGeneratedBy(collectionTypeReference, source);

InstanceOfExpression instanceOfExpression = new InstanceOfExpression(objectCast, collectionTypeReference);
instanceOfExpression.sourceStart = pS; instanceOfExpression.sourceEnd = pE;
setGeneratedBy(instanceOfExpression, source);

varNameForCast = new SingleNameReference(variable.name, p);
setGeneratedBy(varNameForCast, source);
objectTypeReference = new QualifiedTypeReference(TypeConstants.JAVA_LANG_OBJECT, new long[]{p, p, p});
setGeneratedBy(objectTypeReference, source);
objectCast = makeCastExpression(varNameForCast, objectTypeReference,source);
setGeneratedBy(objectCast, source);

collectionTypeReference = new QualifiedTypeReference(TypeConstants.JAVA_UTIL_COLLECTION, new long[]{p, p, p});
setGeneratedBy(collectionTypeReference, source);

CastExpression collectionCast = makeCastExpression(objectCast, collectionTypeReference,source);
setGeneratedBy(collectionCast, source);

MessageSend isEmptyInvocation = new MessageSend();
isEmptyInvocation.arguments = new Expression[] {};
isEmptyInvocation.receiver = collectionCast; // due to a bug (=simplification) in CastExpression.print... this produces invalid java code upon call of printExpression, e.g. "(java.util.Collection) o.isEmpty()", but it should not matter, since the AST is correct
isEmptyInvocation.selector = "isEmpty".toCharArray();
setGeneratedBy(isEmptyInvocation, source);

AND_AND_Expression collectionAndExpression = new AND_AND_Expression(instanceOfExpression, isEmptyInvocation, OperatorIds.AND_AND);
collectionAndExpression.sourceStart = pS; collectionAndExpression.statementEnd = collectionAndExpression.sourceEnd = pE;
setGeneratedBy(collectionAndExpression, source);


OR_OR_Expression orExpression = new OR_OR_Expression(equalsInvocation, collectionAndExpression, OperatorIds.OR_OR);
orExpression.sourceStart = pS; orExpression.statementEnd = orExpression.sourceEnd = pE;
setGeneratedBy(orExpression, source);

AND_AND_Expression andExpression = new AND_AND_Expression(nullCheck, orExpression, OperatorIds.AND_AND);
andExpression.sourceStart = pS; andExpression.statementEnd = andExpression.sourceEnd = pE;
setGeneratedBy(andExpression, source);

IfStatement ifStatement = new IfStatement(andExpression, throwStatement,0,0);
setGeneratedBy(ifStatement, source);

return ifStatement;
}
}

/**
* Create an annotation of the given name, and is marked as being generated by the given source.
9 changes: 7 additions & 2 deletions src/core/lombok/eclipse/handlers/HandleConstructor.java
Original file line number Diff line number Diff line change
@@ -257,13 +257,18 @@ private ConstructorDeclaration createConstructor(AccessLevel level,
setGeneratedBy(parameter, source);
Annotation[] nonNulls = findAnnotations(field, TransformationsUtil.NON_NULL_PATTERN);
Annotation[] nullables = findAnnotations(field, TransformationsUtil.NULLABLE_PATTERN);
Annotation[] nonEmpties = findAnnotations(field, TransformationsUtil.NON_EMPTY_PATTERN);
if (nonNulls.length != 0) {
Statement nullCheck = generateNullCheck(field, source);
if (nullCheck != null) nullChecks.add(nullCheck);
}
Annotation[] copiedAnnotations = copyAnnotations(source, nonNulls, nullables);
Annotation[] copiedAnnotations = copyAnnotations(source, nonNulls, nullables, nonEmpties);
if (copiedAnnotations.length != 0) parameter.annotations = copiedAnnotations;
params.add(parameter);
if (nonEmpties.length != 0) {
Statement emptyCheck = generateEmptyCheck(field, source);
if (emptyCheck != null) nullChecks.add(emptyCheck);
}
}

nullChecks.addAll(assigns);
@@ -330,7 +335,7 @@ private MethodDeclaration createStaticConstructor(AccessLevel level, String name
Argument parameter = new Argument(field.name, fieldPos, copyType(field.type, source), Modifier.FINAL);
setGeneratedBy(parameter, source);

Annotation[] copiedAnnotations = copyAnnotations(source, findAnnotations(field, TransformationsUtil.NON_NULL_PATTERN), findAnnotations(field, TransformationsUtil.NULLABLE_PATTERN));
Annotation[] copiedAnnotations = copyAnnotations(source, findAnnotations(field, TransformationsUtil.NON_NULL_PATTERN), findAnnotations(field, TransformationsUtil.NULLABLE_PATTERN), findAnnotations(field, TransformationsUtil.NON_EMPTY_PATTERN));
if (copiedAnnotations.length != 0) parameter.annotations = copiedAnnotations;
params.add(parameter);
}
2 changes: 1 addition & 1 deletion src/core/lombok/eclipse/handlers/HandleGetter.java
Original file line number Diff line number Diff line change
@@ -222,7 +222,7 @@ private void createGetterForField(AccessLevel level,
deprecated = new Annotation[] { generateDeprecatedAnnotation(source) };
}

Annotation[] copiedAnnotations = copyAnnotations(source, findAnnotations(field, TransformationsUtil.NON_NULL_PATTERN), findAnnotations(field, TransformationsUtil.NULLABLE_PATTERN), findDelegatesAndMarkAsHandled(fieldNode), deprecated);
Annotation[] copiedAnnotations = copyAnnotations(source, findAnnotations(field, TransformationsUtil.NON_NULL_PATTERN), findAnnotations(field, TransformationsUtil.NULLABLE_PATTERN), findAnnotations(field, TransformationsUtil.NON_EMPTY_PATTERN), findDelegatesAndMarkAsHandled(fieldNode), deprecated);
if (copiedAnnotations.length != 0) {
method.annotations = copiedAnnotations;
}
14 changes: 9 additions & 5 deletions src/core/lombok/eclipse/handlers/HandleSetter.java
Original file line number Diff line number Diff line change
@@ -241,14 +241,18 @@ private MethodDeclaration generateSetter(TypeDeclaration parent, EclipseNode fie

Annotation[] nonNulls = findAnnotations(field, TransformationsUtil.NON_NULL_PATTERN);
Annotation[] nullables = findAnnotations(field, TransformationsUtil.NULLABLE_PATTERN);
Annotation[] nonEmpties = findAnnotations(field, TransformationsUtil.NON_EMPTY_PATTERN);
List<Statement> statements = new ArrayList<Statement>(5);
if (nonNulls.length == 0) {
statements.add(assignment);
} else {

if (nonNulls.length > 0) {
Statement nullCheck = generateNullCheck(field, source);
if (nullCheck != null) statements.add(nullCheck);
statements.add(assignment);
}
if (nonEmpties.length > 0) {
Statement emptyCheck = generateEmptyCheck(field, source);
if (emptyCheck != null) statements.add(emptyCheck);
}
statements.add(assignment);

if (shouldReturnThis) {
ThisReference thisRef = new ThisReference(pS, pE);
@@ -259,7 +263,7 @@ private MethodDeclaration generateSetter(TypeDeclaration parent, EclipseNode fie
}
method.statements = statements.toArray(new Statement[0]);

Annotation[] copiedAnnotations = copyAnnotations(source, nonNulls, nullables);
Annotation[] copiedAnnotations = copyAnnotations(source, nonNulls, nullables, nonEmpties);
if (copiedAnnotations.length != 0) param.annotations = copiedAnnotations;
return method;
}
10 changes: 8 additions & 2 deletions src/core/lombok/javac/handlers/HandleConstructor.java
Original file line number Diff line number Diff line change
@@ -203,7 +203,8 @@ private JCMethodDecl createConstructor(AccessLevel level, JavacNode typeNode, Li
JCVariableDecl field = (JCVariableDecl) fieldNode.get();
List<JCAnnotation> nonNulls = findAnnotations(fieldNode, TransformationsUtil.NON_NULL_PATTERN);
List<JCAnnotation> nullables = findAnnotations(fieldNode, TransformationsUtil.NULLABLE_PATTERN);
JCVariableDecl param = maker.VarDef(maker.Modifiers(Flags.FINAL, nonNulls.appendList(nullables)), field.name, field.vartype, null);
List<JCAnnotation> nonEmpties = findAnnotations(fieldNode, TransformationsUtil.NON_EMPTY_PATTERN);
JCVariableDecl param = maker.VarDef(maker.Modifiers(Flags.FINAL, nonNulls.appendList(nullables).appendList(nonEmpties)), field.name, field.vartype, null);
params.append(param);
JCFieldAccess thisX = maker.Select(maker.Ident(fieldNode.toName("this")), field.name);
JCAssign assign = maker.Assign(thisX, maker.Ident(field.name));
@@ -213,6 +214,10 @@ private JCMethodDecl createConstructor(AccessLevel level, JavacNode typeNode, Li
JCStatement nullCheck = generateNullCheck(maker, fieldNode);
if (nullCheck != null) nullChecks.append(nullCheck);
}
if (!nonEmpties.isEmpty()) {
JCStatement emptyCheck = generateEmptyCheck(maker, fieldNode);
if (emptyCheck != null) nullChecks.append(emptyCheck);
}
}

JCModifiers mods = maker.Modifiers(toJavacModifier(level), List.<JCAnnotation>nil());
@@ -271,7 +276,8 @@ else if (field.vartype instanceof JCTypeApply) {
}
List<JCAnnotation> nonNulls = findAnnotations(fieldNode, TransformationsUtil.NON_NULL_PATTERN);
List<JCAnnotation> nullables = findAnnotations(fieldNode, TransformationsUtil.NULLABLE_PATTERN);
JCVariableDecl param = maker.VarDef(maker.Modifiers(Flags.FINAL, nonNulls.appendList(nullables)), field.name, pType, null);
List<JCAnnotation> nonEmpties = findAnnotations(fieldNode, TransformationsUtil.NON_EMPTY_PATTERN);
JCVariableDecl param = maker.VarDef(maker.Modifiers(Flags.FINAL, nonNulls.appendList(nullables).appendList(nonEmpties)), field.name, pType, null);
params.append(param);
args.append(maker.Ident(field.name));
}
Loading