1 16 17 package org.springframework.beans; 18 19 import java.beans.PropertyDescriptor ; 20 import java.util.ArrayList ; 21 import java.util.Collections ; 22 import java.util.List ; 23 24 import org.springframework.util.ObjectUtils; 25 import org.springframework.util.StringUtils; 26 27 37 final class PropertyMatches { 38 39 43 44 public static final int DEFAULT_MAX_DISTANCE = 2; 45 46 47 52 public static PropertyMatches forProperty(String propertyName, Class beanClass) { 53 return forProperty(propertyName, beanClass, DEFAULT_MAX_DISTANCE); 54 } 55 56 62 public static PropertyMatches forProperty(String propertyName, Class beanClass, int maxDistance) { 63 return new PropertyMatches(propertyName, beanClass, maxDistance); 64 } 65 66 67 71 private final String propertyName; 72 73 private String [] possibleMatches; 74 75 76 79 private PropertyMatches(String propertyName, Class beanClass, int maxDistance) { 80 this.propertyName = propertyName; 81 this.possibleMatches = calculateMatches(BeanUtils.getPropertyDescriptors(beanClass), maxDistance); 82 } 83 84 85 88 public String [] getPossibleMatches() { 89 return possibleMatches; 90 } 91 92 96 public String buildErrorMessage() { 97 StringBuffer buf = new StringBuffer (); 98 buf.append("Bean property '"); 99 buf.append(this.propertyName); 100 buf.append("' is not writable or has an invalid setter method. "); 101 102 if (ObjectUtils.isEmpty(this.possibleMatches)) { 103 buf.append("Does the parameter type of the setter match the return type of the getter?"); 104 } 105 else { 106 buf.append("Did you mean "); 107 for (int i = 0; i < this.possibleMatches.length; i++) { 108 buf.append('\''); 109 buf.append(this.possibleMatches[i]); 110 if (i < this.possibleMatches.length - 2) { 111 buf.append("', "); 112 } 113 else if (i == this.possibleMatches.length - 2){ 114 buf.append("', or "); 115 } 116 } 117 buf.append("'?"); 118 } 119 return buf.toString(); 120 } 121 122 123 131 private String [] calculateMatches(PropertyDescriptor [] propertyDescriptors, int maxDistance) { 132 List candidates = new ArrayList (); 133 for (int i = 0; i < propertyDescriptors.length; i++) { 134 if (propertyDescriptors[i].getWriteMethod() != null) { 135 String possibleAlternative = propertyDescriptors[i].getName(); 136 if (calculateStringDistance(this.propertyName, possibleAlternative) <= maxDistance) { 137 candidates.add(possibleAlternative); 138 } 139 } 140 } 141 Collections.sort(candidates); 142 return StringUtils.toStringArray(candidates); 143 } 144 145 152 private int calculateStringDistance(String s1, String s2) { 153 if (s1.length() == 0) { 154 return s2.length(); 155 } 156 if (s2.length() == 0) { 157 return s1.length(); 158 } 159 int d[][] = new int[s1.length() + 1][s2.length() + 1]; 160 161 for (int i = 0; i <= s1.length(); i++) { 162 d[i][0] = i; 163 } 164 for (int j = 0; j <= s2.length(); j++) { 165 d[0][j] = j; 166 } 167 168 for (int i = 1; i <= s1.length(); i++) { 169 char s_i = s1.charAt(i - 1); 170 for (int j = 1; j <= s2.length(); j++) { 171 int cost; 172 char t_j = s2.charAt(j - 1); 173 if (s_i == t_j) { 174 cost = 0; 175 } else { 176 cost = 1; 177 } 178 d[i][j] = Math.min(Math.min(d[i - 1][j] + 1, d[i][j - 1] + 1), 179 d[i - 1][j - 1] + cost); 180 } 181 } 182 183 return d[s1.length()][s2.length()]; 184 } 185 186 } 187 | Popular Tags |