mirror of
https://github.com/tiennm99/lombok.git
synced 2026-10-13 16:15:16 +00:00
Addresses issue #4:
If boolean fields already start with a typical getter prefix (is, has, or get), lombok's @Getter will no longer generate its own prefix as well, so a field named 'hasFoo' will result in a getter named 'hasFoo()', not 'isHasFoo()'. Also, if any likely getter name already exists for a boolean, a getter will not be generated. Thus, if your field is called 'hasFoo', and you already have a method named 'isFoo', then @Getter will not generate anything (and warn, unless the getter is being generated due to @Data). This last mechanism works by taking the field name *AND* any other likely base names (defined by the field name being named as prefix+baseName, with prefix being is/has/get), and then prefixing all the likely fieldnames with is/has/get, and checking if any method with that name exists. Of course, this means weird things are going to happen if you have 2 fields named 'isFoo' and 'hasFoo', but then, you'd be a real idiot if you did that.
This commit is contained in:
1 parent
0d9bde828d
commit
a9d2989688
4 files changed
+100
-22
No files matched your search
@@ -21,6 +21,13 @@
|
||||
*/
|
||||
package lombok.core;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* 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).
|
||||
@@ -30,6 +37,10 @@ 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.
|
||||
*
|
||||
@@ -42,6 +53,10 @@ 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
|
||||
* <b>not</b> a lowercase character, the field name is returned without changing any character's case and without
|
||||
* any prefix.
|
||||
*
|
||||
* @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>.
|
||||
*/
|
||||
@@ -50,6 +65,17 @@ 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();
|
||||
}
|
||||
}
|
||||
|
||||
return buildName(prefix, fieldName.toString());
|
||||
}
|
||||
|
||||
@@ -82,4 +108,35 @@ public class TransformationsUtil {
|
||||
}
|
||||
return String.format("%s%s", prefix, suffix);
|
||||
}
|
||||
|
||||
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.
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
for ( String prefix : KNOWN_BOOLEAN_PREFIXES ) {
|
||||
names.add(prefix + baseName);
|
||||
}
|
||||
}
|
||||
|
||||
return new ArrayList<String>(names);
|
||||
}
|
||||
}
|
||||
@@ -88,21 +88,28 @@ public class HandleGetter implements EclipseAnnotationHandler<Getter> {
|
||||
|
||||
FieldDeclaration field = (FieldDeclaration) fieldNode.get();
|
||||
TypeReference fieldType = Eclipse.copyType(field.type);
|
||||
String getterName = TransformationsUtil.toGetterName(
|
||||
new String(field.name), nameEquals(fieldType.getTypeName(), "boolean") && fieldType.dimensions() == 0);
|
||||
String fieldName = new String(field.name);
|
||||
boolean isBoolean = nameEquals(fieldType.getTypeName(), "boolean") && fieldType.dimensions() == 0;
|
||||
String getterName = TransformationsUtil.toGetterName(fieldName, isBoolean);
|
||||
|
||||
int modifier = toModifier(level) | (field.modifiers & ClassFileConstants.AccStatic);
|
||||
|
||||
switch ( methodExists(getterName, fieldNode) ) {
|
||||
case EXISTS_BY_LOMBOK:
|
||||
return true;
|
||||
case EXISTS_BY_USER:
|
||||
if ( whineIfExists ) errorNode.addWarning(
|
||||
String.format("Not generating %s(): A method with that name already exists", getterName));
|
||||
return true;
|
||||
default:
|
||||
case NOT_EXISTS:
|
||||
//continue with creating the getter
|
||||
for ( String altName : TransformationsUtil.toAllGetterNames(fieldName, isBoolean) ) {
|
||||
switch ( methodExists(altName, fieldNode) ) {
|
||||
case EXISTS_BY_LOMBOK:
|
||||
return true;
|
||||
case EXISTS_BY_USER:
|
||||
if ( whineIfExists ) {
|
||||
String altNameExpl = "";
|
||||
if ( !altName.equals(getterName) ) altNameExpl = String.format("(%s)", altName);
|
||||
errorNode.addWarning(
|
||||
String.format("Not generating %s(): A method with that name already exists%s", getterName, altNameExpl));
|
||||
}
|
||||
return true;
|
||||
default:
|
||||
case NOT_EXISTS:
|
||||
//continue scanning the other alt names.
|
||||
}
|
||||
}
|
||||
|
||||
MethodDeclaration method = generateGetter((TypeDeclaration) fieldNode.up().get(), field, getterName, modifier, pos);
|
||||
|
||||
@@ -90,16 +90,22 @@ public class HandleGetter implements JavacAnnotationHandler<Getter> {
|
||||
JCVariableDecl fieldDecl = (JCVariableDecl)fieldNode.get();
|
||||
String methodName = toGetterName(fieldDecl);
|
||||
|
||||
switch ( methodExists(methodName, fieldNode) ) {
|
||||
case EXISTS_BY_LOMBOK:
|
||||
return true;
|
||||
case EXISTS_BY_USER:
|
||||
if ( whineIfExists ) errorNode.addWarning(
|
||||
String.format("Not generating %s(): A method with that name already exists", methodName));
|
||||
return true;
|
||||
default:
|
||||
case NOT_EXISTS:
|
||||
//continue with creating the getter
|
||||
for ( String altName : toAllGetterNames(fieldDecl) ) {
|
||||
switch ( methodExists(altName, fieldNode) ) {
|
||||
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);
|
||||
|
||||
@@ -45,6 +45,14 @@ class PKG {
|
||||
//Prevent instantiation
|
||||
}
|
||||
|
||||
static java.util.List<String> toAllGetterNames(JCVariableDecl field) {
|
||||
CharSequence fieldName = field.name;
|
||||
|
||||
boolean isBoolean = field.vartype.toString().equals("boolean");
|
||||
|
||||
return TransformationsUtil.toAllGetterNames(fieldName, isBoolean);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the likely getter name for the stated field. (e.g. private boolean foo; to isFoo).
|
||||
*/
|
||||
|
||||
Reference in new issue
Block a user