EMMA Coverage Report (generated Fri Jan 30 13:20:29 EST 2009)
[all classes][org.springframework.batch.item.file.mapping]

COVERAGE SUMMARY FOR SOURCE FILE [PropertyMatches.java]

nameclass, %method, %block, %line, %
PropertyMatches.java100% (1/1)100% (7/7)99%  (275/278)98%  (48/49)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class PropertyMatches100% (1/1)100% (7/7)99%  (275/278)98%  (48/49)
calculateStringDistance (String, String): int 100% (1/1)98%  (129/132)94%  (17/18)
PropertyMatches (String, Class, int): void 100% (1/1)100% (13/13)100% (4/4)
buildErrorMessage (): String 100% (1/1)100% (80/80)100% (16/16)
calculateMatches (PropertyDescriptor [], int): String [] 100% (1/1)100% (38/38)100% (8/8)
forProperty (String, Class): PropertyMatches 100% (1/1)100% (5/5)100% (1/1)
forProperty (String, Class, int): PropertyMatches 100% (1/1)100% (7/7)100% (1/1)
getPossibleMatches (): String [] 100% (1/1)100% (3/3)100% (1/1)

1/*
2 * Copyright 2006-2007 the original author or authors.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 
17package org.springframework.batch.item.file.mapping;
18 
19import java.beans.PropertyDescriptor;
20import java.util.ArrayList;
21import java.util.Collections;
22import java.util.List;
23 
24import org.springframework.beans.BeanUtils;
25import org.springframework.util.ObjectUtils;
26import org.springframework.util.StringUtils;
27 
28/**
29 * Helper class for calculating bean property matches, according to.
30 * Used by BeanWrapperImpl to suggest alternatives for an invalid property name.<br/>
31 * 
32 * Copied and slightly modified from Spring core,
33 *
34 * @author Alef Arendsen
35 * @author Arjen Poutsma
36 * @author Juergen Hoeller
37 * @author Dave Syer
38 * 
39 * @since 1.0
40 * @see #forProperty(String, Class)
41 */
42final class PropertyMatches {
43 
44        //---------------------------------------------------------------------
45        // Static section
46        //---------------------------------------------------------------------
47 
48        /** Default maximum property distance: 2 */
49        public static final int DEFAULT_MAX_DISTANCE = 2;
50 
51 
52        /**
53         * Create PropertyMatches for the given bean property.
54         * @param propertyName the name of the property to find possible matches for
55         * @param beanClass the bean class to search for matches
56         */
57        public static PropertyMatches forProperty(String propertyName, Class beanClass) {
58                return forProperty(propertyName, beanClass, DEFAULT_MAX_DISTANCE);
59        }
60 
61        /**
62         * Create PropertyMatches for the given bean property.
63         * @param propertyName the name of the property to find possible matches for
64         * @param beanClass the bean class to search for matches
65         * @param maxDistance the maximum property distance allowed for matches
66         */
67        public static PropertyMatches forProperty(String propertyName, Class beanClass, int maxDistance) {
68                return new PropertyMatches(propertyName, beanClass, maxDistance);
69        }
70 
71 
72        //---------------------------------------------------------------------
73        // Instance section
74        //---------------------------------------------------------------------
75 
76        private final String propertyName;
77 
78        private String[] possibleMatches;
79 
80 
81        /**
82         * Create a new PropertyMatches instance for the given property.
83         */
84        private PropertyMatches(String propertyName, Class beanClass, int maxDistance) {
85                this.propertyName = propertyName;
86                this.possibleMatches = calculateMatches(BeanUtils.getPropertyDescriptors(beanClass), maxDistance);
87        }
88 
89 
90        /**
91         * Return the calculated possible matches.
92         */
93        public String[] getPossibleMatches() {
94                return possibleMatches;
95        }
96 
97        /**
98         * Build an error message for the given invalid property name,
99         * indicating the possible property matches.
100         */
101        public String buildErrorMessage() {
102                StringBuffer buf = new StringBuffer();
103                buf.append("Bean property '");
104                buf.append(this.propertyName);
105                buf.append("' is not writable or has an invalid setter method. ");
106 
107                if (ObjectUtils.isEmpty(this.possibleMatches)) {
108                        buf.append("Does the parameter type of the setter match the return type of the getter?");
109                }
110                else {
111                        buf.append("Did you mean ");
112                        for (int i = 0; i < this.possibleMatches.length; i++) {
113                                buf.append('\'');
114                                buf.append(this.possibleMatches[i]);
115                                if (i < this.possibleMatches.length - 2) {
116                                        buf.append("', ");
117                                }
118                                else if (i == this.possibleMatches.length - 2){
119                                        buf.append("', or ");
120                                }
121                         }
122                        buf.append("'?");
123                }
124                return buf.toString();
125        }
126 
127 
128        /**
129         * Generate possible property alternatives for the given property and
130         * class. Internally uses the <code>getStringDistance</code> method, which
131         * in turn uses the Levenshtein algorithm to determine the distance between
132         * two Strings.
133         * @param propertyDescriptors the JavaBeans property descriptors to search
134         * @param maxDistance the maximum distance to accept
135         */
136        private String[] calculateMatches(PropertyDescriptor[] propertyDescriptors, int maxDistance) {
137                List candidates = new ArrayList();
138                for (int i = 0; i < propertyDescriptors.length; i++) {
139                        if (propertyDescriptors[i].getWriteMethod() != null) {
140                                String possibleAlternative = propertyDescriptors[i].getName();
141                                if (calculateStringDistance(this.propertyName, possibleAlternative) <= maxDistance) {
142                                        candidates.add(possibleAlternative);
143                                }
144                        }
145                }
146                Collections.sort(candidates);
147                return StringUtils.toStringArray(candidates);
148        }
149 
150        /**
151         * Calculate the distance between the given two Strings
152         * according to the Levenshtein algorithm.
153         * @param s1 the first String
154         * @param s2 the second String
155         * @return the distance value
156         */
157        private int calculateStringDistance(String s1, String s2) {
158                if (s1.length() == 0) {
159                        return s2.length();
160                }
161                if (s2.length() == 0) {
162                        return s1.length();
163                }
164                int d[][] = new int[s1.length() + 1][s2.length() + 1];
165 
166                for (int i = 0; i <= s1.length(); i++) {
167                        d[i][0] = i;
168                }
169                for (int j = 0; j <= s2.length(); j++) {
170                        d[0][j] = j;
171                }
172 
173                for (int i = 1; i <= s1.length(); i++) {
174                        char s_i = s1.charAt(i - 1);
175                        for (int j = 1; j <= s2.length(); j++) {
176                                int cost;
177                                char t_j = s2.charAt(j - 1);
178                                if (Character.toLowerCase(s_i) == Character.toLowerCase(t_j)) {
179                                        cost = 0;
180                                } else {
181                                        cost = 1;
182                                }
183                                d[i][j] = Math.min(Math.min(d[i - 1][j] + 1, d[i][j - 1] + 1),
184                                                d[i - 1][j - 1] + cost);
185                        }
186                }
187 
188                return d[s1.length()][s2.length()];
189        }
190 
191}

[all classes][org.springframework.batch.item.file.mapping]
EMMA 2.0.5312 (C) Vladimir Roubtsov