View Javadoc
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 com.opencsv.CSVParser;
19  import com.opencsv.CSVParserBuilder;
20  import com.opencsv.CSVReader;
21  import com.opencsv.CSVReaderBuilder;
22  import com.opencsv.bean.mocks.*;
23  import com.opencsv.enums.CSVReaderNullFieldIndicator;
24  import com.opencsv.exceptions.CsvException;
25  import com.opencsv.exceptions.CsvRequiredFieldEmptyException;
26  import org.junit.jupiter.api.Assertions;
27  import org.junit.jupiter.api.Test;
28  
29  import java.io.*;
30  import java.util.Iterator;
31  import java.util.List;
32  import java.util.NoSuchElementException;
33  
34  import static org.junit.jupiter.api.Assertions.*;
35  
36  public class CsvToBeanAsIteratorTest {
37  
38      private static final String TEST_STRING = "name,orderNumber,num\n"
39              + "kyle,abc123456,123\n"
40              + "jimmy,def098765,456 ";
41  
42      private CSVReader createReader() {
43          StringReader reader = new StringReader(TEST_STRING);
44          return new CSVReader(reader);
45      }
46  
47      // This class is an example where you would want to use the BeanVerifier instead as the position of
48      // the number could be different if you are getting data from different sources.
49      private static class FilterSmallNumbers implements CsvToBeanFilter {
50          @Override
51          public boolean allowLine(String[] line) {
52              return Integer.parseInt(line[2].trim()) > 200;
53          }
54      }
55  
56      @Test
57      public void throwRuntimeExceptionWhenExceptionIsThrown() {
58          CsvToBean<Object> bean = new CsvToBean<>();
59          bean.setMappingStrategy(new ErrorHeaderMappingStrategy<>());
60          bean.setCsvReader(createReader());
61          Assertions.assertThrows(RuntimeException.class, () -> {
62              for (Object o : bean) {
63              }
64          });
65      }
66  
67      @Test
68      public void throwRuntimeExceptionLineWhenExceptionIsThrown() {
69          CsvToBean<Object> bean = new CsvToBean<>();
70          bean.setMappingStrategy(new ErrorLineMappingStrategy<>());
71          bean.setCsvReader(createReader());
72          Assertions.assertThrows(RuntimeException.class, () -> {
73              for (Object o : bean) {
74              }
75          });
76      }
77  
78      @Test
79      public void parseBeanWithNoAnnotations() {
80          HeaderColumnNameMappingStrategy<MockBean> strategy = new HeaderColumnNameMappingStrategy<>();
81          strategy.setType(MockBean.class);
82          CsvToBean<MockBean> bean = new CsvToBean<>();
83          bean.setMappingStrategy(strategy);
84          bean.setCsvReader(createReader());
85  
86          Iterator<MockBean> it = bean.iterator();
87          assertTrue(it.hasNext());
88          assertEquals(new MockBean("kyle", null, "abc123456", 123, 0.0), it.next());
89          assertTrue(it.hasNext());
90          assertEquals(new MockBean("jimmy", null, "def098765", 456, 0.0), it.next());
91          assertFalse(it.hasNext());
92          try {
93              it.next();
94              fail("Iterator should have thrown an exception trying to access the element after the end of the list");
95          } catch (NoSuchElementException e) {/* Good. */
96          }
97      }
98  
99      @Test
100     public void iteratorShouldNotSupportRemove() {
101         HeaderColumnNameMappingStrategy<MockBean> strategy = new HeaderColumnNameMappingStrategy<>();
102         strategy.setType(MockBean.class);
103         CsvToBean<MockBean> bean = new CsvToBean<>();
104         bean.setMappingStrategy(strategy);
105         bean.setCsvReader(createReader());
106 
107         Iterator<MockBean> it = bean.iterator();
108         Assertions.assertThrows(UnsupportedOperationException.class, it::remove);
109     }
110 
111     @Test
112     public void bug133ShouldNotThrowNullPointerExceptionWhenProcessingEmptyWithNoAnnotations() {
113         HeaderColumnNameMappingStrategy<Bug133Bean> strategy = new HeaderColumnNameMappingStrategy<>();
114         strategy.setType(Bug133Bean.class);
115 
116         StringReader reader = new StringReader("one;two;three\n"
117                 + "kyle;;123\n"
118                 + "jimmy;;456 ");
119 
120         CSVParserBuilder parserBuilder = new CSVParserBuilder();
121         CSVReaderBuilder readerBuilder = new CSVReaderBuilder(reader);
122 
123         CSVParser parser = parserBuilder.withFieldAsNull(CSVReaderNullFieldIndicator.BOTH).withSeparator(';').build();
124         CSVReader csvReader = readerBuilder.withCSVParser(parser).build();
125 
126         CsvToBean<Bug133Bean> bean = new CsvToBean<>();
127         bean.setMappingStrategy(strategy);
128         bean.setCsvReader(csvReader);
129 
130         Iterator<Bug133Bean> it = bean.iterator();
131         assertTrue(it.hasNext());
132         assertNotNull(it.next());
133         assertTrue(it.hasNext());
134         assertNotNull(it.next());
135         assertFalse(it.hasNext());
136     }
137 
138     @Test
139     public void throwIllegalStateWhenParseWithoutArgumentsIsCalled() {
140         CsvToBean csvtb = new CsvToBean();
141         Assertions.assertThrows(IllegalStateException.class, csvtb::iterator);
142     }
143 
144     @Test
145     public void throwIllegalStateWhenOnlyReaderIsSpecifiedToParseWithoutArguments() {
146         CsvToBean csvtb = new CsvToBean();
147         csvtb.setCsvReader(new CSVReader(new StringReader(TEST_STRING)));
148         Assertions.assertThrows(IllegalStateException.class, csvtb::iterator);
149     }
150 
151     @Test
152     public void throwIllegalStateWhenOnlyMapperIsSpecifiedToParseWithoutArguments() {
153         CsvToBean<AnnotatedMockBeanFull> csvtb = new CsvToBean<>();
154         HeaderColumnNameMappingStrategy<AnnotatedMockBeanFull> strat = new HeaderColumnNameMappingStrategy<>();
155         strat.setType(AnnotatedMockBeanFull.class);
156         csvtb.setMappingStrategy(strat);
157         Assertions.assertThrows(IllegalStateException.class, csvtb::iterator);
158     }
159 
160     @Test
161     public void readWithIteratorAndFilter() {
162         HeaderColumnNameMappingStrategy<MockBean> strategy;
163         strategy = new HeaderColumnNameMappingStrategy<>();
164         strategy.setType(MockBean.class);
165         CsvToBean<MockBean> bean = new CsvToBeanBuilder<MockBean>(new StringReader(TEST_STRING))
166                 .withMappingStrategy(strategy)
167                 .withFilter(new FilterSmallNumbers())
168                 .build();
169 
170         Iterator<MockBean> iterator = bean.iterator();
171 
172         assertTrue(iterator.hasNext());
173         MockBean mockBean = iterator.next();
174         assertEquals("jimmy", mockBean.getName());
175         assertEquals("def098765", mockBean.getOrderNumber());
176         assertEquals(456, mockBean.getNum());
177 
178         assertFalse(iterator.hasNext());
179     }
180 
181     @Test
182     public void readWithIteratorOfAnnotatedBean() {
183         HeaderColumnNameMappingStrategy<MinimalCsvBindByNameBeanForWriting> minimalStrategy = new HeaderColumnNameMappingStrategy<>();
184         minimalStrategy.setType(MinimalCsvBindByNameBeanForWriting.class);
185         StringReader reader = new StringReader("finda,findb,c\n1,2,3\n4,5,6");
186         Iterator<MinimalCsvBindByNameBeanForWriting> iterator = new CsvToBeanBuilder<MinimalCsvBindByNameBeanForWriting>(reader)
187                 .withMappingStrategy(minimalStrategy)
188                 .build()
189                 .iterator();
190 
191         assertTrue(iterator.hasNext());
192         MinimalCsvBindByNameBeanForWriting mockBean = iterator.next();
193         assertEquals(1, mockBean.getA());
194         assertEquals(2, mockBean.getB());
195         assertEquals(3, mockBean.getC());
196 
197         assertTrue(iterator.hasNext());
198         mockBean = iterator.next();
199         assertEquals(4, mockBean.getA());
200         assertEquals(5, mockBean.getB());
201         assertEquals(6, mockBean.getC());
202 
203         assertFalse(iterator.hasNext());
204     }
205 
206     @Test
207     public void testRequiredHeaderMissing() {
208         HeaderColumnNameMappingStrategy<AnnotatedMockBeanForIterator> strat
209                 = new HeaderColumnNameMappingStrategy<>();
210         strat.setType(AnnotatedMockBeanForIterator.class);
211         Reader fin = new StringReader("a\n1;2\n3,4");
212         Assertions.assertThrows(RuntimeException.class, () -> {
213             Iterator<AnnotatedMockBeanForIterator> iterator = new CsvToBeanBuilder<AnnotatedMockBeanForIterator>(fin)
214                     .withMappingStrategy(strat)
215                     .withSeparator(';')
216                     .build()
217                     .iterator();
218         });
219     }
220 
221     @Test
222     public void testPrematureEOLUsingHeaderNameMappingWithoutExceptionCapturing() {
223         HeaderColumnNameMappingStrategy<AnnotatedMockBeanForIterator> strat
224                 = new HeaderColumnNameMappingStrategy<>();
225         strat.setType(AnnotatedMockBeanForIterator.class);
226         Reader fin = new StringReader("a;b\n1;2\n3");
227         Iterator<AnnotatedMockBeanForIterator> iterator = new CsvToBeanBuilder<AnnotatedMockBeanForIterator>(fin)
228                 .withMappingStrategy(strat)
229                 .withSeparator(';')
230                 .build()
231                 .iterator();
232         try {
233             iterator.next();
234             fail("The first bean should not have been returned since the second bean is incomplete.");
235         } catch (RuntimeException e) {
236             assertNotNull(e.getCause());
237             assertTrue(e.getCause() instanceof CsvRequiredFieldEmptyException);
238         }
239     }
240 
241     @Test
242     public void testPrematureEOLUsingHeaderNameMappingWithExceptionCapturing() {
243         HeaderColumnNameMappingStrategy<AnnotatedMockBeanForIterator> strat
244                 = new HeaderColumnNameMappingStrategy<>();
245         strat.setType(AnnotatedMockBeanForIterator.class);
246         Reader fin = new StringReader("a;b\n1;2\n3");
247         CsvToBean<AnnotatedMockBeanForIterator> csvtb = new CsvToBeanBuilder<AnnotatedMockBeanForIterator>(fin)
248                 .withMappingStrategy(strat)
249                 .withSeparator(';')
250                 .withThrowExceptions(false)
251                 .build();
252         Iterator<AnnotatedMockBeanForIterator> iterator = csvtb.iterator();
253 
254         iterator.next(); // The first bean is okay.
255         assertFalse(iterator.hasNext());
256         List<CsvException> savedExceptions = csvtb.getCapturedExceptions();
257         assertEquals(1, savedExceptions.size());
258         CsvException csve = savedExceptions.get(0);
259         assertTrue(csve instanceof CsvRequiredFieldEmptyException);
260     }
261 
262     @Test
263     public void iteratorConvertsIOExceptionToRuntimeException() {
264         HeaderColumnNameMappingStrategy<MockBean> strategy = new HeaderColumnNameMappingStrategy<>();
265         strategy.setType(MockBean.class);
266         CsvToBean<MockBean> bean = new CsvToBean<>();
267         bean.setMappingStrategy(strategy);
268         bean.setCsvReader(new CSVReader(new ReaderThrowsIOException()));
269 
270         try {
271             bean.iterator();
272             fail("Exception should have been thrown.");
273         } catch (RuntimeException re) {
274             assertNotNull(re.getCause());
275             assertTrue(re.getCause() instanceof IOException);
276         }
277     }
278 
279     @Test
280     public void testMultipleExceptionsPerLine() throws FileNotFoundException {
281         ColumnPositionMappingStrategy<AnnotatedMockBeanFull> strat =
282                 new ColumnPositionMappingStrategy<>();
283         strat.setType(AnnotatedMockBeanFull.class);
284         Reader fin = new FileReader("src/test/resources/testMultipleExceptionsPerLine.csv");
285         CsvToBean<AnnotatedMockBeanFull> ctb = new CsvToBeanBuilder<AnnotatedMockBeanFull>(fin)
286                 .withMappingStrategy(strat)
287                 .withSeparator(';')
288                 .withThrowExceptions(false)
289                 .build();
290         Iterator<AnnotatedMockBeanFull> it = ctb.iterator();
291         while(it.hasNext()) { it.next(); }
292         List<CsvException> exceptionList = ctb.getCapturedExceptions();
293         assertNotNull(exceptionList);
294         assertEquals(6, exceptionList.size()); // Two lines, three mistakes per line
295         assertEquals(1, exceptionList.get(0).getLineNumber());
296         assertEquals(1, exceptionList.get(1).getLineNumber());
297         assertEquals(1, exceptionList.get(2).getLineNumber());
298         assertEquals(2, exceptionList.get(3).getLineNumber());
299         assertEquals(2, exceptionList.get(4).getLineNumber());
300         assertEquals(2, exceptionList.get(5).getLineNumber());
301     }
302 }