1 package com.opencsv.bean;
2
3 import com.opencsv.CSVReader;
4 import com.opencsv.ICSVParser;
5 import com.opencsv.exceptions.CsvBadConverterException;
6 import com.opencsv.exceptions.CsvRequiredFieldEmptyException;
7 import org.apache.commons.collections4.ListValuedMap;
8 import org.apache.commons.lang3.ArrayUtils;
9 import org.apache.commons.lang3.StringUtils;
10
11 import java.io.IOException;
12 import java.io.Serializable;
13 import java.lang.reflect.Field;
14 import java.util.*;
15
16
17
18
19
20
21
22
23
24 abstract public class HeaderNameBaseMappingStrategy<T> extends AbstractMappingStrategy<String, String, ComplexFieldMapEntry<String, String, T>, T> {
25
26
27
28
29
30 protected FieldMapByName<T> fieldMap = null;
31
32
33 protected Comparator<String> writeOrder = null;
34
35
36 protected final boolean forceCorrectRecordLength;
37
38
39 public HeaderNameBaseMappingStrategy() {
40 this.forceCorrectRecordLength = false;
41 }
42
43
44
45
46
47
48
49
50 public HeaderNameBaseMappingStrategy(boolean forceCorrectRecordLength) {
51 this.forceCorrectRecordLength = forceCorrectRecordLength;
52 }
53
54 @Override
55 public void captureHeader(CSVReader reader) throws IOException, CsvRequiredFieldEmptyException {
56
57 if(type == null) {
58 throw new IllegalStateException(ResourceBundle
59 .getBundle(ICSVParser.DEFAULT_BUNDLE_NAME, errorLocale)
60 .getString("type.unset"));
61 }
62
63
64 String[] header = ArrayUtils.nullToEmpty(reader.readNextSilently());
65 for(int i = 0; i < header.length; i++) {
66
67
68 if(header[i] == null) {
69 header[i] = StringUtils.EMPTY;
70 }
71 }
72 headerIndex.initializeHeaderIndex(header);
73
74
75 List<FieldMapByNameEntry<T>> missingRequiredHeaders = fieldMap.determineMissingRequiredHeaders(header);
76 if (!missingRequiredHeaders.isEmpty()) {
77 String[] requiredHeaderNames = new String[missingRequiredHeaders.size()];
78 List<Field> requiredFields = new ArrayList<>(missingRequiredHeaders.size());
79 for(int i = 0; i < missingRequiredHeaders.size(); i++) {
80 FieldMapByNameEntry<T> fme = missingRequiredHeaders.get(i);
81 if(fme.isRegexPattern()) {
82 requiredHeaderNames[i] = String.format(
83 ResourceBundle
84 .getBundle(ICSVParser.DEFAULT_BUNDLE_NAME, errorLocale)
85 .getString("matching"),
86 fme.getName());
87 } else {
88 requiredHeaderNames[i] = fme.getName();
89 }
90 requiredFields.add(fme.getField().getField());
91 }
92 String missingRequiredFields = String.join(", ", requiredHeaderNames);
93 String allHeaders = String.join(",", header);
94 CsvRequiredFieldEmptyException e = new CsvRequiredFieldEmptyException(type, requiredFields,
95 String.format(
96 ResourceBundle.getBundle(ICSVParser.DEFAULT_BUNDLE_NAME, errorLocale)
97 .getString("header.required.field.absent"),
98 missingRequiredFields, allHeaders));
99 e.setLine(header);
100 throw e;
101 }
102 }
103
104 @Override
105 protected String chooseMultivaluedFieldIndexFromHeaderIndex(int index) {
106 String[] s = headerIndex.getHeaderIndex();
107 return index >= s.length ? null: s[index];
108 }
109
110 @Override
111 public void verifyLineLength(int numberOfFields) throws CsvRequiredFieldEmptyException {
112 if(!headerIndex.isEmpty()) {
113 if (numberOfFields != headerIndex.getHeaderIndexLength() && !forceCorrectRecordLength) {
114 throw new CsvRequiredFieldEmptyException(type, ResourceBundle
115 .getBundle(ICSVParser.DEFAULT_BUNDLE_NAME, errorLocale)
116 .getString("header.data.mismatch"));
117 }
118 }
119 }
120
121 @Override
122 protected BeanField<T, String> findField(int col) throws CsvBadConverterException {
123 BeanField<T, String> beanField = null;
124 String columnName = getColumnName(col);
125 if (columnName == null) {
126 return null;
127 }
128 columnName = columnName.trim();
129 if (!columnName.isEmpty()) {
130 beanField = fieldMap.get(columnName.toUpperCase());
131 }
132 return beanField;
133 }
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151 @Override
152 protected void loadUnadornedFieldMap(ListValuedMap<Class<?>, Field> fields) {
153 fields.entries().stream()
154 .filter(entry -> !(Serializable.class.isAssignableFrom(entry.getKey()) && "serialVersionUID".equals(entry.getValue().getName())))
155 .filter(entry -> !entry.getValue().isAnnotationPresent(CsvRecurse.class))
156 .forEach(entry -> {
157 final CsvConverter converter = determineConverter(entry.getValue(), entry.getValue().getType(), null, null, null);
158 fieldMap.put(entry.getValue().getName().toUpperCase(), new BeanFieldSingleValue<>(
159 entry.getKey(), entry.getValue(),
160 false, errorLocale, converter, null, null));
161 });
162 }
163
164 @Override
165 protected void initializeFieldMap() {
166 fieldMap = new FieldMapByName<>(errorLocale);
167 fieldMap.setColumnOrderOnWrite(writeOrder);
168 }
169
170 @Override
171 protected FieldMap<String, String, ? extends ComplexFieldMapEntry<String, String, T>, T> getFieldMap() {return fieldMap;}
172
173 @Override
174 public String findHeader(int col) {
175 return headerIndex.getByPosition(col);
176 }
177
178
179
180
181
182
183
184
185
186
187
188 public void setColumnOrderOnWrite(Comparator<String> writeOrder) {
189 this.writeOrder = writeOrder;
190 if(fieldMap != null) {
191 fieldMap.setColumnOrderOnWrite(this.writeOrder);
192 }
193 }
194 }