View Javadoc
1   /*
2    * CSVeed (https://github.com/42BV/CSVeed)
3    *
4    * Copyright 2013-2023 CSVeed.
5    *
6    * All rights reserved. This program and the accompanying materials
7    * are made available under the terms of The Apache Software License,
8    * Version 2.0 which accompanies this distribution, and is available at
9    * https://www.apache.org/licenses/LICENSE-2.0.txt
10   */
11  package org.csveed.bean;
12  
13  import java.io.Reader;
14  import java.util.ArrayList;
15  import java.util.List;
16  
17  import org.csveed.api.Header;
18  import org.csveed.api.Row;
19  import org.csveed.report.CsvException;
20  import org.csveed.report.GeneralError;
21  import org.csveed.row.RowReader;
22  import org.csveed.row.RowReaderImpl;
23  import org.slf4j.Logger;
24  import org.slf4j.LoggerFactory;
25  
26  /**
27   * The Class BeanReaderImpl.
28   *
29   * @param <T>
30   *            the generic type
31   */
32  public class BeanReaderImpl<T> implements BeanReader<T> {
33  
34      /** The Constant logger. */
35      private static final Logger logger = LoggerFactory.getLogger(BeanReaderImpl.class);
36  
37      /** The row reader. */
38      private final RowReader rowReader;
39  
40      /** The bean instructions. */
41      private final BeanInstructions beanInstructions;
42  
43      /** The mapper. */
44      private AbstractMapper<T> mapper;
45  
46      /** The current dynamic column. */
47      private final DynamicColumn currentDynamicColumn;
48  
49      /** The unmapped row. */
50      private Row unmappedRow;
51  
52      /**
53       * Instantiates a new bean reader impl.
54       *
55       * @param reader
56       *            the reader
57       * @param beanClass
58       *            the bean class
59       */
60      public BeanReaderImpl(Reader reader, Class<T> beanClass) {
61          this(reader, new BeanParser().getBeanInstructions(beanClass));
62      }
63  
64      /**
65       * Instantiates a new bean reader impl.
66       *
67       * @param reader
68       *            the reader
69       * @param beanInstructions
70       *            the bean instructions
71       */
72      public BeanReaderImpl(Reader reader, BeanInstructions beanInstructions) {
73          this.beanInstructions = beanInstructions;
74          this.rowReader = new RowReaderImpl(reader, this.beanInstructions.getRowInstructions());
75          this.currentDynamicColumn = new DynamicColumn(this.beanInstructions.getStartIndexDynamicColumns());
76      }
77  
78      /**
79       * Gets the mapper.
80       *
81       * @return the mapper
82       */
83      public AbstractMapper<T> getMapper() {
84          if (this.mapper == null) {
85              this.mapper = this.createMappingStrategy();
86              mapper.setBeanInstructions(this.beanInstructions);
87          }
88          return mapper;
89      }
90  
91      @Override
92      public List<T> readBeans() {
93          List<T> beans = new ArrayList<>();
94          while (!isFinished()) {
95              T bean = readBean();
96              if (bean != null) {
97                  beans.add(bean);
98              }
99          }
100         return beans;
101     }
102 
103     @Override
104     public T readBean() {
105         logSettings();
106 
107         if (this.beanInstructions.useHeader()) {
108             getMapper().verifyHeader(getHeader());
109         }
110 
111         currentDynamicColumn.checkForReset(((RowReaderImpl) rowReader).getMaxNumberOfColumns());
112         if (currentDynamicColumn.atFirstDynamicColumn()) {
113             unmappedRow = rowReader.readRow();
114         }
115         if (unmappedRow == null) {
116             return null;
117         }
118 
119         T bean = getMapper().convert(instantiateBean(), unmappedRow, getCurrentLine(), currentDynamicColumn);
120         currentDynamicColumn.advanceDynamicColumn();
121         return bean;
122     }
123 
124     /**
125      * Log settings.
126      */
127     protected void logSettings() {
128         this.beanInstructions.logSettings();
129     }
130 
131     /**
132      * Gets the header.
133      *
134      * @return the header
135      */
136     protected Header getHeader() {
137         if (this.beanInstructions.useHeader()) {
138             return rowReader.getHeader();
139         }
140         return null;
141     }
142 
143     @Override
144     public Header readHeader() {
145         return rowReader.readHeader();
146     }
147 
148     @Override
149     public int getCurrentLine() {
150         return this.rowReader.getCurrentLine();
151     }
152 
153     @Override
154     public boolean isFinished() {
155         return rowReader.isFinished();
156     }
157 
158     @Override
159     public RowReader getRowReader() {
160         return this.rowReader;
161     }
162 
163     /**
164      * Instantiate bean.
165      *
166      * @return the t
167      */
168     private T instantiateBean() {
169         try {
170             return this.getBeanClass().getDeclaredConstructor().newInstance();
171         } catch (Exception err) {
172             throw new CsvException(new GeneralError("Unable to instantiate the bean class "
173                     + this.getBeanClass().getName() + ". Does it have a no-arg public constructor?"));
174         }
175     }
176 
177     /**
178      * Gets the bean class.
179      *
180      * @return the bean class
181      */
182     @SuppressWarnings("unchecked")
183     public Class<T> getBeanClass() {
184         return this.beanInstructions.getBeanClass();
185     }
186 
187     /**
188      * Creates the mapping strategy.
189      *
190      * @return the abstract mapper
191      */
192     @SuppressWarnings("unchecked")
193     public AbstractMapper<T> createMappingStrategy() {
194         try {
195             return this.beanInstructions.getMappingStrategy().getDeclaredConstructor().newInstance();
196         } catch (Exception e) {
197             logger.trace("", e);
198             throw new CsvException(new GeneralError("Unable to instantiate the mapping strategy"));
199         }
200     }
201 
202     @Override
203     public BeanInstructions getBeanInstructions() {
204         return this.beanInstructions;
205     }
206 
207 }