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.List;
9 import java.util.Map;
10
11 import net.sourceforge.pmd.AbstractRule;
12 import net.sourceforge.pmd.PropertyDescriptor;
13 import net.sourceforge.pmd.ast.ASTClassOrInterfaceDeclaration;
14 import net.sourceforge.pmd.ast.ASTCompilationUnit;
15 import net.sourceforge.pmd.ast.ASTMethodDeclaration;
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.NameOccurrence;
23 import net.sourceforge.pmd.symboltable.VariableNameDeclaration;
24
25 public class BeanMembersShouldSerializeRule extends AbstractRule {
26
27 private String prefixProperty;
28
29 private static final PropertyDescriptor prefixDescriptor = new StringProperty(
30 "prefix", "Prefix somethingorother?", "", 1.0f
31 );
32
33 private static final Map<String, PropertyDescriptor> propertyDescriptorsByName = asFixedMap(prefixDescriptor);
34
35
36 public Object visit(ASTCompilationUnit node, Object data) {
37 prefixProperty = getStringProperty(prefixDescriptor);
38 super.visit(node, data);
39 return data;
40 }
41
42 private static String[] imagesOf(List<? extends SimpleNode> simpleNodes) {
43
44 String[] imageArray = new String[simpleNodes.size()];
45
46 for (int i = 0; i < simpleNodes.size(); i++) {
47 imageArray[i] = simpleNodes.get(i).getImage();
48 }
49 return imageArray;
50 }
51
52 public Object visit(ASTClassOrInterfaceDeclaration node, Object data) {
53 if (node.isInterface()) {
54 return data;
55 }
56
57 Map<MethodNameDeclaration, List<NameOccurrence>> methods = node.getScope().getEnclosingClassScope().getMethodDeclarations();
58 List<ASTMethodDeclarator> getSetMethList = new ArrayList<ASTMethodDeclarator>(methods.size());
59 for (MethodNameDeclaration d: methods.keySet()) {
60 ASTMethodDeclarator mnd = d.getMethodNameDeclaratorNode();
61 if (isBeanAccessor(mnd)) {
62 getSetMethList.add(mnd);
63 }
64 }
65
66 String[] methNameArray = imagesOf(getSetMethList);
67
68 Arrays.sort(methNameArray);
69
70 Map<VariableNameDeclaration, List<NameOccurrence>> vars = node.getScope().getVariableDeclarations();
71 for (VariableNameDeclaration decl: vars.keySet()) {
72 if (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 = ((ASTMethodDeclaration) meth.jjtGetParent()).getResultType();
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<String, PropertyDescriptor> propertiesByName() {
114 return propertyDescriptorsByName;
115 }
116 }