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.ASTMethodDeclarator;
16  import net.sourceforge.pmd.ast.ASTPrimitiveType;
17  import net.sourceforge.pmd.ast.ASTResultType;
18  import net.sourceforge.pmd.ast.SimpleNode;
19  import net.sourceforge.pmd.properties.StringProperty;
20  import net.sourceforge.pmd.symboltable.MethodNameDeclaration;
21  import net.sourceforge.pmd.symboltable.NameOccurrence;
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<String, PropertyDescriptor> 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<? extends SimpleNode> simpleNodes) {
42  		
43          String[] imageArray = new String[simpleNodes.size()];
44          
45          for (int i = 0; i < simpleNodes.size(); i++) {
46          	imageArray[i] = 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<MethodNameDeclaration, List<NameOccurrence>> methods = node.getScope().getEnclosingClassScope().getMethodDeclarations();
57          List<ASTMethodDeclarator> getSetMethList = new ArrayList<ASTMethodDeclarator>(methods.size());
58          for (MethodNameDeclaration d: methods.keySet()) {
59              ASTMethodDeclarator mnd = d.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<VariableNameDeclaration, List<NameOccurrence>> vars = node.getScope().getVariableDeclarations();
70          for (VariableNameDeclaration decl: vars.keySet()) {
71              if (vars.get(decl).isEmpty() || decl.getAccessNodeParent().isTransient() || decl.getAccessNodeParent().isStatic()) {
72                  continue;
73              }
74              String varName = trimIfPrefix(decl.getImage());
75              varName = varName.substring(0, 1).toUpperCase() + varName.substring(1, varName.length());
76              boolean hasGetMethod = Arrays.binarySearch(methNameArray, "get" + varName) >= 0 || Arrays.binarySearch(methNameArray, "is" + varName) >= 0;
77              boolean hasSetMethod = Arrays.binarySearch(methNameArray, "set" + varName) >= 0;
78              if (!hasGetMethod || !hasSetMethod) {
79                  addViolation(data, decl.getNode(), decl.getImage());
80              }
81          }
82          return super.visit(node, data);
83      }
84  
85      private String trimIfPrefix(String img) {
86          if (prefixProperty != null && img.startsWith(prefixProperty)) {
87              return img.substring(prefixProperty.length());
88          }
89          return img;
90      }
91  
92      private boolean isBeanAccessor(ASTMethodDeclarator meth) {
93      	
94      	String methodName = meth.getImage();
95      	
96          if (methodName.startsWith("get") || methodName.startsWith("set")) {
97              return true;
98          }
99          if (methodName.startsWith("is")) {
100             ASTResultType ret = (ASTResultType) meth.jjtGetParent().jjtGetChild(0);
101             List primitives = ret.findChildrenOfType(ASTPrimitiveType.class);
102             if (!primitives.isEmpty() && ((ASTPrimitiveType) primitives.get(0)).isBoolean()) {
103                 return true;
104             }
105         }
106         return false;
107     }
108     
109     /**
110      * @return Map
111      */
112     protected Map<String, PropertyDescriptor> propertiesByName() {
113     	return propertyDescriptorsByName;
114     }
115 }