diff options
15 files changed, 408 insertions, 12 deletions
diff --git a/src/core/lombok/ConfigurationKeys.java b/src/core/lombok/ConfigurationKeys.java index b8cd442a..12307471 100644 --- a/src/core/lombok/ConfigurationKeys.java +++ b/src/core/lombok/ConfigurationKeys.java @@ -558,6 +558,14 @@ public class ConfigurationKeys { */ public static final ConfigurationKey<Boolean> ACCESSORS_FLUENT = new ConfigurationKey<Boolean>("lombok.accessors.fluent", "Generate getters and setters using only the field name (no get/set prefix) (default: false).") {}; + /** + * lombok configuration: {@code lombok.accessors.javaBeansSpecCapitalization} = {@code true} | {@code false}. + * + * For any class without an {@code @Accessors} that explicitly defines the {@code javaBeansSpecCapitalization} option, this value is used (default = false). + */ + public static final ConfigurationKey<Boolean> ACCESSORS_JAVA_BEANS_SPEC_CAPITALIZATION = new ConfigurationKey<Boolean>("lombok.accessors.javaBeansSpecCapitalization", "Generating accessors name according to the JavaBeans Spec (default: false).") {}; + + // ----- ExtensionMethod ----- /** diff --git a/src/core/lombok/core/handlers/HandlerUtil.java b/src/core/lombok/core/handlers/HandlerUtil.java index f88d1679..f45481d4 100644 --- a/src/core/lombok/core/handlers/HandlerUtil.java +++ b/src/core/lombok/core/handlers/HandlerUtil.java @@ -585,11 +585,13 @@ public class HandlerUtil { if (Boolean.TRUE.equals(ast.readConfiguration(ConfigurationKeys.GETTER_CONSEQUENT_BOOLEAN))) isBoolean = false; boolean explicitPrefix = accessors != null && accessors.isExplicit("prefix"); boolean explicitFluent = accessors != null && accessors.isExplicit("fluent"); + boolean explicitJavaBeansSpecCapitalization = accessors != null && accessors.isExplicit("javaBeansSpecCapitalization"); - Accessors ac = (explicitPrefix || explicitFluent) ? accessors.getInstance() : null; + Accessors ac = (explicitPrefix || explicitFluent || explicitJavaBeansSpecCapitalization) ? accessors.getInstance() : null; List<String> prefix = explicitPrefix ? Arrays.asList(ac.prefix()) : ast.readConfiguration(ConfigurationKeys.ACCESSORS_PREFIX); boolean fluent = explicitFluent ? ac.fluent() : Boolean.TRUE.equals(ast.readConfiguration(ConfigurationKeys.ACCESSORS_FLUENT)); + boolean javaBeansSpecCapitalization = explicitJavaBeansSpecCapitalization ? ac.javaBeansSpecCapitalization() : Boolean.TRUE.equals(ast.readConfiguration(ConfigurationKeys.ACCESSORS_JAVA_BEANS_SPEC_CAPITALIZATION)); fieldName = removePrefix(fieldName, prefix); if (fieldName == null) return null; @@ -602,7 +604,7 @@ public class HandlerUtil { return booleanPrefix + fName.substring(2); } - return buildAccessorName(isBoolean ? booleanPrefix : normalPrefix, fName); + return buildAccessorName(isBoolean ? booleanPrefix : normalPrefix, fName, javaBeansSpecCapitalization); } /** @@ -675,12 +677,14 @@ public class HandlerUtil { boolean explicitPrefix = accessors != null && accessors.isExplicit("prefix"); boolean explicitFluent = accessors != null && accessors.isExplicit("fluent"); + boolean explicitJavaBeansSpecCapitalization = accessors != null && accessors.isExplicit("javaBeansSpecCapitalization"); - Accessors ac = (explicitPrefix || explicitFluent) ? accessors.getInstance() : null; + Accessors ac = (explicitPrefix || explicitFluent || explicitJavaBeansSpecCapitalization) ? accessors.getInstance() : null; List<String> prefix = explicitPrefix ? Arrays.asList(ac.prefix()) : ast.readConfiguration(ConfigurationKeys.ACCESSORS_PREFIX); boolean fluent = explicitFluent ? ac.fluent() : Boolean.TRUE.equals(ast.readConfiguration(ConfigurationKeys.ACCESSORS_FLUENT)); - + boolean javaBeansSpecCapitalization = explicitJavaBeansSpecCapitalization ? ac.javaBeansSpecCapitalization() : Boolean.TRUE.equals(ast.readConfiguration(ConfigurationKeys.ACCESSORS_JAVA_BEANS_SPEC_CAPITALIZATION)); + fieldName = removePrefix(fieldName, prefix); if (fieldName == null) return Collections.emptyList(); @@ -691,8 +695,8 @@ public class HandlerUtil { if (adhereToFluent && fluent) { names.add(baseName); } else { - names.add(buildAccessorName(normalPrefix, baseName)); - if (!normalPrefix.equals(booleanPrefix)) names.add(buildAccessorName(booleanPrefix, baseName)); + names.add(buildAccessorName(normalPrefix, baseName, javaBeansSpecCapitalization)); + if (!normalPrefix.equals(booleanPrefix)) names.add(buildAccessorName(booleanPrefix, baseName, javaBeansSpecCapitalization)); } } @@ -723,17 +727,34 @@ public class HandlerUtil { * @return prefix + smartly title-cased suffix. For example, {@code setRunning}. */ public static String buildAccessorName(String prefix, String suffix) { + return buildAccessorName(prefix, suffix, false); + } + + /** + * @param prefix Something like {@code get} or {@code set} or {@code is}. + * @param suffix Something like {@code running}. + * @param shouldFollowJavaBeansSpecCapitalization {@code boolean} that indicates whether the capitalization rules should follow JavaBeanSpec + * @return if shouldFollowJavaBeansSpecCapitalization is {@code true} and name start with only single lowercase letter, returns simple suffix+prefix. For example, {@code setaFieldName} + * otherwise, returns prefix + smartly title-cased suffix. For example, {@code setRunning}. + */ + private static String buildAccessorName(String prefix, String suffix, boolean shouldFollowJavaBeansSpecCapitalization) { if (suffix.length() == 0) return prefix; if (prefix.length() == 0) return suffix; char first = suffix.charAt(0); - 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())); + if (!Character.isLowerCase(first)) { + return String.format("%s%s", prefix, suffix); } + + boolean useUpperCase = suffix.length() > 2 && + (Character.isTitleCase(suffix.charAt(1)) || Character.isUpperCase(suffix.charAt(1))); + if (shouldFollowJavaBeansSpecCapitalization && useUpperCase) { + return String.format("%s%s", prefix, suffix); + } + + suffix = String.format("%s%s", + useUpperCase ? Character.toUpperCase(first) : Character.toTitleCase(first), + suffix.subSequence(1, suffix.length())); return String.format("%s%s", prefix, suffix); } diff --git a/src/core/lombok/experimental/Accessors.java b/src/core/lombok/experimental/Accessors.java index dc9ae4b0..b3da9a5b 100644 --- a/src/core/lombok/experimental/Accessors.java +++ b/src/core/lombok/experimental/Accessors.java @@ -55,6 +55,15 @@ public @interface Accessors { boolean chain() default false; /** + * If true, accessors names will be capitalized according to JavaBeans capitalization rules. + * If {@code true}, an accessor for a field that starts with a single lowercase letter followed by a capital letter, + * wont capitalize the first letter (named {@code getaFieldName()}, not for example {@code getAFieldName}). + * <strong>default: false</strong> + * @return + */ + boolean javaBeansSpecCapitalization() default false; + + /** * If present, only fields with any of the stated prefixes are given the getter/setter treatment. * Note that a prefix only counts if the next character is NOT a lowercase character or the last * letter of the prefix is not a letter (for instance an underscore). If multiple fields diff --git a/test/transform/resource/after-delombok/GetterWithJavaBeansSpecCapitalization.java b/test/transform/resource/after-delombok/GetterWithJavaBeansSpecCapitalization.java new file mode 100644 index 00000000..06026c1b --- /dev/null +++ b/test/transform/resource/after-delombok/GetterWithJavaBeansSpecCapitalization.java @@ -0,0 +1,28 @@ +class GetterWithoutJavaBeansSpecCapitalization { + int a; + int aField; + @java.lang.SuppressWarnings("all") + public int getA() { + return this.a; + } + @java.lang.SuppressWarnings("all") + public int getAField() { + return this.aField; + } +} + + +class GetterWithJavaBeansSpecCapitalization { + int a; + int aField; + @java.lang.SuppressWarnings("all") + public int getA() { + return this.a; + } + @java.lang.SuppressWarnings("all") + public int getaField() { + return this.aField; + } +} + + diff --git a/test/transform/resource/after-delombok/SetterWithJavaBeansSpecCapitalization.java b/test/transform/resource/after-delombok/SetterWithJavaBeansSpecCapitalization.java new file mode 100644 index 00000000..24c8e883 --- /dev/null +++ b/test/transform/resource/after-delombok/SetterWithJavaBeansSpecCapitalization.java @@ -0,0 +1,27 @@ +class SetterWithoutJavaBeansSpecCapitalization { + int a; + int aField; + @java.lang.SuppressWarnings("all") + public void setA(final int a) { + this.a = a; + } + @java.lang.SuppressWarnings("all") + public void setAField(final int aField) { + this.aField = aField; + } +} + +class SetterWithJavaBeansSpecCapitalization { + int a; + int aField; + @java.lang.SuppressWarnings("all") + public void setA(final int a) { + this.a = a; + } + @java.lang.SuppressWarnings("all") + public void setaField(final int aField) { + this.aField = aField; + } +} + + diff --git a/test/transform/resource/after-delombok/ValueWithJavaBeansSpecCapitalization.java b/test/transform/resource/after-delombok/ValueWithJavaBeansSpecCapitalization.java new file mode 100644 index 00000000..20139baf --- /dev/null +++ b/test/transform/resource/after-delombok/ValueWithJavaBeansSpecCapitalization.java @@ -0,0 +1,77 @@ +final class ValueWithJavaBeansSpecCapitalization { + private final int aField; + + @java.lang.SuppressWarnings("all") + public ValueWithJavaBeansSpecCapitalization(final int aField) { + this.aField = aField; + } + + @java.lang.SuppressWarnings("all") + public int getaField() { + return this.aField; + } + + @java.lang.Override + @java.lang.SuppressWarnings("all") + public boolean equals(final java.lang.Object o) { + if (o == this) return true; + if (!(o instanceof ValueWithJavaBeansSpecCapitalization)) return false; + final ValueWithJavaBeansSpecCapitalization other = (ValueWithJavaBeansSpecCapitalization) o; + if (this.getaField() != other.getaField()) return false; + return true; + } + + @java.lang.Override + @java.lang.SuppressWarnings("all") + public int hashCode() { + final int PRIME = 59; + int result = 1; + result = result * PRIME + this.getaField(); + return result; + } + + @java.lang.Override + @java.lang.SuppressWarnings("all") + public java.lang.String toString() { + return "ValueWithJavaBeansSpecCapitalization(aField=" + this.getaField() + ")"; + } +} + +final class ValueWithoutJavaBeansSpecCapitalization { + private final int aField; + + @java.lang.SuppressWarnings("all") + public ValueWithoutJavaBeansSpecCapitalization(final int aField) { + this.aField = aField; + } + + @java.lang.SuppressWarnings("all") + public int getAField() { + return this.aField; + } + + @java.lang.Override + @java.lang.SuppressWarnings("all") + public boolean equals(final java.lang.Object o) { + if (o == this) return true; + if (!(o instanceof ValueWithoutJavaBeansSpecCapitalization)) return false; + final ValueWithoutJavaBeansSpecCapitalization other = (ValueWithoutJavaBeansSpecCapitalization) o; + if (this.getAField() != other.getAField()) return false; + return true; + } + + @java.lang.Override + @java.lang.SuppressWarnings("all") + public int hashCode() { + final int PRIME = 59; + int result = 1; + result = result * PRIME + this.getAField(); + return result; + } + + @java.lang.Override + @java.lang.SuppressWarnings("all") + public java.lang.String toString() { + return "ValueWithoutJavaBeansSpecCapitalization(aField=" + this.getAField() + ")"; + } +} diff --git a/test/transform/resource/after-delombok/WithOnJavaBeansSpecCapitalization.java b/test/transform/resource/after-delombok/WithOnJavaBeansSpecCapitalization.java new file mode 100644 index 00000000..afed2f0e --- /dev/null +++ b/test/transform/resource/after-delombok/WithOnJavaBeansSpecCapitalization.java @@ -0,0 +1,29 @@ +class WithOnJavaBeansSpecCapitalization { + int aField; + + WithOnJavaBeansSpecCapitalization(int aField) { + } + + /** + * @return a clone of this object, except with this updated property (returns {@code this} if an identical value is passed). + */ + @java.lang.SuppressWarnings("all") + public WithOnJavaBeansSpecCapitalization withaField(final int aField) { + return this.aField == aField ? this : new WithOnJavaBeansSpecCapitalization(aField); + } +} + +class WithOffJavaBeansSpecCapitalization { + int aField; + + WithOffJavaBeansSpecCapitalization(int aField) { + } + + /** + * @return a clone of this object, except with this updated property (returns {@code this} if an identical value is passed). + */ + @java.lang.SuppressWarnings("all") + public WithOffJavaBeansSpecCapitalization withAField(final int aField) { + return this.aField == aField ? this : new WithOffJavaBeansSpecCapitalization(aField); + } +} diff --git a/test/transform/resource/after-ecj/GetterWithJavaBeansSpecCapitalization.java b/test/transform/resource/after-ecj/GetterWithJavaBeansSpecCapitalization.java new file mode 100644 index 00000000..d605b4ac --- /dev/null +++ b/test/transform/resource/after-ecj/GetterWithJavaBeansSpecCapitalization.java @@ -0,0 +1,33 @@ +class GetterWithoutJavaBeansSpecCapitalization { + @lombok.Getter int a; + @lombok.Getter int aField; + + GetterWithoutJavaBeansSpecCapitalization() { + super(); + } + + public @java.lang.SuppressWarnings("all") int getA() { + return this.a; + } + + public @java.lang.SuppressWarnings("all") int getAField() { + return this.aField; + } +} + +@lombok.experimental.Accessors(javaBeansSpecCapitalization = true) class GetterWithJavaBeansSpecCapitalization { + @lombok.Getter int a; + @lombok.Getter int aField; + + GetterWithJavaBeansSpecCapitalization() { + super(); + } + + public @java.lang.SuppressWarnings("all") int getA() { + return this.a; + } + + public @java.lang.SuppressWarnings("all") int getaField() { + return this.aField; + } +} diff --git a/test/transform/resource/after-ecj/SetterWithJavaBeansSpecCapitalization.java b/test/transform/resource/after-ecj/SetterWithJavaBeansSpecCapitalization.java new file mode 100644 index 00000000..9907621f --- /dev/null +++ b/test/transform/resource/after-ecj/SetterWithJavaBeansSpecCapitalization.java @@ -0,0 +1,33 @@ +class SetterWithoutJavaBeansSpecCapitalization { + @lombok.Setter int a; + @lombok.Setter int aField; + + SetterWithoutJavaBeansSpecCapitalization() { + super(); + } + + public @java.lang.SuppressWarnings("all") void setA(final int a) { + this.a = a; + } + + public @java.lang.SuppressWarnings("all") void setAField(final int aField) { + this.aField = aField; + } +} + +@lombok.experimental.Accessors(javaBeansSpecCapitalization = true) class SetterWithJavaBeansSpecCapitalization { + @lombok.Setter int a; + @lombok.Setter int aField; + + SetterWithJavaBeansSpecCapitalization() { + super(); + } + + public @java.lang.SuppressWarnings("all") void setA(final int a) { + this.a = a; + } + + public @java.lang.SuppressWarnings("all") void setaField(final int aField) { + this.aField = aField; + } +} diff --git a/test/transform/resource/after-ecj/ValueWithJavaBeansSpecCapitalization.java b/test/transform/resource/after-ecj/ValueWithJavaBeansSpecCapitalization.java new file mode 100644 index 00000000..f41fcf58 --- /dev/null +++ b/test/transform/resource/after-ecj/ValueWithJavaBeansSpecCapitalization.java @@ -0,0 +1,58 @@ +final @lombok.Value @lombok.experimental.Accessors(javaBeansSpecCapitalization = true) class ValueWithJavaBeansSpecCapitalization { + private final int aField; + public @java.lang.SuppressWarnings("all") int getaField() { + return this.aField; + } + public @java.lang.Override @java.lang.SuppressWarnings("all") boolean equals(final java.lang.Object o) { + if ((o == this)) + return true; + if ((! (o instanceof ValueWithJavaBeansSpecCapitalization))) + return false; + final ValueWithJavaBeansSpecCapitalization other = (ValueWithJavaBeansSpecCapitalization) o; + if ((this.getaField() != other.getaField())) + return false; + return true; + } + public @java.lang.Override @java.lang.SuppressWarnings("all") int hashCode() { + final int PRIME = 59; + int result = 1; + result = ((result * PRIME) + this.getaField()); + return result; + } + public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() { + return (("ValueWithJavaBeansSpecCapitalization(aField=" + this.getaField()) + ")"); + } + public @java.lang.SuppressWarnings("all") ValueWithJavaBeansSpecCapitalization(final int aField) { + super(); + this.aField = aField; + } +} +final @lombok.Value class ValueWithoutJavaBeansSpecCapitalization { + private final int aField; + public @java.lang.SuppressWarnings("all") int getAField() { + return this.aField; + } + public @java.lang.Override @java.lang.SuppressWarnings("all") boolean equals(final java.lang.Object o) { + if ((o == this)) + return true; + if ((! (o instanceof ValueWithoutJavaBeansSpecCapitalization))) + return false; + final ValueWithoutJavaBeansSpecCapitalization other = (ValueWithoutJavaBeansSpecCapitalization) o; + if ((this.getAField() != other.getAField())) + return false; + return true; + } + public @java.lang.Override @java.lang.SuppressWarnings("all") int hashCode() { + final int PRIME = 59; + int result = 1; + result = ((result * PRIME) + this.getAField()); + return result; + } + public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() { + return (("ValueWithoutJavaBeansSpecCapitalization(aField=" + this.getAField()) + ")"); + } + public @java.lang.SuppressWarnings("all") ValueWithoutJavaBeansSpecCapitalization(final int aField) { + super(); + this.aField = aField; + } +} diff --git a/test/transform/resource/after-ecj/WithOnJavaBeansSpecCapitalization.java b/test/transform/resource/after-ecj/WithOnJavaBeansSpecCapitalization.java new file mode 100644 index 00000000..06164fe9 --- /dev/null +++ b/test/transform/resource/after-ecj/WithOnJavaBeansSpecCapitalization.java @@ -0,0 +1,25 @@ +@lombok.With @lombok.experimental.Accessors(javaBeansSpecCapitalization = true) class WithOnJavaBeansSpecCapitalization { + int aField; + WithOnJavaBeansSpecCapitalization(int aField) { + super(); + } + /** + * @return a clone of this object, except with this updated property (returns {@code this} if an identical value is passed). + */ + public @java.lang.SuppressWarnings("all") WithOnJavaBeansSpecCapitalization withaField(final int aField) { + return ((this.aField == aField) ? this : new WithOnJavaBeansSpecCapitalization(aField)); + } +} + +@lombok.With class WithOffJavaBeansSpecCapitalization { + int aField; + WithOffJavaBeansSpecCapitalization(int aField) { + super(); + } + /** + * @return a clone of this object, except with this updated property (returns {@code this} if an identical value is passed). + */ + public @java.lang.SuppressWarnings("all") WithOffJavaBeansSpecCapitalization withAField(final int aField) { + return ((this.aField == aField) ? this : new WithOffJavaBeansSpecCapitalization(aField)); + } +} diff --git a/test/transform/resource/before/GetterWithJavaBeansSpecCapitalization.java b/test/transform/resource/before/GetterWithJavaBeansSpecCapitalization.java new file mode 100644 index 00000000..3c27317c --- /dev/null +++ b/test/transform/resource/before/GetterWithJavaBeansSpecCapitalization.java @@ -0,0 +1,11 @@ +class GetterWithoutJavaBeansSpecCapitalization { + @lombok.Getter int a; + @lombok.Getter int aField; +} + +@lombok.experimental.Accessors(javaBeansSpecCapitalization=true) +class GetterWithJavaBeansSpecCapitalization { + @lombok.Getter int a; + @lombok.Getter int aField; +} + diff --git a/test/transform/resource/before/SetterWithJavaBeansSpecCapitalization.java b/test/transform/resource/before/SetterWithJavaBeansSpecCapitalization.java new file mode 100644 index 00000000..80a1b4ee --- /dev/null +++ b/test/transform/resource/before/SetterWithJavaBeansSpecCapitalization.java @@ -0,0 +1,11 @@ +class SetterWithoutJavaBeansSpecCapitalization { + @lombok.Setter int a; + @lombok.Setter int aField; +} + +@lombok.experimental.Accessors(javaBeansSpecCapitalization=true) +class SetterWithJavaBeansSpecCapitalization { + @lombok.Setter int a; + @lombok.Setter int aField; +} + diff --git a/test/transform/resource/before/ValueWithJavaBeansSpecCapitalization.java b/test/transform/resource/before/ValueWithJavaBeansSpecCapitalization.java new file mode 100644 index 00000000..f0044ed9 --- /dev/null +++ b/test/transform/resource/before/ValueWithJavaBeansSpecCapitalization.java @@ -0,0 +1,10 @@ +@lombok.Value +@lombok.experimental.Accessors(javaBeansSpecCapitalization = true) +class ValueWithJavaBeansSpecCapitalization { + final int aField; +} + +@lombok.Value +class ValueWithoutJavaBeansSpecCapitalization { + final int aField; +} diff --git a/test/transform/resource/before/WithOnJavaBeansSpecCapitalization.java b/test/transform/resource/before/WithOnJavaBeansSpecCapitalization.java new file mode 100644 index 00000000..476fb5a4 --- /dev/null +++ b/test/transform/resource/before/WithOnJavaBeansSpecCapitalization.java @@ -0,0 +1,16 @@ +@lombok.With +@lombok.experimental.Accessors(javaBeansSpecCapitalization = true) +class WithOnJavaBeansSpecCapitalization { + int aField; + + WithOnJavaBeansSpecCapitalization(int aField) { + } +} + +@lombok.With +class WithOffJavaBeansSpecCapitalization { + int aField; + + WithOffJavaBeansSpecCapitalization(int aField) { + } +} |