1 /***
2 * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
3 */
4 package net.sourceforge.pmd.rules;
5
6 import java.util.ArrayList;
7 import java.util.Arrays;
8 import java.util.Iterator;
9 import java.util.List;
10 import java.util.Map;
11
12 import net.sourceforge.pmd.AbstractRule;
13 import net.sourceforge.pmd.PropertyDescriptor;
14 import net.sourceforge.pmd.ast.ASTClassOrInterfaceDeclaration;
15 import net.sourceforge.pmd.ast.ASTCompilationUnit;
16 import net.sourceforge.pmd.ast.ASTMethodDeclarator;
17 import net.sourceforge.pmd.ast.ASTPrimitiveType;
18 import net.sourceforge.pmd.ast.ASTResultType;
19 import net.sourceforge.pmd.ast.SimpleNode;
20 import net.sourceforge.pmd.properties.StringProperty;
21 import net.sourceforge.pmd.symboltable.MethodNameDeclaration;
22 import net.sourceforge.pmd.symboltable.VariableNameDeclaration;
23
24 public class BeanMembersShouldSerializeRule extends AbstractRule {
25
26 private String prefixProperty;
27
28 private static final PropertyDescriptor prefixDescriptor = new StringProperty(
29 "prefix", "Prefix somethingorother?", "", 1.0f
30 );
31
32 private static final Map propertyDescriptorsByName = asFixedMap(prefixDescriptor);
33
34
35 public Object visit(ASTCompilationUnit node, Object data) {
36 prefixProperty = getStringProperty(prefixDescriptor);
37 super.visit(node, data);
38 return data;
39 }
40
41 private static String[] imagesOf(List simpleNodes) {
42
43 String[] imageArray = new String[simpleNodes.size()];
44
45 for (int i = 0; i < simpleNodes.size(); i++) {
46 imageArray[i] = ((SimpleNode) simpleNodes.get(i)).getImage();
47 }
48 return imageArray;
49 }
50
51 public Object visit(ASTClassOrInterfaceDeclaration node, Object data) {
52 if (node.isInterface()) {
53 return data;
54 }
55
56 Map methods = node.getScope().getEnclosingClassScope().getMethodDeclarations();
57 List getSetMethList = new ArrayList(methods.size());
58 for (Iterator i = methods.keySet().iterator(); i.hasNext();) {
59 ASTMethodDeclarator mnd = ((MethodNameDeclaration) i.next()).getMethodNameDeclaratorNode();
60 if (isBeanAccessor(mnd)) {
61 getSetMethList.add(mnd);
62 }
63 }
64
65 String[] methNameArray = imagesOf(getSetMethList);
66
67 Arrays.sort(methNameArray);
68
69 Map vars = node.getScope().getVariableDeclarations();
70 for (Iterator i = vars.keySet().iterator(); i.hasNext();) {
71 VariableNameDeclaration decl = (VariableNameDeclaration) i.next();
72 if (((List) vars.get(decl)).isEmpty() || decl.getAccessNodeParent().isTransient() || decl.getAccessNodeParent().isStatic()) {
73 continue;
74 }
75 String varName = trimIfPrefix(decl.getImage());
76 varName = varName.substring(0, 1).toUpperCase() + varName.substring(1, varName.length());
77 boolean hasGetMethod = Arrays.binarySearch(methNameArray, "get" + varName) >= 0 || Arrays.binarySearch(methNameArray, "is" + varName) >= 0;
78 boolean hasSetMethod = Arrays.binarySearch(methNameArray, "set" + varName) >= 0;
79 if (!hasGetMethod || !hasSetMethod) {
80 addViolation(data, decl.getNode(), decl.getImage());
81 }
82 }
83 return super.visit(node, data);
84 }
85
86 private String trimIfPrefix(String img) {
87 if (prefixProperty != null && img.startsWith(prefixProperty)) {
88 return img.substring(prefixProperty.length());
89 }
90 return img;
91 }
92
93 private boolean isBeanAccessor(ASTMethodDeclarator meth) {
94
95 String methodName = meth.getImage();
96
97 if (methodName.startsWith("get") || methodName.startsWith("set")) {
98 return true;
99 }
100 if (methodName.startsWith("is")) {
101 ASTResultType ret = (ASTResultType) meth.jjtGetParent().jjtGetChild(0);
102 List primitives = ret.findChildrenOfType(ASTPrimitiveType.class);
103 if (!primitives.isEmpty() && ((ASTPrimitiveType) primitives.get(0)).isBoolean()) {
104 return true;
105 }
106 }
107 return false;
108 }
109
110 /***
111 * @return Map
112 */
113 protected Map propertiesByName() {
114 return propertyDescriptorsByName;
115 }
116 }