View Javadoc
1   package net.technearts;
2   
3   import static org.apache.poi.ss.util.CellReference.convertColStringToIndex;
4   
5   import java.io.File;
6   import java.io.IOException;
7   import java.util.HashSet;
8   import java.util.Map;
9   import java.util.Set;
10  import java.util.SortedSet;
11  import java.util.function.Predicate;
12  
13  import org.apache.poi.ss.usermodel.CellType;
14  import org.apache.poi.ss.usermodel.Row;
15  import org.slf4j.Logger;
16  import org.slf4j.LoggerFactory;
17  
18  import com.fasterxml.jackson.core.JsonParseException;
19  import com.fasterxml.jackson.databind.JsonMappingException;
20  import com.fasterxml.jackson.databind.ObjectMapper;
21  import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
22  
23  import net.technearts.ExcelFile.ExcelSheet;
24  
25  public class ExcelMarshaller {
26  
27    private static final Logger LOG = LoggerFactory.getLogger("Marshaller");
28  
29    private Mappings mappings;
30    private Set<String> sheets;
31    private String separator;
32    private Predicate<Row> rowFilter;
33    private boolean skipTitle;
34  
35    private Repository repo;
36  
37    private ExcelMarshaller(File yaml, String separator, Predicate<Row> rowFilter, boolean skipTitle)
38        throws JsonParseException, JsonMappingException, IOException {
39      ObjectMapper mapper = new ObjectMapper(new YAMLFactory());
40      this.mappings = mapper.readValue(yaml, Mappings.class);
41      this.sheets = new HashSet<>();
42      this.separator = separator;
43      this.rowFilter = rowFilter;
44      this.skipTitle = skipTitle;
45      this.repo = new Repository();
46    }
47  
48    private ExcelMarshaller(File yaml, Predicate<Row> rowFilter, boolean skipTitle)
49        throws JsonParseException, JsonMappingException, IOException {
50      this(yaml, ";", rowFilter, skipTitle);
51    }
52  
53    public static ExcelMarshaller create(File file)
54        throws JsonParseException, JsonMappingException, IOException {
55      return create(file, any -> true, true);
56    }
57  
58    public static ExcelMarshaller create(File file, Predicate<Row> rowFilter, boolean skipTitle)
59        throws JsonParseException, JsonMappingException, IOException {
60      ExcelMarshaller marshaller = new ExcelMarshaller(file, rowFilter, skipTitle);
61      for (Mapping mapping : marshaller.mappings.getMappings()) {
62        marshaller.sheets.add(mapping.getSheet());
63      }
64      return marshaller;
65    }
66  
67    public void read(File xls) {
68      ExcelSheet sheet;
69      Class<?> klazz = null;
70      try (ExcelFile file = new ExcelFile(xls)) {
71        for (Mapping mapping : this.mappings.getMappings()) {
72          sheet = file.sheet(mapping.getSheet());
73          klazz = Class.forName(mapping.getClassName());
74          for (int line : getLines(sheet)) {
75            Object entity = klazz.newInstance();
76            for (Member member : mapping.getMembers()) {
77              setMember(sheet, line, entity, member);
78            }
79            repo.put(mapping, line, entity);
80          }
81        }
82      } catch (IOException e) {
83        throw new IllegalArgumentException("Arquivo excel não encontrado.", e);
84      } catch (ClassNotFoundException | IllegalAccessException | InstantiationException e) {
85        throw new IllegalArgumentException("Erro ao instanciar a classe " + klazz.getName(), e);
86      }
87    }
88  
89    private final void setMember(ExcelSheet sheet, int line, Object entity, Member member) {
90  
91      try {
92        if (member.isMapped()) {
93          if (member.isReferenceBased()) {
94            sheet.read(line, column(sheet, member), ConverterFactory.converter(member), value -> repo
95                .set(entity, member, value, this.separator, this.mappings.getMappings()));
96          } else {
97            repo.set(entity, member, repo.get(member.getConverter(), line), this.separator,
98                this.mappings.getMappings());
99          }
100       } else {
101         sheet.read(line, column(sheet, member), value -> value,
102             value -> repo.set(member, line, value));
103       }
104     } catch (IllegalArgumentException e) {
105       LOG.debug("A coluna referente à " + member.getProperty() + " não foi encontrada.");
106     } catch (NullPointerException e) {
107       LOG.debug("### A coluna referente à " + member.getProperty() + " não foi encontrada. ###");
108     }
109   }
110 
111   private final int column(ExcelSheet sheet, Member member) {
112     try {
113       return member.isTitleBased()
114           ? sheet.getColumn(cell -> CellType.STRING.equals(cell.getCellTypeEnum())
115               && cell.getStringCellValue().equalsIgnoreCase(member.getTitle()))
116           : convertColStringToIndex(member.getColumn());
117     } catch (Exception e) {
118       throw new IllegalArgumentException("Coluna "
119           + (member.isTitleBased() ? member.getTitle() : member.getColumn()) + " não encontrada.",
120           e);
121     }
122   }
123 
124   private final SortedSet<Integer> getLines(ExcelSheet sheet) {
125     SortedSet<Integer> rows =
126         sheet.getRows(row -> row.getFirstCellNum() >= 0 && rowFilter.test(row));
127     return rows.isEmpty() ? rows : skipTitle ? rows.tailSet(rows.first() + 1) : rows;
128   }
129 
130   @SuppressWarnings("unchecked")
131   public final <T> Map<Integer, T> get(Class<T> klazz) {
132     return (Map<Integer, T>) repo.get(klazz);
133   }
134 
135   public void addBeanFilter(Predicate<Object> predicate) {
136     repo.addFilter(predicate);
137   }
138 
139 }