Skip to content

Commit 9171b52

Browse files
author
glelouet
committed
modified annotation to have shorter name for prefix, suffix, added option to camelcase the variable name and the method name. Created util to extract the var name and met name from the requested name and the annotation.
Changed the tests to have the var match the getter, and implemented the var name and assignment replacement in the node.
1 parent eab7d44 commit 9171b52

File tree

5 files changed

+203
-13
lines changed

5 files changed

+203
-13
lines changed

src/core/lombok/Onstruct.java

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,7 @@
4242
* Before:
4343
*
4444
* <pre>
45-
* &#064;Onstruct(prefix = "b_")
46-
* Object author, name, editiondate, purchasable = mybook;
45+
* &#064;Onstruct(pre = "b_") Object author, name, editiondate, purchasable = mybook;
4746
* </pre>
4847
*
4948
* After:
@@ -60,8 +59,29 @@
6059
@Retention(RetentionPolicy.SOURCE)
6160
public @interface Onstruct {
6261

63-
String prefix() default "";
62+
/**
63+
* prefix to start the created var name with. Default is empty
64+
*/
65+
String pre() default "";
6466

65-
String suffix() default "";
67+
/**
68+
* suffix to append to created var name. Default is empty
69+
*/
70+
String suf() default "";
71+
72+
/**
73+
* if true, should camel case the variable name. Only applied when prefix is
74+
* non blank. Default is false.
75+
*/
76+
boolean cml() default false;
77+
78+
/** prefix to start the getter call by. Default is "get" */
79+
String methodPre() default "get";
80+
81+
/**
82+
* if true, should camel case the method call. Only applied when method
83+
* prefix is non blank. Default is true.
84+
*/
85+
boolean methodCml() default true;
6686

6787
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package lombok.core.handlers;
2+
3+
import lombok.Onstruct;
4+
5+
public class OnstructUtils {
6+
7+
public static String varName(String requestedName, Onstruct instance) {
8+
String prefix = instance.pre();
9+
String suffix = instance.suf();
10+
boolean cml = instance.cml() && prefix != null && !prefix.isEmpty();
11+
return (prefix != null ? prefix : "") + (cml ? cml(requestedName) : requestedName) + (suffix != null ? suffix : "");
12+
}
13+
14+
public static String methodName(String requestedName, Onstruct instance) {
15+
String methodPrefix = instance.methodPre();
16+
if (methodPrefix == null || methodPrefix.isEmpty()) return requestedName;
17+
return methodPrefix + (instance.methodCml() ? cml(requestedName) : requestedName);
18+
}
19+
20+
public static String cml(String name) {
21+
return name.substring(0, 1).toUpperCase() + name.substring(1);
22+
}
23+
24+
}

src/core/lombok/eclipse/handlers/HandleOnstruct.java

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,29 @@
11
package lombok.eclipse.handlers;
22

3+
import java.io.PrintStream;
4+
35
import org.eclipse.jdt.internal.compiler.ast.Annotation;
46

57
import lombok.Onstruct;
68
import lombok.core.AnnotationValues;
79
import lombok.core.HandlerPriority;
10+
import lombok.eclipse.DeferUntilPostDiet;
11+
import lombok.eclipse.EclipseASTVisitor;
812
import lombok.eclipse.EclipseAnnotationHandler;
913
import lombok.eclipse.EclipseNode;
14+
import lombok.spi.Provides;
1015

16+
@Provides
17+
@DeferUntilPostDiet
1118
@HandlerPriority(65536) // same as HandleValue // TODO
1219
public class HandleOnstruct extends EclipseAnnotationHandler<Onstruct> {
1320

1421
public static final HandleOnstruct INSTANCE = new HandleOnstruct();
1522

1623
@Override public void handle(AnnotationValues<Onstruct> annotation, Annotation ast, EclipseNode annotationNode) {
17-
// TODO Auto-generated method stub
18-
24+
PrintStream stream = System.out;
25+
stream.println("got annotation on " + ast);
26+
annotationNode.up().traverse(new EclipseASTVisitor.Printer(true, stream, true));
1927
}
2028

2129

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
package lombok.javac.handlers;
2+
3+
import static lombok.javac.handlers.JavacHandlerUtil.deleteAnnotationIfNeccessary;
4+
5+
import java.util.ArrayList;
6+
import java.util.Collection;
7+
import java.util.Collections;
8+
import java.util.List;
9+
10+
import com.sun.tools.javac.tree.JCTree;
11+
import com.sun.tools.javac.tree.JCTree.JCAnnotation;
12+
import com.sun.tools.javac.tree.JCTree.JCExpression;
13+
import com.sun.tools.javac.tree.JCTree.JCIdent;
14+
import com.sun.tools.javac.tree.JCTree.JCVariableDecl;
15+
16+
import lombok.Onstruct;
17+
import lombok.core.AST.Kind;
18+
import lombok.core.AnnotationValues;
19+
import lombok.core.HandlerPriority;
20+
import lombok.core.LombokNode;
21+
import lombok.core.handlers.OnstructUtils;
22+
import lombok.eclipse.DeferUntilPostDiet;
23+
import lombok.javac.JavacAnnotationHandler;
24+
import lombok.javac.JavacNode;
25+
import lombok.javac.JavacTreeMaker;
26+
import lombok.spi.Provides;
27+
28+
@Provides
29+
@DeferUntilPostDiet
30+
@HandlerPriority(65536) // same as HandleValue // TODO
31+
public class HandleOnstruct extends JavacAnnotationHandler<Onstruct> {
32+
33+
34+
/**
35+
* find the siblings with same kind and annotation. Copy of
36+
* {@link LombokNode#upFromAnnotationToFields()} with same kind and no check
37+
* on the parent.
38+
*
39+
*/
40+
public static Collection<JavacNode> upFromAnnotationToSameKind(JavacNode node) {
41+
if (node.getKind() != Kind.ANNOTATION) return Collections.emptyList();
42+
JavacNode declaration = node.up();
43+
if (declaration == null) return Collections.emptyList();
44+
45+
List<JavacNode> fields = new ArrayList();
46+
47+
for (JavacNode potentialField : declaration.up().down()) {
48+
if (potentialField.getKind() != declaration.getKind()) continue;
49+
for (JavacNode child : potentialField.down()) {
50+
if (child.getKind() != Kind.ANNOTATION) continue;
51+
if (child.get() == node.get()) fields.add(potentialField);
52+
}
53+
}
54+
55+
return fields;
56+
}
57+
58+
/**
59+
* retrieve the children statements from a list of node
60+
*/
61+
protected static List<JCTree> findChildrenStatements(Collection<JavacNode> fields) {
62+
List<JCTree> ret = new ArrayList();
63+
for (JavacNode f : fields) {
64+
for (JavacNode potentialStatement : f.down()) {
65+
if (potentialStatement.getKind() == Kind.STATEMENT) {
66+
ret.add(potentialStatement.get());
67+
}
68+
}
69+
}
70+
return ret;
71+
}
72+
73+
@Override public void handle(AnnotationValues<Onstruct> annotation, JCAnnotation ast, JavacNode annotationNode) {
74+
Collection<JavacNode> annotatedVariables = upFromAnnotationToSameKind(annotationNode);
75+
JavacNode parentNode = annotationNode.up();
76+
Onstruct annotationInstance = annotation.getInstance();
77+
deleteAnnotationIfNeccessary(annotationNode, Onstruct.class);
78+
79+
List<JCTree> statements = findChildrenStatements(annotatedVariables);
80+
// sanity checks on statements. Among the variables declaration, there
81+
// must be one statement.
82+
if (statements.isEmpty()) {
83+
annotationNode.addError("no assignment. Requires one identifier assignment.");
84+
return;
85+
}
86+
if (statements.size() > 1) {
87+
annotationNode.addError("Too many assignments:" + statements + " Requires exactly one identifier assignment.");
88+
return;
89+
}
90+
91+
JCTree tree = statements.get(0);
92+
JCTree.JCIdent ident;
93+
String varName = null;
94+
// sanity checks on the assignment. It must be an identifier.
95+
if (tree instanceof JCTree.JCIdent) {
96+
ident = (JCTree.JCIdent) tree;
97+
varName = (ident.name.toString());
98+
} else {
99+
annotationNode.addError("invalid assignment" + tree + " : must be an identifier");
100+
return;
101+
}
102+
if (varName == null) {
103+
annotationNode.addError("assignement is null . Must be an identifier");
104+
return;
105+
}
106+
107+
for (JavacNode f : annotatedVariables) {
108+
handleVarDeclaration(f, annotationInstance, parentNode, ident);
109+
}
110+
// parentNode.rebuild();
111+
}
112+
113+
private void handleVarDeclaration(JavacNode varNode, Onstruct annotationInstance, JavacNode parentNode, JCIdent ident) {
114+
String varName = OnstructUtils.varName(varNode.getName(), annotationInstance);
115+
String methName = OnstructUtils.methodName(varNode.getName(), annotationInstance);
116+
JCTree elem = varNode.get();
117+
JavacTreeMaker maker = varNode.getTreeMaker();
118+
// System.out.println("create : var " + varName + " = " + ident.name + "." + methName + "();");
119+
if (elem instanceof JCVariableDecl) {
120+
JCVariableDecl variable = (JCVariableDecl) elem;
121+
variable.type = (JavacHandlerUtil.chainDotsString(varNode, "java.lang.String")).type;
122+
JCExpression methCall = maker.Select(ident, varNode.toName(methName));
123+
variable.init = maker.Apply(com.sun.tools.javac.util.List.<JCExpression>nil(),
124+
methCall,
125+
com.sun.tools.javac.util.List.<JCExpression>nil());
126+
variable.name = varNode.toName(varName);
127+
// System.out.println("replaced with " + variable);
128+
} else
129+
System.err.println(varNode.get());
130+
}
131+
132+
}

test/transform/resource/before/OnstructBook.java

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
import lombok.AllArgsConstructor;
55
import lombok.Onstruct;
6+
import lombok.core.PrintAST;
67
import lombok.experimental.Accessors;
78

89
public class OnstructBook {
@@ -21,21 +22,26 @@ public static class Book {
2122

2223
void test() {
2324
Book mybook = new Book("author0", "bookname0", new Date(), true);
24-
@Onstruct()
25-
Object author, name, editiondate, purchasable = mybook;
25+
@Onstruct
26+
Object author, editionDate = mybook;
27+
@Onstruct(methodPre = "")
28+
Object name = mybook;
2629
assert Objects.equals(mybook.getAuthor(), author);
2730
assert Objects.equals(mybook.name(), name);
28-
assert Objects.equals(mybook.getEditionDate(), editiondate);
31+
assert Objects.equals(mybook.getEditionDate(), editionDate);
32+
@Onstruct(methodPre = "is")
33+
Object purchasable = mybook;
2934
assert Objects.equals(mybook.isPurchasable(), purchasable);
3035
}
3136

3237
void testPrefix() {
3338
Book mybook = new Book("author0", "bookname0", new Date(), true);
34-
@Onstruct(prefix = "b_")
35-
Object author, name, editiondate, purchasable = mybook;
39+
@Onstruct(pre = "b_")
40+
Object author, editionDate = mybook;
3641
assert Objects.equals(mybook.getAuthor(), b_author);
37-
assert Objects.equals(mybook.name(), b_name);
38-
assert Objects.equals(mybook.getEditionDate(), b_editiondate);
42+
assert Objects.equals(mybook.getEditionDate(), b_editionDate);
43+
@Onstruct(pre="b_", methodPre = "is")
44+
Object purchasable = mybook;
3945
assert Objects.equals(mybook.isPurchasable(), b_purchasable);
4046
}
4147

0 commit comments

Comments
 (0)