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