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.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 }