package com.opencsv.bean;
import com.opencsv.CSVReader;
import com.opencsv.exceptions.CsvRequiredFieldEmptyException;
import org.apache.commons.collections4.ListValuedMap;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.text.similarity.LevenshteinDistance;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class FuzzyMappingStrategy<T> extends HeaderColumnNameMappingStrategy<T> {
public FuzzyMappingStrategy() {
}
@Override
protected void loadUnadornedFieldMap(ListValuedMap<Class<?>, Field> fields) {}
@Override
public void (CSVReader reader) throws IOException, CsvRequiredFieldEmptyException {
super.captureHeader(reader);
final Set<String> unusedHeaders = Stream.of(headerIndex.getHeaderIndex())
.filter(Objects::nonNull)
.filter(k -> fieldMap.get(k.toUpperCase()) == null)
.collect(Collectors.toSet());
final ListValuedMap<Class<?>, Field> unusedFields = partitionFields().get(Boolean.FALSE);
LevenshteinDistance levenshtein = LevenshteinDistance.getDefaultInstance();
List<FuzzyComparison> comparisons = new LinkedList<>();
unusedHeaders.forEach(h -> {
unusedFields.entries().forEach(f -> {
comparisons.add(new FuzzyComparison(
levenshtein.apply(h.toUpperCase(), f.getValue().getName().toUpperCase()),
h, f.getKey(), f.getValue()));
});
});
comparisons.sort(null);
while (!comparisons.isEmpty()) {
FuzzyComparison fc = comparisons.get(0);
CsvConverter converter = determineConverter(
fc.field, fc.field.getType(), null, null, null);
fieldMap.put(fc.header.toUpperCase(), new BeanFieldSingleValue<>(
fc.type, fc.field, false, errorLocale, converter, null,
null));
comparisons.removeIf(e ->
StringUtils.equals(e.header, fc.header)
|| Objects.equals(e.field, fc.field));
}
}
private static class FuzzyComparison implements Comparable<FuzzyComparison> {
final Integer distance;
final String ;
final Class<?> type;
final Field field;
FuzzyComparison(Integer distance, String header, Class<?> type, Field field) {
this.distance = distance;
this.header = header;
this.type = type;
this.field = field;
}
@Override
public int compareTo(FuzzyComparison o) {
return Integer.compare(distance, o.distance);
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof FuzzyComparison)) {
return false;
}
FuzzyComparison that = (FuzzyComparison) o;
return Objects.equals(distance, that.distance);
}
@Override
public int hashCode() {
return Objects.hash(distance);
}
}
}