Skip to content

Commit

Permalink
Adding a new accessors flag - javaBeansSpecCapitalization
Browse files Browse the repository at this point in the history
  • Loading branch information
ysherwin committed Oct 17, 2021
1 parent 4d568ab commit d2e8370
Show file tree
Hide file tree
Showing 15 changed files with 408 additions and 12 deletions.
8 changes: 8 additions & 0 deletions src/core/lombok/ConfigurationKeys.java
Expand Up @@ -558,6 +558,14 @@ private 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 -----

/**
Expand Down
45 changes: 33 additions & 12 deletions src/core/lombok/core/handlers/HandlerUtil.java
Expand Up @@ -585,11 +585,13 @@ private static String toAccessorName(AST<?, ?, ?> ast, AnnotationValues<Accessor
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;
Expand All @@ -602,7 +604,7 @@ private static String toAccessorName(AST<?, ?, ?> ast, AnnotationValues<Accessor
return booleanPrefix + fName.substring(2);
}

return buildAccessorName(isBoolean ? booleanPrefix : normalPrefix, fName);
return buildAccessorName(isBoolean ? booleanPrefix : normalPrefix, fName, javaBeansSpecCapitalization);
}

/**
Expand Down Expand Up @@ -675,12 +677,14 @@ private static List<String> toAllAccessorNames(AST<?, ?, ?> ast, AnnotationValue

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();

Expand All @@ -691,8 +695,8 @@ private static List<String> toAllAccessorNames(AST<?, ?, ?> ast, AnnotationValue
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));
}
}

Expand Down Expand Up @@ -723,17 +727,34 @@ private static List<String> toBaseNames(CharSequence fieldName, boolean isBoolea
* @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);
}

Expand Down
9 changes: 9 additions & 0 deletions src/core/lombok/experimental/Accessors.java
Expand Up @@ -54,6 +54,15 @@
*/
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
Expand Down
@@ -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;
}
}


@@ -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;
}
}


@@ -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() + ")";
}
}
@@ -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);
}
}
@@ -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;
}
}
@@ -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;
}
}

0 comments on commit d2e8370

Please sign in to comment.