diff options
author | Reinier Zwitserloot <reinier@zwitserloot.com> | 2011-01-29 16:54:14 +0100 |
---|---|---|
committer | Reinier Zwitserloot <reinier@zwitserloot.com> | 2011-02-07 21:35:34 +0100 |
commit | c98cec7d2ddceddcc0f127185912be4f826a6caa (patch) | |
tree | dc8c50a3ac256a08faac8adde76904bca004cbd8 /src/core/lombok | |
parent | aab3faa3cb43b4a854b5d094f1ef80eb39543bfb (diff) | |
download | lombok-c98cec7d2ddceddcc0f127185912be4f826a6caa.tar.gz lombok-c98cec7d2ddceddcc0f127185912be4f826a6caa.tar.bz2 lombok-c98cec7d2ddceddcc0f127185912be4f826a6caa.zip |
Presence of isFoo(), hasFoo(), and getFoo(), as well as properties named 'isFoo', 'hasFoo', or 'getFoo' would trigger specialized handling for @Getter/@Setter. However, this special handling broke the bean spec, and has been simplified: Only fields named 'isFoo', and only if that field's type is 'boolean', results in both 'isFoo' and 'foo' being considered as possible property names for this property, with 'foo' preferred, so that @Getter boolean isFoo will generate setFoo and isFoo methods, not setIsFoo and isIsFoo.
Fixes issue #148
Diffstat (limited to 'src/core/lombok')
-rw-r--r-- | src/core/lombok/core/handlers/TransformationsUtil.java | 91 | ||||
-rw-r--r-- | src/core/lombok/eclipse/handlers/HandleSetter.java | 31 | ||||
-rw-r--r-- | src/core/lombok/javac/handlers/HandleSetter.java | 27 | ||||
-rw-r--r-- | src/core/lombok/javac/handlers/JavacHandlerUtil.java | 16 |
4 files changed, 112 insertions, 53 deletions
diff --git a/src/core/lombok/core/handlers/TransformationsUtil.java b/src/core/lombok/core/handlers/TransformationsUtil.java index 7f6faf99..50c1ca02 100644 --- a/src/core/lombok/core/handlers/TransformationsUtil.java +++ b/src/core/lombok/core/handlers/TransformationsUtil.java @@ -22,7 +22,6 @@ package lombok.core.handlers; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.List; @@ -38,10 +37,6 @@ public class TransformationsUtil { //Prevent instantiation } - private static final List<String> KNOWN_BOOLEAN_PREFIXES = Collections.unmodifiableList(Arrays.asList( - "is", "has", "get" - )); - /** * Generates a getter name from a given field name. * @@ -54,7 +49,7 @@ public class TransformationsUtil { * * return the prefix plus the possibly title/uppercased first character, and the rest of the field name. * - * Note that for boolean fields, if the field starts with 'has', 'get', or 'is', and the character after that is + * Note that for boolean fields, if the field starts with 'is', and the character after that is * <b>not</b> a lowercase character, the field name is returned without changing any character's case and without * any prefix. * @@ -66,15 +61,9 @@ public class TransformationsUtil { if (fieldName.length() == 0) return prefix; - for (String knownBooleanPrefix : KNOWN_BOOLEAN_PREFIXES) { - if (!fieldName.toString().startsWith(knownBooleanPrefix)) continue; - if (fieldName.length() > knownBooleanPrefix.length() && - !Character.isLowerCase(fieldName.charAt(knownBooleanPrefix.length()))) { - //The field is called something like 'isFoo' or 'hasFoo' or 'getFoo', so we shouldn't - //prefix with 'is' but instead just use the field name as is. The isLowerCase check is so we don't turn - //hashCodeGenerated, which so happens to start with 'has', into hasHCodeGenerated instead of isHashCodeGenerated. - return fieldName.toString(); - } + if (isBoolean && fieldName.toString().startsWith("is") && fieldName.length() > 2 && !Character.isLowerCase(fieldName.charAt(2))) { + // The field is for example named 'isRunning'. + return fieldName.toString(); } return buildName(prefix, fieldName.toString()); @@ -87,7 +76,7 @@ public class TransformationsUtil { public static final Pattern NULLABLE_PATTERN = Pattern.compile("^(?:nullable|checkfornull)$", Pattern.CASE_INSENSITIVE); /** - * Generates a getter name from a given field name. + * Generates a setter name from a given field name. * * Strategy: * @@ -96,9 +85,19 @@ public class TransformationsUtil { * * return "set" plus the possibly title/uppercased first character, and the rest of the field name. * + * Note that if the field is boolean and starts with 'is' followed by a non-lowercase letter, the 'is' is stripped and replaced with 'set'. + * * @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}. */ - public static String toSetterName(CharSequence fieldName) { + public static String toSetterName(CharSequence fieldName, boolean isBoolean) { + if (fieldName.length() == 0) return "set"; + + if (isBoolean && fieldName.toString().startsWith("is") && fieldName.length() > 2 && !Character.isLowerCase(fieldName.charAt(2))) { + // The field is for example named 'isRunning'. + return "set" + fieldName.toString().substring(2); + } + return buildName("set", fieldName.toString()); } @@ -116,21 +115,24 @@ public class TransformationsUtil { return String.format("%s%s", prefix, suffix); } + /** + * Returns all names of methods that would represent the getter for a field with the provided name. + * + * For example if {@code isBoolean} is true, then a field named {@code isRunning} would produce:<br /> + * {@code [isRunning, getRunning, isIsRunning, getIsRunning]} + * + * @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}. + */ public static List<String> toAllGetterNames(CharSequence fieldName, boolean isBoolean) { if (!isBoolean) return Collections.singletonList(toGetterName(fieldName, false)); List<String> baseNames = new ArrayList<String>(); baseNames.add(fieldName.toString()); - for (String knownBooleanPrefix : KNOWN_BOOLEAN_PREFIXES) { - if (!fieldName.toString().startsWith(knownBooleanPrefix)) continue; - if (fieldName.length() > knownBooleanPrefix.length() && - !Character.isLowerCase(fieldName.charAt(knownBooleanPrefix.length()))) { - //The field is called something like 'isFoo' or 'hasFoo' or 'getFoo', so the practical fieldname - //could also be 'foo'. - baseNames.add(fieldName.toString().substring(knownBooleanPrefix.length())); - //prefix with 'is' but instead just use the field name as is. The isLowerCase check is so we don't turn - //hashCodeGenerated, which so happens to start with 'has', into hashCodeGenerated instead of isHashCodeGenerated. - } + + // isPrefix = field is called something like 'isRunning', so 'running' could also be the fieldname. + if (fieldName.toString().startsWith("is") && fieldName.length() > 2 && !Character.isLowerCase(fieldName.charAt(2))) { + baseNames.add(fieldName.toString().substring(2)); } Set<String> names = new HashSet<String>(); @@ -139,9 +141,40 @@ public class TransformationsUtil { baseName = Character.toTitleCase(baseName.charAt(0)) + baseName.substring(1); } - for (String prefix : KNOWN_BOOLEAN_PREFIXES) { - names.add(prefix + baseName); + names.add("is" + baseName); + names.add("get" + baseName); + } + + return new ArrayList<String>(names); + } + + /** + * Returns all names of methods that would represent the setter for a field with the provided name. + * + * For example if {@code isBoolean} is true, then a field named {@code isRunning} would produce:<br /> + * {@code [setRunning, setIsRunning]} + * + * @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}. + */ + public static List<String> toAllSetterNames(CharSequence fieldName, boolean isBoolean) { + if (!isBoolean) return Collections.singletonList(toSetterName(fieldName, false)); + + List<String> baseNames = new ArrayList<String>(); + baseNames.add(fieldName.toString()); + + // isPrefix = field is called something like 'isRunning', so 'running' could also be the fieldname. + if (fieldName.toString().startsWith("is") && fieldName.length() > 2 && !Character.isLowerCase(fieldName.charAt(2))) { + baseNames.add(fieldName.toString().substring(2)); + } + + Set<String> names = new HashSet<String>(); + for (String baseName : baseNames) { + if (baseName.length() > 0 && Character.isLowerCase(baseName.charAt(0))) { + baseName = Character.toTitleCase(baseName.charAt(0)) + baseName.substring(1); } + + names.add("set" + baseName); } return new ArrayList<String>(names); diff --git a/src/core/lombok/eclipse/handlers/HandleSetter.java b/src/core/lombok/eclipse/handlers/HandleSetter.java index 14ff0e10..945495c6 100644 --- a/src/core/lombok/eclipse/handlers/HandleSetter.java +++ b/src/core/lombok/eclipse/handlers/HandleSetter.java @@ -157,21 +157,28 @@ public class HandleSetter implements EclipseAnnotationHandler<Setter> { } FieldDeclaration field = (FieldDeclaration) fieldNode.get(); - String setterName = TransformationsUtil.toSetterName(new String(field.name)); + TypeReference fieldType = copyType(field.type, source); + boolean isBoolean = nameEquals(fieldType.getTypeName(), "boolean") && fieldType.dimensions() == 0; + String setterName = TransformationsUtil.toSetterName(new String(field.name), isBoolean); int modifier = toEclipseModifier(level) | (field.modifiers & ClassFileConstants.AccStatic); - switch (methodExists(setterName, fieldNode, false)) { - case EXISTS_BY_LOMBOK: - return true; - case EXISTS_BY_USER: - if (whineIfExists) errorNode.addWarning( - String.format("Not generating %s(%s %s): A method with that name already exists", - setterName, field.type, new String(field.name))); - return true; - default: - case NOT_EXISTS: - //continue with creating the setter + for (String altName : TransformationsUtil.toAllSetterNames(new String(field.name), isBoolean)) { + switch (methodExists(altName, fieldNode, false)) { + case EXISTS_BY_LOMBOK: + return true; + case EXISTS_BY_USER: + if (whineIfExists) { + String altNameExpl = ""; + if (!altName.equals(setterName)) altNameExpl = String.format(" (%s)", altName); + errorNode.addWarning( + String.format("Not generating %s(): A method with that name already exists%s", setterName, altNameExpl)); + } + return true; + default: + case NOT_EXISTS: + //continue scanning the other alt names. + } } MethodDeclaration method = generateSetter((TypeDeclaration) fieldNode.up().get(), fieldNode, setterName, modifier, source, onParam); diff --git a/src/core/lombok/javac/handlers/HandleSetter.java b/src/core/lombok/javac/handlers/HandleSetter.java index 6dd88abd..ec5195ac 100644 --- a/src/core/lombok/javac/handlers/HandleSetter.java +++ b/src/core/lombok/javac/handlers/HandleSetter.java @@ -174,17 +174,22 @@ public class HandleSetter implements JavacAnnotationHandler<Setter> { JCVariableDecl fieldDecl = (JCVariableDecl)fieldNode.get(); String methodName = toSetterName(fieldDecl); - switch (methodExists(methodName, fieldNode, false)) { - case EXISTS_BY_LOMBOK: - return true; - case EXISTS_BY_USER: - if (whineIfExists) errorNode.addWarning( - String.format("Not generating %s(%s %s): A method with that name already exists", - methodName, fieldDecl.vartype, fieldDecl.name)); - return true; - default: - case NOT_EXISTS: - //continue with creating the setter + for (String altName : toAllSetterNames(fieldDecl)) { + switch (methodExists(altName, fieldNode, false)) { + case EXISTS_BY_LOMBOK: + return true; + case EXISTS_BY_USER: + if (whineIfExists) { + String altNameExpl = ""; + if (!altName.equals(methodName)) altNameExpl = String.format(" (%s)", altName); + errorNode.addWarning( + String.format("Not generating %s(): A method with that name already exists%s", methodName, altNameExpl)); + } + return true; + default: + case NOT_EXISTS: + //continue scanning the other alt names. + } } long access = toJavacModifier(level) | (fieldDecl.mods.flags & Flags.STATIC); diff --git a/src/core/lombok/javac/handlers/JavacHandlerUtil.java b/src/core/lombok/javac/handlers/JavacHandlerUtil.java index aa4e1bb2..1fb72dfa 100644 --- a/src/core/lombok/javac/handlers/JavacHandlerUtil.java +++ b/src/core/lombok/javac/handlers/JavacHandlerUtil.java @@ -159,6 +159,18 @@ public class JavacHandlerUtil { } /** + * Translates the given field into all possible setter names. + * Convenient wrapper around {@link TransformationsUtil#toAllSetterNames(CharSequence, boolean)}. + */ + public static java.util.List<String> toAllSetterNames(JCVariableDecl field) { + CharSequence fieldName = field.name; + + boolean isBoolean = field.vartype.toString().equals("boolean"); + + return TransformationsUtil.toAllSetterNames(fieldName, isBoolean); + } + + /** * @return the likely setter name for the stated field. (e.g. private boolean foo; to setFoo). * * Convenient wrapper around {@link TransformationsUtil#toSetterName(CharSequence)}. @@ -166,7 +178,9 @@ public class JavacHandlerUtil { public static String toSetterName(JCVariableDecl field) { CharSequence fieldName = field.name; - return TransformationsUtil.toSetterName(fieldName); + boolean isBoolean = field.vartype.toString().equals("boolean"); + + return TransformationsUtil.toSetterName(fieldName, isBoolean); } /** Serves as return value for the methods that check for the existence of fields and methods. */ |