Implement prefixed setters

Related to #1805, this change adds an optional `setterPrefix` parameter
to the `Builder` annotation; if this parameter is unspecified or blank
the behavior of the `Builder` annotation is unchanged, but if it is
present the value specified will be prefixed to the generated methods.

For example, using:

```
@Builder(setterPrefix = "include")
class Foo {
    private int someValue;
}
```

will result in a generated `Builder` class containing an `includeSomeValue(int someValue)`
method instead of the default `someValue(int someValue)`.
This commit is contained in:
Caleb Brinkman committed 2019-07-10 17:28:54 -05:00
1 parent 96151ade65
commit 88bf742e3e
3 files changed
+89 -11

No files matched your search

@@ -31,6 +31,7 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import com.sun.tools.javac.util.Name;
import org.eclipse.jdt.internal.compiler.ast.ASTNode;
import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
import org.eclipse.jdt.internal.compiler.ast.AbstractVariableDeclaration;
@@ -482,7 +483,7 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> {
}
for (BuilderFieldData bfd : builderFields) {
makeSetterMethodsForBuilder(builderType, bfd, annotationNode, fluent, chain, accessForInners, bfd.originalFieldNode);
makePrefixedSetterMethodsForBuilder(builderType, bfd, annotationNode, fluent, chain, accessForInners, bfd.originalFieldNode, builderInstance.setterPrefix());
}
{
@@ -840,7 +841,46 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> {
sourceNode, methodAnnsList, annotations != null ? Arrays.asList(copyAnnotations(sourceNode.get(), annotations)) : Collections.<Annotation>emptyList());
injectMethod(builderType, setter);
}
public void makePrefixedSetterMethodsForBuilder(EclipseNode builderType, BuilderFieldData bfd, EclipseNode sourceNode, boolean fluent, boolean chain, AccessLevel access, EclipseNode originalFieldNode, String prefix) {
boolean deprecate = isFieldDeprecated(bfd.originalFieldNode);
if (bfd.singularData == null || bfd.singularData.getSingularizer() == null) {
makePrefixedSetterMethodForBuilder(builderType, deprecate, bfd.createdFields.get(0), bfd.nameOfSetFlag, sourceNode, fluent, chain, bfd.annotations, access, originalFieldNode, prefix);
} else {
bfd.singularData.getSingularizer().generateMethods(bfd.singularData, deprecate, builderType, fluent, chain, access);
}
}
private void makePrefixedSetterMethodForBuilder(EclipseNode builderType, boolean deprecate, EclipseNode fieldNode, char[] nameOfSetFlag, EclipseNode sourceNode, boolean fluent, boolean chain, Annotation[] annotations, AccessLevel access, EclipseNode originalFieldNode, String prefix) {
TypeDeclaration td = (TypeDeclaration) builderType.get();
AbstractMethodDeclaration[] existing = td.methods;
if (existing == null) existing = EMPTY;
int len = existing.length;
FieldDeclaration fd = (FieldDeclaration) fieldNode.get();
char[] name = fd.name;
for (int i = 0; i < len; i++) {
if (!(existing[i] instanceof MethodDeclaration)) continue;
char[] existingName = existing[i].selector;
if (Arrays.equals(name, existingName) && !isTolerate(fieldNode, existing[i])) return;
}
String setterPrefix = prefix.isEmpty() ? "set" : prefix;
String setterName;
if(fluent) {
setterName = prefix.isEmpty() ? fieldNode.getName() : HandlerUtil.buildAccessorName(setterPrefix, fieldNode.getName());
} else {
setterName = HandlerUtil.buildAccessorName(setterPrefix, fieldNode.getName());
}
List<Annotation> methodAnnsList = Collections.<Annotation>emptyList();
Annotation[] methodAnns = EclipseHandlerUtil.findCopyableToSetterAnnotations(originalFieldNode);
if (methodAnns != null && methodAnns.length > 0) methodAnnsList = Arrays.asList(methodAnns);
MethodDeclaration setter = HandleSetter.createSetter(td, deprecate, fieldNode, setterName, nameOfSetFlag, chain, toEclipseModifier(access),
sourceNode, methodAnnsList, annotations != null ? Arrays.asList(copyAnnotations(sourceNode.get(), annotations)) : Collections.<Annotation>emptyList());
injectMethod(builderType, setter);
}
public EclipseNode makeBuilderClass(boolean isStatic, EclipseNode tdParent, String builderClassName, TypeParameter[] typeParams, ASTNode source, AccessLevel access) {
TypeDeclaration parent = (TypeDeclaration) tdParent.get();
TypeDeclaration builder = new TypeDeclaration(parent.compilationResult);
@@ -430,7 +430,7 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> {
}
for (BuilderFieldData bfd : builderFields) {
makeSetterMethodsForBuilder(builderType, bfd, annotationNode, fluent, chain, accessForInners);
makePrefixedSetterMethodsForBuilder(builderType, bfd, annotationNode, fluent, chain, accessForInners, builderInstance.setterPrefix());
}
{
@@ -745,29 +745,67 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> {
fieldNode.singularData.getSingularizer().generateMethods(fieldNode.singularData, deprecate, builderType, source.get(), fluent, chain, access);
}
}
private void makeSimpleSetterMethodForBuilder(JavacNode builderType, boolean deprecate, JavacNode fieldNode, Name nameOfSetFlag, JavacNode source, boolean fluent, boolean chain, List<JCAnnotation> annosOnParam, JavacNode originalFieldNode, AccessLevel access) {
Name fieldName = ((JCVariableDecl) fieldNode.get()).name;
for (JavacNode child : builderType.down()) {
if (child.getKind() != Kind.METHOD) continue;
JCMethodDecl methodDecl = (JCMethodDecl) child.get();
Name existingName = methodDecl.name;
if (existingName.equals(fieldName) && !isTolerate(fieldNode, methodDecl)) return;
}
String setterName = fluent ? fieldNode.getName() : HandlerUtil.buildAccessorName("set", fieldNode.getName());
JavacTreeMaker maker = fieldNode.getTreeMaker();
List<JCAnnotation> methodAnns = JavacHandlerUtil.findCopyableToSetterAnnotations(originalFieldNode);
JCMethodDecl newMethod = HandleSetter.createSetter(toJavacModifier(access), deprecate, fieldNode, maker, setterName, nameOfSetFlag, chain, source, methodAnns, annosOnParam);
recursiveSetGeneratedBy(newMethod, source.get(), builderType.getContext());
copyJavadoc(originalFieldNode, newMethod, CopyJavadoc.SETTER);
injectMethod(builderType, newMethod);
}
public void makePrefixedSetterMethodsForBuilder(JavacNode builderType, BuilderFieldData fieldNode, JavacNode source, boolean fluent, boolean chain, AccessLevel access, String prefix) {
boolean deprecate = isFieldDeprecated(fieldNode.originalFieldNode);
if (fieldNode.singularData == null || fieldNode.singularData.getSingularizer() == null) {
makePrefixedSetterMethodForBuilder(builderType, deprecate, fieldNode.createdFields.get(0), fieldNode.nameOfSetFlag, source, fluent, chain, fieldNode.annotations, fieldNode.originalFieldNode, access, prefix);
} else {
// TODO prefixed version
fieldNode.singularData.getSingularizer().generateMethods(fieldNode.singularData, deprecate, builderType, source.get(), fluent, chain, access);
}
}
private void makePrefixedSetterMethodForBuilder(JavacNode builderType, boolean deprecate, JavacNode fieldNode, Name nameOfSetFlag, JavacNode source, boolean fluent, boolean chain, List<JCAnnotation> annosOnParam, JavacNode originalFieldNode, AccessLevel access, String prefix) {
Name fieldName = ((JCVariableDecl) fieldNode.get()).name;
for (JavacNode child : builderType.down()) {
if (child.getKind() != Kind.METHOD) continue;
JCMethodDecl methodDecl = (JCMethodDecl) child.get();
Name existingName = methodDecl.name;
if (existingName.equals(fieldName) && !isTolerate(fieldNode, methodDecl)) return;
}
String setterPrefix = prefix.isEmpty() ? "set" : prefix;
String setterName;
if(fluent) {
setterName = prefix.isEmpty() ? fieldNode.getName() : HandlerUtil.buildAccessorName(setterPrefix, fieldNode.getName());
} else {
setterName = HandlerUtil.buildAccessorName(setterPrefix, fieldNode.getName());
}
JavacTreeMaker maker = fieldNode.getTreeMaker();
List<JCAnnotation> methodAnns = JavacHandlerUtil.findCopyableToSetterAnnotations(originalFieldNode);
JCMethodDecl newMethod = HandleSetter.createSetter(toJavacModifier(access), deprecate, fieldNode, maker, setterName, nameOfSetFlag, chain, source, methodAnns, annosOnParam);
recursiveSetGeneratedBy(newMethod, source.get(), builderType.getContext());
copyJavadoc(originalFieldNode, newMethod, CopyJavadoc.SETTER);
injectMethod(builderType, newMethod);
}
public JavacNode makeBuilderClass(boolean isStatic, JavacNode source, JavacNode tdParent, String builderClassName, List<JCTypeParameter> typeParams, JCAnnotation ast, AccessLevel access) {
JavacTreeMaker maker = tdParent.getTreeMaker();
int modifiers = toJavacModifier(access);
@@ -13,7 +13,7 @@ import java.util.List;
return new BuilderWithPrefix<T>(unprefixed);
}
public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() {
return (((("BuilderWithPrefix.BuilderWithPrefixBuilder(unprefixed=" + this.unprefixed) + ")");
return (("BuilderWithPrefix.BuilderWithPrefixBuilder(unprefixed=" + this.unprefixed) + ")");
}
}
private int unprefixed;