View Javadoc
1   /*
2    * Copyright 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   */
16  
17  package com.orangesignal.csv.bean;
18  
19  import java.io.IOException;
20  import java.lang.reflect.Field;
21  import java.text.Format;
22  import java.text.ParseException;
23  import java.util.ArrayList;
24  import java.util.HashMap;
25  import java.util.List;
26  import java.util.Map;
27  
28  /**
29   * Java プログラム要素の操作を簡素化するヘルパーの基底クラスを提供します。
30   * 
31   * @param <T> Java プログラム要素の型
32   * @param <O> Java プログラム要素の操作を簡素化するヘルパークラスの型
33   * @author Koji Sugisawa
34   * @since 1.4.0
35   */
36  public abstract class AbstractCsvBeanTemplate<T, O extends AbstractCsvBeanTemplate<T, O>> {
37  
38  	/**
39  	 * Java プログラム要素の型を保持します。
40  	 */
41  	private Class<T> type;
42  
43  	/**
44  	 * Java プログラム要素のフィールド名と項目値を解析するオブジェクトのマップを保持します。
45  	 */
46  	private Map<String, Format> valueParserMapping = new HashMap<String, Format>();
47  
48  	/**
49  	 * 項目名 (または項目位置) と項目値へ書式化するオブジェクトのマップを保持します。
50  	 */
51  	private Map<Object, Format> valueFormatterMapping = new HashMap<Object, Format>();
52  
53  	/**
54  	 * 区切り文字形式データの項目値コンバータを保持します。
55  	 */
56  	private CsvValueConverter valueConverter = new SimpleCsvValueConverter();
57  
58  	// ------------------------------------------------------------------------
59  	// コンストラクタ
60  
61  	/**
62  	 * コンストラクタです。
63  	 * 
64  	 * @param type Java プログラム要素の型
65  	 * @throws IllegalArgumentException {@code type} が {@code null} の場合。
66  	 */
67  	protected AbstractCsvBeanTemplate(final Class<T> type) {
68  		if (type == null) {
69  			throw new IllegalArgumentException("Class must not be null");
70  		}
71  		this.type = type;
72  	}
73  
74  	// ------------------------------------------------------------------------
75  	// ゲッター / セッター
76  
77  	/**
78  	 * Java プログラム要素の型を返します。
79  	 * 
80  	 * @return Java プログラム要素の型
81  	 */
82  	public Class<T> getType() {
83  		return type;
84  	}
85  
86  	/**
87  	 * Java プログラム要素のフィールド名と項目値を解析するオブジェクトのマップを設定します。
88  	 * 
89  	 * @param valueParserMapping Java プログラム要素のフィールド名と項目値を解析するオブジェクトのマップ
90  	 * @throws IllegalArgumentException {@code valueParserMapping} が {@code null} の場合
91  	 */
92  	public void setValueParserMapping(final Map<String, Format> valueParserMapping) {
93  		if (valueParserMapping == null) {
94  			throw new IllegalArgumentException("CSV value parser mapping must not be null");
95  		}
96  		this.valueParserMapping = valueParserMapping;
97  	}
98  
99  	/**
100 	 * Java プログラム要素のフィールド名と項目値を解析するオブジェクトのマップを設定します。
101 	 * 
102 	 * @param valueParserMapping Java プログラム要素のフィールド名と項目値を解析するオブジェクトのマップ
103 	 * @return このオブジェクトへの参照
104 	 * @throws IllegalArgumentException {@code valueParserMapping} が {@code null} の場合
105 	 */
106 	@SuppressWarnings("unchecked")
107 	public O valueParserMapping(final Map<String, Format> valueParserMapping) {
108 		setValueParserMapping(valueParserMapping);
109 		return (O) this;
110 	}
111 
112 	/**
113 	 * 項目名 (または項目位置) と項目値へ書式化するオブジェクトのマップを設定します。
114 	 * 
115 	 * @param valueFormatterMapping 項目名 (または項目位置) と項目値へ書式化するオブジェクトのマップ
116 	 * @throws IllegalArgumentException {@code valueFormaterMapping} が {@code null} の場合
117 	 */
118 	public void setValueFormatterMapping(final Map<Object, Format> valueFormatterMapping) {
119 		if (valueFormatterMapping == null) {
120 			throw new IllegalArgumentException("CSV value formatter mapping must not be null");
121 		}
122 		this.valueFormatterMapping = valueFormatterMapping;
123 	}
124 
125 	/**
126 	 * 項目名 (または項目位置) と項目値へ書式化するオブジェクトのマップを設定します。
127 	 * 
128 	 * @param valueFormatterMapping 項目名 (または項目位置) と項目値へ書式化するオブジェクトのマップ
129 	 * @return このオブジェクトへの参照
130 	 * @throws IllegalArgumentException {@code valueFormaterMapping} が {@code null} の場合
131 	 */
132 	@SuppressWarnings("unchecked")
133 	public O valueFormatterMapping(final Map<Object, Format> valueFormatterMapping) {
134 		setValueFormatterMapping(valueFormatterMapping);
135 		return (O) this;
136 	}
137 
138 	/**
139 	 * 区切り文字形式データの項目値コンバータを設定します。
140 	 * 
141 	 * @param valueConverter 区切り文字形式データの項目値コンバータ
142 	 * @throws IllegalArgumentException {@code valueConverter} が {@code null} の場合
143 	 */
144 	public void setValueConverter(final CsvValueConverter valueConverter) {
145 		if (valueConverter == null) {
146 			throw new IllegalArgumentException("CsvValueConverter must not be null");
147 		}
148 		this.valueConverter = valueConverter;
149 	}
150 
151 	/**
152 	 * 区切り文字形式データの項目値コンバータを設定します。
153 	 * 
154 	 * @param valueConverter 区切り文字形式データの項目値コンバータ
155 	 * @return このオブジェクトへの参照
156 	 * @throws IllegalArgumentException {@code valueConverter} が {@code null} の場合
157 	 */
158 	@SuppressWarnings("unchecked")
159 	public O valueConverter(final CsvValueConverter valueConverter) {
160 		setValueConverter(valueConverter);
161 		return (O) this;
162 	}
163 
164 	// ------------------------------------------------------------------------
165 
166 	/**
167 	 * 指定された Java プログラム要素のフィールドを処理するフォーマットオブジェクトを設定します。
168 	 * 
169 	 * @param name Java プログラム要素のフィールド名
170 	 * @param format フィールドを処理するフォーマットオブジェクト
171 	 * @return このオブジェクトへの参照
172 	 */
173 	@SuppressWarnings("unchecked")
174 	public O format(final String name, final Format format) {
175 		setValueParser(name, format);
176 		setValueFormatter(name, format);
177 		return (O) this;
178 	}
179 
180 	/**
181 	 * <p>指定された Java プログラム要素のフィールド名と項目値を解析するオブジェクトをマップへ追加します。</p>
182 	 * <p>
183 	 * 指定されたフィールド名に既に項目値を解析するオブジェクトが設定されている場合、
184 	 * 既存の項目値解析オブジェクトへパラメータで指定された項目値解析オブジェクトのパターン文字列を追加します。
185 	 * </p>
186 	 * 
187 	 * @param field Java プログラム要素のフィールド名
188 	 * @param parser 項目値を解析するオブジェクト
189 	 */
190 	public void setValueParser(final String field, final Format parser) {
191 		final Format src = valueParserMapping.get(field);
192 		if (src != null) {
193 			valueParserMapping.put(field, FormatUtils.mergeFormatPattern(src, parser));
194 		} else {
195 			valueParserMapping.put(field, parser);
196 		}
197 	}
198 
199 	/**
200 	 * 指定された項目名 (または項目位置) と項目値へ書式化するオブジェクトをマップへ追加します。
201 	 * 
202 	 * @param column 項目名 (または項目位置)
203 	 * @param formatter 項目値へ書式化するオブジェクト
204 	 */
205 	public void setValueFormatter(final Object column, final Format formatter) {
206 		valueFormatterMapping.put(column, formatter);
207 	}
208 
209 	/**
210 	 * Java プログラム要素の型が表すクラスの新しいインスタンスを生成します。
211 	 * 
212 	 * @return Java プログラム要素の型が表す、クラスの新しく割り当てられたインスタンス
213 	 * @throws IOException Java プログラム要素のインスタンス化に失敗した場合
214 	 */
215 	public T createBean() throws IOException {
216 		try {
217 			return type.newInstance();
218 		} catch (final IllegalAccessException e) {
219 			throw new IOException("Cannot create " + type.getName() + ": " + e.getMessage(), e);
220 		} catch (final InstantiationException e) {
221 			throw new IOException("Cannot create " + type.getName() + ": " + e.getMessage(), e);
222 		}
223 	}
224 
225 	/**
226 	 * 指定された項目名 (または項目位置) と Java プログラム要素のフィールド名のマップと Java プログラム要素の型から、
227 	 * Java プログラム要素のフィールド名と項目名群のマップを構築して返します。
228 	 * 
229 	 * @param map 項目名 (または項目位置) と Java プログラム要素のフィールド名のマップ
230 	 * @return Java プログラム要素のフィールド名と項目名群のマップ
231 	 */
232 	public Map<String, Object[]> createFieldAndColumnsMap(final Map<?, String> map) {
233 		final Map<String, Object[]> results = new HashMap<String, Object[]>();
234 		for (final Field f : type.getDeclaredFields()) {
235 			final String fieldName = f.getName();
236 			final List<Object> list = new ArrayList<Object>();
237 			for (final Map.Entry<?, String> e : map.entrySet()) {
238 				if (fieldName.equals(e.getValue())) {
239 					list.add(e.getKey());
240 				}
241 			}
242 			if (list.size() > 0) {
243 				results.put(fieldName, list.toArray());
244 			}
245 		}
246 		return results;
247 	}
248 
249 	/**
250 	 * 指定された項目値を指定されたフィールドのオブジェクトへ変換して返します。
251 	 * この実装は、指定されたフィールドに対応する項目値を解析するオブジェクトが存在する場合は、{@link Format#parseObject(String)} で得られたオブジェクトを返します。
252 	 * それ以外の場合は、項目値コンバータを使用して得られたオブジェクトを返します。
253 	 * 
254 	 * @param field フィールド
255 	 * @param value 項目値
256 	 * @return 変換された項目値
257 	 */
258 	public Object stringToObject(final Field field, final String value) {
259 		final Format format = valueParserMapping.get(field.getName());
260 		if (format != null) {
261 			if (value == null || value.isEmpty()) {
262 				return null;
263 			}
264 			try {
265 				return format.parseObject(value);
266 			} catch (final ParseException e) {
267 				throw new IllegalArgumentException(String.format("Unable to parse the %s: %s", field.getName(), value), e);
268 			}
269 		}
270 		final Class<?> type = field.getType();
271 		return valueConverter.convert(value, type.isArray() ? type.getComponentType() : type);
272 	}
273 
274 	/**
275 	 * 指定されたオブジェクトを項目値へ変換して返します。
276 	 * この実装は、指定された項目に対応する項目値へ書式化するオブジェクトが存在する場合は、{@link Format#format(Object)} で得られた文字列を返します。
277 	 * それ以外の場合は、項目値コンバータを使用して得られた文字列を返します。
278 	 * 
279 	 * @param column 項目名 (または項目位置)
280 	 * @param obj オブジェクト
281 	 * @return 文字列の項目値
282 	 */
283 	public String objectToString(final Object column, final Object obj) {
284 		final Format format = valueFormatterMapping.get(column);
285 		if (format != null) {
286 			if (obj == null) {
287 				return null;
288 			}
289 			return format.format(obj);
290 		}
291 		return valueConverter.convert(obj);
292 	}
293 
294 }