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 }