1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package com.opencsv.bean;
17
18 import com.opencsv.ICSVParser;
19 import com.opencsv.bean.util.OpencsvUtils;
20 import com.opencsv.exceptions.CsvBadConverterException;
21 import com.opencsv.exceptions.CsvBeanIntrospectionException;
22 import com.opencsv.exceptions.CsvConstraintViolationException;
23 import com.opencsv.exceptions.CsvDataTypeMismatchException;
24 import org.apache.commons.collections4.Bag;
25 import org.apache.commons.collections4.SortedBag;
26 import org.apache.commons.collections4.bag.HashBag;
27 import org.apache.commons.collections4.bag.TreeBag;
28 import org.apache.commons.lang3.ArrayUtils;
29 import org.apache.commons.lang3.StringUtils;
30
31 import java.lang.reflect.Field;
32 import java.lang.reflect.InvocationTargetException;
33 import java.util.*;
34 import java.util.regex.Matcher;
35 import java.util.regex.Pattern;
36
37
38
39
40
41
42
43
44
45 public class BeanFieldSplit<T, I> extends AbstractBeanField<T, I> {
46
47 private final Pattern splitOn, capture;
48 private final String writeDelimiter, writeFormat;
49 private final Class<? extends Collection> collectionType;
50 private final Class<?> elementType;
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72 public BeanFieldSplit(
73 Class<?> type, Field field, boolean required, Locale errorLocale,
74 CsvConverter converter, String splitOn, String writeDelimiter,
75 Class<? extends Collection> collectionType, Class<?> elementType,
76 String capture, String format) {
77
78
79 super(type, field, required, errorLocale, converter);
80 this.writeDelimiter = writeDelimiter;
81 this.writeFormat = format;
82 this.elementType = elementType;
83
84
85 if(!Collection.class.isAssignableFrom(field.getType())) {
86 throw new CsvBadConverterException(
87 BeanFieldSplit.class,
88 String.format(
89 ResourceBundle.getBundle(
90 ICSVParser.DEFAULT_BUNDLE_NAME,
91 this.errorLocale).getString("invalid.collection.type"),
92 field.getType().toString()));
93 }
94
95
96 this.splitOn = OpencsvUtils.compilePattern(splitOn, 0,
97 BeanFieldSplit.class, this.errorLocale);
98 this.capture = OpencsvUtils.compilePatternAtLeastOneGroup(capture, 0,
99 BeanFieldSplit.class, this.errorLocale);
100
101
102 OpencsvUtils.verifyFormatString(this.writeFormat, BeanFieldSplit.class, this.errorLocale);
103
104
105
106 Class<?> fieldType = field.getType();
107 if(!fieldType.isInterface()) {
108 this.collectionType = (Class<Collection>)field.getType();
109 }
110 else if(!collectionType.isInterface()) {
111 this.collectionType = collectionType;
112 }
113 else {
114 if(Collection.class.equals(fieldType) || List.class.equals(fieldType)) {
115 this.collectionType = ArrayList.class;
116 }
117 else if(Set.class.equals(fieldType)) {
118 if(fieldType.isEnum()) {
119 this.collectionType = EnumSet.class;
120 }
121 else {
122 this.collectionType = HashSet.class;
123 }
124 }
125 else if(SortedSet.class.equals(fieldType) || NavigableSet.class.equals(fieldType)) {
126 this.collectionType = TreeSet.class;
127 }
128 else if(Queue.class.equals(fieldType) || Deque.class.equals(fieldType)) {
129 this.collectionType = ArrayDeque.class;
130 }
131 else if(Bag.class.equals(fieldType)) {
132 this.collectionType = HashBag.class;
133 }
134 else if(SortedBag.class.equals(fieldType)) {
135 this.collectionType = TreeBag.class;
136 }
137 else {
138 this.collectionType = null;
139 throw new CsvBadConverterException(
140 BeanFieldSplit.class,
141 String.format(
142 ResourceBundle.getBundle(
143 ICSVParser.DEFAULT_BUNDLE_NAME,
144 this.errorLocale).getString("invalid.collection.type"),
145 collectionType.toString()));
146 }
147 }
148
149
150
151 if(!field.getType().isAssignableFrom(this.collectionType)) {
152 throw new CsvBadConverterException(
153 BeanFieldSplit.class,
154 String.format(
155 ResourceBundle.getBundle(
156 ICSVParser.DEFAULT_BUNDLE_NAME,
157 this.errorLocale).getString("unassignable.collection.type"),
158 collectionType.getName(), field.getType().getName()));
159 }
160 }
161
162
163
164
165
166
167
168
169
170
171
172
173 @Override
174 protected Object convert(String value) throws CsvDataTypeMismatchException, CsvConstraintViolationException {
175 Collection<Object> collection;
176 try {
177 if(collectionType.equals(EnumSet.class)) {
178 collection = (Collection)EnumSet.noneOf((Class<Enum>)elementType);
179 }
180 else {
181 collection = collectionType.getDeclaredConstructor().newInstance();
182 }
183 }
184 catch(InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException | SecurityException e) {
185 CsvBeanIntrospectionException csve = new CsvBeanIntrospectionException(
186 String.format(
187 ResourceBundle
188 .getBundle(ICSVParser.DEFAULT_BUNDLE_NAME, errorLocale)
189 .getString("collection.cannot.be.instantiated"),
190 collectionType.getCanonicalName()));
191 csve.initCause(e);
192 throw csve;
193 }
194
195 String[] splitValues = value == null ? ArrayUtils.EMPTY_STRING_ARRAY : splitOn.split(value);
196 for(String s : splitValues) {
197 if(capture != null) {
198 Matcher m = capture.matcher(s);
199 if(m.matches()) {
200 s = m.group(1);
201 }
202
203 }
204 collection.add(converter.convertToRead(s));
205 }
206 return collection;
207 }
208
209
210
211
212
213
214 @Override
215 protected String convertToWrite(Object value)
216 throws CsvDataTypeMismatchException {
217 String retval = StringUtils.EMPTY;
218 if(value != null) {
219 @SuppressWarnings("unchecked") Collection<Object> collection = (Collection<Object>) value;
220 String[] convertedValue = new String[collection.size()];
221 int i = 0;
222 for(Object o : collection) {
223 convertedValue[i] = converter.convertToWrite(o);
224 if(StringUtils.isNotEmpty(this.writeFormat)
225 && StringUtils.isNotEmpty(convertedValue[i])) {
226 convertedValue[i] = String.format(this.writeFormat, convertedValue[i]);
227 }
228 i++;
229 }
230 retval = StringUtils.join(convertedValue, writeDelimiter);
231 }
232 return retval;
233 }
234
235
236
237
238
239
240 @SuppressWarnings("unchecked")
241 @Override
242 protected boolean isFieldEmptyForWrite(Object value) {
243 return super.isFieldEmptyForWrite(value) || ((Collection<Object>)value).isEmpty();
244 }
245 }