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 }