View Javadoc

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 }