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 }