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.exceptions.CsvBadConverterException;
20 import com.opencsv.exceptions.CsvBeanIntrospectionException;
21 import com.opencsv.exceptions.CsvDataTypeMismatchException;
22 import org.apache.commons.collections4.ListValuedMap;
23 import org.apache.commons.collections4.MultiValuedMap;
24 import org.apache.commons.collections4.SetValuedMap;
25 import org.apache.commons.collections4.multimap.ArrayListValuedHashMap;
26 import org.apache.commons.collections4.multimap.HashSetValuedHashMap;
27 import org.apache.commons.lang3.ArrayUtils;
28
29 import java.lang.reflect.Constructor;
30 import java.lang.reflect.Field;
31 import java.lang.reflect.InvocationTargetException;
32 import java.util.Collection;
33 import java.util.Locale;
34 import java.util.ResourceBundle;
35
36
37
38
39
40
41
42
43
44
45 abstract public class BeanFieldJoin<T, I> extends BeanFieldSingleValue<T, I> {
46
47
48
49
50
51 private final Class<? extends MultiValuedMap> mapType;
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72 public BeanFieldJoin(
73 Class<?> type, Field field, boolean required, Locale errorLocale,
74 CsvConverter converter, Class<? extends MultiValuedMap> mapType,
75 String capture, String format) {
76
77
78 super(type, field, required, errorLocale, converter, capture, format);
79
80
81 if(!MultiValuedMap.class.isAssignableFrom(field.getType())) {
82 throw new CsvBadConverterException(
83 BeanFieldJoin.class,
84 String.format(
85 ResourceBundle.getBundle(
86 ICSVParser.DEFAULT_BUNDLE_NAME,
87 errorLocale).getString("invalid.multivaluedmap.type"),
88 field.getType().toString()));
89 }
90
91
92
93 Class<?> fieldType = field.getType();
94 if(!fieldType.isInterface()) {
95 this.mapType = (Class<MultiValuedMap>)field.getType();
96 }
97 else if(!mapType.isInterface()) {
98 this.mapType = mapType;
99 }
100 else {
101 if(MultiValuedMap.class.equals(fieldType) || ListValuedMap.class.equals(fieldType)) {
102 this.mapType = ArrayListValuedHashMap.class;
103 }
104 else if(SetValuedMap.class.equals(fieldType)) {
105 this.mapType = HashSetValuedHashMap.class;
106 }
107 else {
108 this.mapType = null;
109 throw new CsvBadConverterException(
110 BeanFieldJoin.class,
111 String.format(
112 ResourceBundle.getBundle(
113 ICSVParser.DEFAULT_BUNDLE_NAME,
114 errorLocale).getString("invalid.multivaluedmap.type"),
115 mapType.toString()));
116 }
117 }
118
119
120
121 if(!field.getType().isAssignableFrom(this.mapType)) {
122 throw new CsvBadConverterException(
123 BeanFieldJoin.class,
124 String.format(
125 ResourceBundle.getBundle(
126 ICSVParser.DEFAULT_BUNDLE_NAME,
127 errorLocale).getString("unassignable.multivaluedmap.type"),
128 mapType.getName(), field.getType().getName()));
129 }
130 }
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145 abstract protected Object putNewValue(MultiValuedMap<I, Object> map, String index, Object newValue);
146
147
148
149
150
151
152
153
154 @Override
155 protected void assignValueToField(Object bean, Object obj, String header)
156 throws CsvDataTypeMismatchException {
157
158
159
160
161 @SuppressWarnings("unchecked")
162 MultiValuedMap<I,Object> currentValue = (MultiValuedMap<I,Object>) getFieldValue(bean);
163 try {
164 if(currentValue == null) {
165 Constructor<? extends MultiValuedMap> c = mapType.getConstructor();
166 currentValue = c.newInstance();
167 }
168 putNewValue(currentValue, header, obj);
169 super.assignValueToField(bean, currentValue, header);
170 } catch (IllegalAccessException | InvocationTargetException | ClassCastException e) {
171 CsvBeanIntrospectionException csve =
172 new CsvBeanIntrospectionException(bean, field,
173 e.getLocalizedMessage());
174 csve.initCause(e);
175 throw csve;
176 } catch(InstantiationException | NoSuchMethodException e) {
177 CsvBadConverterException csve = new CsvBadConverterException(
178 BeanFieldJoin.class,
179 String.format(
180 ResourceBundle.getBundle(ICSVParser.DEFAULT_BUNDLE_NAME, errorLocale)
181 .getString("map.cannot.be.instantiated"),
182 mapType.getName()));
183 csve.initCause(e);
184 throw csve;
185 }
186 }
187
188
189
190
191
192
193
194 @Override
195 public Object[] indexAndSplitMultivaluedField(Object value, I index)
196 throws CsvDataTypeMismatchException {
197 Object[] splitObjects = ArrayUtils.EMPTY_OBJECT_ARRAY;
198 if(value != null) {
199 if(MultiValuedMap.class.isAssignableFrom(value.getClass())) {
200 @SuppressWarnings("unchecked")
201 MultiValuedMap<Object,Object> map = (MultiValuedMap<Object,Object>) value;
202 Collection<Object> splitCollection = map.get(index);
203 splitObjects = splitCollection.toArray(ArrayUtils.EMPTY_OBJECT_ARRAY);
204 }
205 else {
206
207
208 throw new CsvDataTypeMismatchException(value, String.class,
209 ResourceBundle.getBundle(ICSVParser.DEFAULT_BUNDLE_NAME, errorLocale)
210 .getString("field.not.multivaluedmap"));
211 }
212 }
213 return splitObjects;
214 }
215
216
217
218
219
220 @Override
221 @SuppressWarnings("unchecked")
222 protected boolean isFieldEmptyForWrite(Object value) {
223 return super.isFieldEmptyForWrite(value) || ((MultiValuedMap<Object, Object>)value).isEmpty();
224 }
225 }