EMMA Coverage Report (generated Thu May 22 12:08:10 CDT 2014)
[all classes][org.springframework.batch.core.converter]

COVERAGE SUMMARY FOR SOURCE FILE [DefaultJobParametersConverter.java]

nameclass, %method, %block, %line, %
DefaultJobParametersConverter.java100% (1/1)100% (9/9)97%  (385/397)99%  (72.9/74)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class DefaultJobParametersConverter100% (1/1)100% (9/9)97%  (385/397)99%  (72.9/74)
getJobParameters (Properties): JobParameters 100% (1/1)94%  (178/189)97%  (35/36)
parseNumber (String): Number 100% (1/1)98%  (39/40)99%  (4/4)
<static initializer> 100% (1/1)100% (4/4)100% (1/1)
DefaultJobParametersConverter (): void 100% (1/1)100% (18/18)100% (4/4)
decimalFormat (double): String 100% (1/1)100% (12/12)100% (3/3)
getProperties (JobParameters): Properties 100% (1/1)100% (116/116)100% (18/18)
isIdentifyingKey (String): boolean 100% (1/1)100% (10/10)100% (4/4)
setDateFormat (DateFormat): void 100% (1/1)100% (4/4)100% (2/2)
setNumberFormat (NumberFormat): void 100% (1/1)100% (4/4)100% (2/2)

1/*
2 * Copyright 2006-2013 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 */
16package org.springframework.batch.core.converter;
17 
18import java.text.DateFormat;
19import java.text.DecimalFormat;
20import java.text.NumberFormat;
21import java.text.ParseException;
22import java.text.SimpleDateFormat;
23import java.util.Date;
24import java.util.Iterator;
25import java.util.Locale;
26import java.util.Map;
27import java.util.Map.Entry;
28import java.util.Properties;
29 
30import org.springframework.batch.core.JobInstance;
31import org.springframework.batch.core.JobParameter;
32import org.springframework.batch.core.JobParameter.ParameterType;
33import org.springframework.batch.core.JobParameters;
34import org.springframework.batch.core.JobParametersBuilder;
35import org.springframework.util.StringUtils;
36 
37/**
38 * Converter for {@link JobParameters} instances using a simple naming
39 * convention for property keys. Key names that are prefixed with a - are
40 * considered non-identifying and will not contribute to the identity of a
41 * {@link JobInstance}.  Key names ending with "(&lt;type&gt;)" where
42 * type is one of string, date, long are converted to the corresponding type.
43 * The default type is string. E.g.
44 *
45 * <pre>
46 * schedule.date(date)=2007/12/11
47 * department.id(long)=2345
48 * </pre>
49 *
50 * The literal values are converted to the correct type using the default Spring
51 * strategies, augmented if necessary by the custom editors provided.
52 *
53 * <br/>
54 * 
55 * If you need to be able to parse and format local-specific dates and numbers,
56 * you can inject formatters ({@link #setDateFormat(DateFormat)} and
57 * {@link #setNumberFormat(NumberFormat)}).
58 *
59 * @author Dave Syer
60 * @author Michael Minella
61 *
62 */
63public class DefaultJobParametersConverter implements JobParametersConverter {
64 
65        public static final String DATE_TYPE = "(date)";
66 
67        public static final String STRING_TYPE = "(string)";
68 
69        public static final String LONG_TYPE = "(long)";
70 
71        private static final String DOUBLE_TYPE = "(double)";
72 
73        private static final String NON_IDENTIFYING_FLAG = "-";
74 
75        private static final String IDENTIFYING_FLAG = "+";
76 
77        private static NumberFormat DEFAULT_NUMBER_FORMAT = NumberFormat.getInstance(Locale.US);
78 
79        private DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd");
80 
81        private NumberFormat numberFormat = DEFAULT_NUMBER_FORMAT;
82 
83        private final NumberFormat longNumberFormat = new DecimalFormat("#");
84 
85        /**
86         * Check for suffix on keys and use those to decide how to convert the
87         * value.
88         *
89         * @throws IllegalArgumentException if a number or date is passed in that
90         * cannot be parsed, or cast to the correct type.
91         *
92         * @see org.springframework.batch.core.converter.JobParametersConverter#getJobParameters(java.util.Properties)
93         */
94        @Override
95        public JobParameters getJobParameters(Properties props) {
96 
97                if (props == null || props.isEmpty()) {
98                        return new JobParameters();
99                }
100 
101                JobParametersBuilder propertiesBuilder = new JobParametersBuilder();
102 
103                for (Iterator<Entry<Object, Object>> it = props.entrySet().iterator(); it.hasNext();) {
104                        Entry<Object, Object> entry = it.next();
105                        String key = (String) entry.getKey();
106                        String value = (String) entry.getValue();
107 
108                        boolean identifying = isIdentifyingKey(key);
109                        if(!identifying) {
110                                key = key.replaceFirst(NON_IDENTIFYING_FLAG, "");
111                        } else if(identifying && key.startsWith(IDENTIFYING_FLAG)) {
112                                key = key.replaceFirst("\\" + IDENTIFYING_FLAG, "");
113                        }
114 
115                        if (key.endsWith(DATE_TYPE)) {
116                                Date date;
117                                try {
118                                        date = dateFormat.parse(value);
119                                }
120                                catch (ParseException ex) {
121                                        String suffix = (dateFormat instanceof SimpleDateFormat) ? ", use "
122                                                        + ((SimpleDateFormat) dateFormat).toPattern() : "";
123                                                        throw new IllegalArgumentException("Date format is invalid: [" + value + "]" + suffix);
124                                }
125                                propertiesBuilder.addDate(StringUtils.replace(key, DATE_TYPE, ""), date, identifying);
126                        }
127                        else if (key.endsWith(LONG_TYPE)) {
128                                Long result;
129                                try {
130                                        result = (Long) parseNumber(value);
131                                }
132                                catch (ClassCastException ex) {
133                                        throw new IllegalArgumentException("Number format is invalid for long value: [" + value
134                                                        + "], use a format with no decimal places");
135                                }
136                                propertiesBuilder.addLong(StringUtils.replace(key, LONG_TYPE, ""), result, identifying);
137                        }
138                        else if (key.endsWith(DOUBLE_TYPE)) {
139                                Double result = parseNumber(value).doubleValue();
140                                propertiesBuilder.addDouble(StringUtils.replace(key, DOUBLE_TYPE, ""), result, identifying);
141                        }
142                        else if (StringUtils.endsWithIgnoreCase(key, STRING_TYPE)) {
143                                propertiesBuilder.addString(StringUtils.replace(key, STRING_TYPE, ""), value, identifying);
144                        }
145                        else {
146                                propertiesBuilder.addString(key, value, identifying);
147                        }
148                }
149 
150                return propertiesBuilder.toJobParameters();
151        }
152 
153        private boolean isIdentifyingKey(String key) {
154                boolean identifying = true;
155 
156                if(key.startsWith(NON_IDENTIFYING_FLAG)) {
157                        identifying = false;
158                }
159 
160                return identifying;
161        }
162 
163        /**
164         * Delegate to {@link NumberFormat} to parse the value
165         */
166        private Number parseNumber(String value) {
167                try {
168                        return numberFormat.parse(value);
169                }
170                catch (ParseException ex) {
171                        String suffix = (numberFormat instanceof DecimalFormat) ? ", use "
172                                        + ((DecimalFormat) numberFormat).toPattern() : "";
173                                        throw new IllegalArgumentException("Number format is invalid: [" + value + "], use " + suffix);
174                }
175        }
176 
177        /**
178         * Use the same suffixes to create properties (omitting the string suffix
179         * because it is the default).
180         *
181         * @see org.springframework.batch.core.converter.JobParametersConverter#getProperties(org.springframework.batch.core.JobParameters)
182         */
183        @Override
184        public Properties getProperties(JobParameters params) {
185 
186                if (params == null || params.isEmpty()) {
187                        return new Properties();
188                }
189 
190                Map<String, JobParameter> parameters = params.getParameters();
191                Properties result = new Properties();
192                for (Entry<String, JobParameter> entry : parameters.entrySet()) {
193 
194                        String key = entry.getKey();
195                        JobParameter jobParameter = entry.getValue();
196                        Object value = jobParameter.getValue();
197                        if (value != null) {
198                                if (jobParameter.getType() == ParameterType.DATE) {
199                                        result.setProperty(key + DATE_TYPE, dateFormat.format(value));
200                                }
201                                else if (jobParameter.getType() == ParameterType.LONG) {
202                                        result.setProperty(key + LONG_TYPE, longNumberFormat.format(value));
203                                }
204                                else if (jobParameter.getType() == ParameterType.DOUBLE) {
205                                        result.setProperty(key + DOUBLE_TYPE, decimalFormat((Double)value));
206                                }
207                                else {
208                                        result.setProperty(key, "" + value);
209                                }
210                        }
211                }
212                return result;
213        }
214 
215        /**
216         * @param value a decimal value
217         * @return a best guess at the desired format
218         */
219        private String decimalFormat(double value) {
220                if (numberFormat != DEFAULT_NUMBER_FORMAT) {
221                        return numberFormat.format(value);
222                }
223                return Double.toString(value);
224        }
225 
226        /**
227         * Public setter for injecting a date format.
228         *
229         * @param dateFormat a {@link DateFormat}, defaults to "yyyy/MM/dd"
230         */
231        public void setDateFormat(DateFormat dateFormat) {
232                this.dateFormat = dateFormat;
233        }
234 
235        /**
236         * Public setter for the {@link NumberFormat}. Used to parse longs and
237         * doubles, so must not contain decimal place (e.g. use "#" or "#,###").
238         *
239         * @param numberFormat the {@link NumberFormat} to set
240         */
241        public void setNumberFormat(NumberFormat numberFormat) {
242                this.numberFormat = numberFormat;
243        }
244}

[all classes][org.springframework.batch.core.converter]
EMMA 2.0.5312 (C) Vladimir Roubtsov