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