1 /*
2 * Copyright 2017 Andrew Rucker Jones.
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 package com.opencsv.bean;
17
18 import java.lang.annotation.*;
19 import java.util.regex.Matcher;
20
21 import org.apache.commons.collections4.MultiValuedMap;
22
23 /**
24 * Joins the values of multiple columns from the input into one bean field based
25 * on a selection of column positions.
26 *
27 * @author Andrew Rucker Jones
28 * @since 4.2
29 */
30 @Documented
31 @Retention(RetentionPolicy.RUNTIME)
32 @Target(ElementType.FIELD)
33 @Repeatable(CsvBindAndJoinByPositions.class)
34 public @interface CsvBindAndJoinByPosition {
35
36 /**
37 * Whether or not the annotated field is required to be present in every
38 * data set of the input.
39 * This means that the input cannot be empty. The output after conversion is
40 * not guaranteed to be non-empty. "Input" means the string from every
41 * matching field in the CSV file on reading and the bean member variable on
42 * writing.
43 *
44 * @return If the field is required to contain information.
45 */
46 boolean required() default false;
47
48 /**
49 * The column position(s) in the input that is/are used to fill the
50 * annotated field.
51 * This field allows comma-separated lists of columns, e.g. "2,4,6", as well
52 * as ranges, including open-ended ranges, e.g. "3-5", "10-" or "-3". With
53 * the open-ended versions the implicit ends are the first and last column.
54 * A mixture of these forms is naturally possible, e.g. "2,4,6-10". Nothing
55 * bad will happen if you make a silly list, like "4,2,-0,1000-,10-5".
56 *
57 * @return The position(s) of the column(s) in the CSV file from which this
58 * field should be taken. The column numbers are zero-based.
59 */
60 String position();
61
62 /**
63 * Defines the locale to be used for decoding the argument.
64 * <p>If not specified, the current default locale is used. The locale must be
65 * one recognized by {@link java.util.Locale}. Locale conversion is supported
66 * for the following data types:<ul>
67 * <li>byte and {@link java.lang.Byte}</li>
68 * <li>float and {@link java.lang.Float}</li>
69 * <li>double and {@link java.lang.Double}</li>
70 * <li>int and {@link java.lang.Integer}</li>
71 * <li>long and {@link java.lang.Long}</li>
72 * <li>short and {@link java.lang.Short}</li>
73 * <li>{@link java.math.BigDecimal}</li>
74 * <li>{@link java.math.BigInteger}</li>
75 * <li>All time data types supported by {@link com.opencsv.bean.CsvDate}</li></ul>
76 * <p>The locale must be in a format accepted by
77 * {@link java.util.Locale#forLanguageTag(java.lang.String)}</p>
78 * <p>Caution must be exercised with the default locale, for the default
79 * locale for numerical types does not mean the locale of the running
80 * program, such as en-US or de-DE, but rather <em>no</em> locale. Numbers
81 * will be parsed more or less the way the Java compiler would parse them.
82 * That means, for instance, that thousands separators in long numbers are
83 * not permitted, even if the locale of the running program would accept
84 * them. When dealing with locale-sensitive data, it is always best to
85 * specify the locale explicitly.</p>
86 *
87 * @return The locale selected. The default is indicated by an empty string.
88 */
89 String locale() default "";
90
91 /**
92 * Whether or not the same locale is used for writing as for reading.
93 * If this is true, {@link #locale()} is used for both reading and writing
94 * and {@link #writeLocale()} is ignored.
95 *
96 * @return Whether the read locale is used for writing as well
97 * @since 5.0
98 */
99 boolean writeLocaleEqualsReadLocale() default true;
100
101 /**
102 * The locale for writing.
103 * This field is ignored unless {@link #writeLocaleEqualsReadLocale()} is
104 * {@code false}. The format is identical to {@link #locale()}.
105 *
106 * @return The locale for writing, if one is in use
107 * @see #locale()
108 * @see #writeLocaleEqualsReadLocale()
109 * @since 5.0
110 */
111 String writeLocale() default "";
112
113 /**
114 * Defines the class used for the multi-valued map.
115 * <p>This must be a specific implementation of
116 * {@link org.apache.commons.collections4.MultiValuedMap}, and not an
117 * interface! The default is set to {@code MultiValuedMap.class} as a signal
118 * to use the default for the interface supplied in the bean to be
119 * populated.</p>
120 * <p>The logic for determining which class to instantiate for the
121 * multi-valued map is as follows. In all cases, the implementation must
122 * have a nullary constructor.</p>
123 * <ol><li>If the bean declares a specific implementation instead of the
124 * associated interface
125 * (e.g. {@link org.apache.commons.collections4.multimap.ArrayListValuedHashMap}
126 * vs.
127 * {@link org.apache.commons.collections4.ListValuedMap}), that specific
128 * implementation will always be used.</li>
129 * <li>Otherwise, the implementation named in this field will be used, if it
130 * is not an interface.</li>
131 * <li>If no implementation is specified in this field (i.e. if
132 * an interface is specified, as is the default), a default is used
133 * based on the interface of the bean field annotated. These are:
134 * <ul><li>{@link org.apache.commons.collections4.multimap.ArrayListValuedHashMap} for {@link org.apache.commons.collections4.MultiValuedMap}</li>
135 * <li>{@link org.apache.commons.collections4.multimap.ArrayListValuedHashMap} for {@link org.apache.commons.collections4.ListValuedMap}</li>
136 * <li>{@link org.apache.commons.collections4.multimap.HashSetValuedHashMap} for {@link org.apache.commons.collections4.SetValuedMap}</li></ul></li></ol>
137 *
138 * @return A class implementing {@link org.apache.commons.collections4.MultiValuedMap}
139 */
140 Class<? extends MultiValuedMap> mapType() default MultiValuedMap.class;
141
142 /**
143 * Defines what type the elements of the map should have.
144 * It is necessary to instantiate elements of the map, and it is not
145 * always possible to determine the type of the elements at runtime.
146 * A perfect example of this is {@code Map<String, ? extends Number>}.
147 *
148 * @return The type of the map elements
149 */
150 Class<?> elementType();
151
152 /**
153 * Once the data points have been recovered from the various columns of the
154 * input, a custom converter can optionally be specified for conversion of
155 * each of the data points before they are joined in a
156 * {@link org.apache.commons.collections4.MultiValuedMap}.
157 *
158 * @return The converter applied to each of the data points extracted from
159 * the input
160 * @since 4.3
161 */
162 Class<? extends AbstractCsvConverter> converter() default AbstractCsvConverter.class;
163
164 /**
165 * If this is anything but an empty string, it will be used as a regular
166 * expression to extract part of the input before conversion to the bean
167 * field.
168 * <p>An empty string behaves as if the regular expression {@code ^(.*)$}
169 * had been specified.</p>
170 * <p>The regular expression will be compiled and every field of input will
171 * be passed through it, naturally after the input has been normalized
172 * (quotations and escape characters removed). The first capture group will
173 * be extracted, and that string will be passed on to the appropriate
174 * conversion routine for the bean field in question.</p>
175 * <p>This makes it possible to easily convert input fields with forms like
176 * {@code Grade: 94.2} into {@code 94.2}, which can then be converted to a
177 * floating point bean field, all without writing a custom converter.</p>
178 * <p>The regular expression is applied to the entire string in question
179 * (i.e. with {@link Matcher#matches()}), instead of just the beginning of
180 * the string ({@link Matcher#lookingAt()}) or anywhere in the string
181 * ({@link Matcher#find()}). If it fails to match, the input string is
182 * passed unchanged to the appropriate conversion routine for the bean
183 * field. The reason for this is two-fold:</p>
184 * <ol><li>The matching may occur against an empty string. If the field is
185 * not required, this is legitimate, but it's likely the regular expression
186 * is not written to accommodate this possibility, and it may indeed not be
187 * at all desirable to.</li>
188 * <li>If there is an error in either the regular expression or the input
189 * that causes the match to fail, there is a good likelihood that the
190 * subsequent conversion will fail with a
191 * {@link com.opencsv.exceptions.CsvDataTypeMismatchException} if the
192 * input is not being converted into a simple string.</li></ol>
193 * <p>This is the inverse operation of {@link #format()}.</p>
194 *
195 * @return A regular expression, the first capture group of which will be
196 * used for conversion to the bean field
197 * @since 4.3
198 */
199 String capture() default "";
200
201 /**
202 * If this is anything but an empty string, it will be used as a format
203 * string for {@link java.lang.String#format(String, Object...)} on
204 * writing.
205 * <p>An empty string behaves as if the format string {@code "%s"} had been
206 * specified.</p>
207 * <p>The format string, if it is not empty, should contain one and only
208 * one {@code %s}, which will be replaced by the string value of the bean
209 * field after conversion. If, however, the bean field is empty, then the
210 * output will be empty as well, as opposed to passing an empty string to
211 * this format string and using that as the output.</p>
212 * <p>This is the inverse operation of {@link #capture()}.</p>
213 *
214 * @return A format string for writing fields
215 * @since 4.3
216 */
217 String format() default "";
218
219 /**
220 * A profile can be used to annotate the same field differently for
221 * different inputs or outputs.
222 * <p>Perhaps you have multiple input sources, and they all use different
223 * header names or positions for the same data. With profiles, you don't
224 * have to create different beans with the same fields and different
225 * annotations for each input. Simply annotate the same field multiple
226 * times and specify the profile when you parse the input.</p>
227 * <p>The same applies to output: if you want to be able to represent the
228 * same data in multiple CSV formats (that is, with different headers or
229 * orders), annotate the bean fields multiple times with different profiles
230 * and specify which profile you want to use on writing.</p>
231 * <p>Results are undefined if profile names are not unique.</p>
232 * <p>If the same configuration applies to multiple profiles, simply list
233 * all applicable profile names here. This parameter is an array of
234 * strings.</p>
235 * <p>The empty string, which is the default value, specifies the default
236 * profile and will be used if no annotation for the specific profile
237 * being used can be found, or if no profile is specified.</p>
238 *
239 * @return The names of the profiles this configuration is for
240 * @since 5.4
241 */
242 String[] profiles() default "";
243 }