java - libreria - Necesidad de asignar mĂșltiples columNames a un solo campo en Univocity
opencsv maven (1)
class MyPOJO implements Serializable
{
private static final long serialVersionUID = 1L;
@Parsed(field = "UniqueCode")
private String code;
@Parsed(field = "Name")
private String name;
@Parsed(field = "dogId")
private String someOtherId;
//------Getters and Setters-------
public String getCode()
{
return code;
}
public void setCode(String code)
{
this.code = code;
}
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
public String getSomeOtherId()
{
return someOtherId;
}
public void setSomeOtherId(String someOtherId)
{
this.someOtherId = someOtherId;
}
}
Ahora necesito asignar un solo campo, por ejemplo, algún otro Id con múltiples nombres de encabezado (por ejemplo: "ID de perro", "ID de catId", "ID de vaca", etc.) procedentes de diferentes archivos CSV. Así que supongamos en los archivos 1.csv que la columna del encabezado llamada dogId
debe correlacionarse con el campo POJO en someOtherId
mientras que en el archivo 2.csv el encabezado catId
debe catId
al mismo campo, es decir, someOtherId
. ¿Es posible? ¿Cómo?
Puede analizar esto fácilmente si las columnas con valores para someOtherId
están siempre en la misma ubicación, sin importar qué archivos está usando.
class MyPOJO implements Serializable
{
private static final long serialVersionUID = 1L;
@Parsed(field = "UniqueCode")
private String code;
@Parsed(field = "Name")
private String name;
@Parsed(index = 2) //anything goes here, "catId", "cowId", etc
private String someOtherId;
...
}
Si la posición de la columna varía en cada archivo de entrada, puede implementar su propio procesador de fila. Creé la siguiente implementación que probablemente funcione para usted. En esencia, asigna posibles encabezados a un índice. Estos índices deben coincidir con los índices anotados en su clase.
Desglose los detalles para ayudarte a entender lo que hice.
Primero asigne un índice a cada campo de su POJO:
@Parsed(index = 0)
private String code;
@Parsed(index = 1)
private String name;
@Parsed(index = 2) //cowId, dogId or catId or anything else
private String someOtherId;
Cree un envoltorio alrededor de la implementación de BeanProcessor existente:
public class MyBeanProcessor<T> extends AbstractRowProcessor{
//here''s the wrapped bean processor.
private final BeanListProcessor<T> processor;
//we need a LinkedHashMap here to keep the the correct ordering.
private final LinkedHashMap<String, Integer> headersToCapture;
public MyBeanProcessor(Class<T> beanType, LinkedHashMap<String, Integer> headersToCapture){
processor = new BeanListProcessor<T>(beanType);
this.headersToCapture = headersToCapture;
}
// work with parsed headers to find out what is in the input
@Override
public void rowProcessed(String[] inputRow, ParsingContext context) {
//... more details later
}
@Override
public void processEnded(ParsingContext context) {
processor.processEnded(context);
}
public List<T> getBeans(){
return processor.getBeans();
}
}
Uso previsto de este procesador de fila personalizado:
//keys are possible headers, and values are the indexes where each header will be mapped to:
Map<String, Integer> headerPositions = new LinkedHashMap<String, Integer>();
headerPositions.put("UniqueCode", 0);
headerPositions.put("Name", 1);
headerPositions.put("dogId", 2);
headerPositions.put("catId", 2);
headerPositions.put("cowId", 2);
CsvParserSettings settings = new CsvParserSettings();
//we want headers
settings.setHeaderExtractionEnabled(true);
//let''s use the custom row processor:
MyBeanProcessor<MyPOJO> processor = new MyBeanProcessor<MyPOJO>(MyPOJO.class, headerPositions);
settings.setRowProcessor(processor);
CsvParser parser = new CsvParser(settings);
parser.parse(<YOUR_INPUT_HERE>);
List<MyPOJO> myPojos = processor.getBeans();
Implementación del método rowProcessed
:
private int[] headerIndexes = null;
private String[] row = null;
@Override
public void rowProcessed(String[] inputRow, ParsingContext context) {
if(headerIndexes == null){ //initializes the indexes to capture
processor.processStarted(context);
String[] parsedHeaders = context.headers();
LinkedHashSet<Integer> indexes = new LinkedHashSet<Integer>();
for(String headerToCapture : headersToCapture.keySet()){
int headerIndex = ArgumentUtils.indexOf(parsedHeaders, headerToCapture);
if(headerIndex != -1){
indexes.add(headerIndex);
}
}
headerIndexes = ArgumentUtils.toIntArray(indexes);
row = new String[indexes.size()]; //creates a reusable row with the number of columns captured
}
//once the input format is known, we can collect the values from the expected positions:
for(int i = 0; i < headerIndexes.length; i++){
int indexToCapture = headerIndexes[i];
if(indexToCapture < inputRow.length){
row[i] = inputRow[indexToCapture];
} else {
row[i] = null;
}
}
//and submit a row with the values in the correct places to the actual bean processor
processor.rowProcessed(row, context);
}
Probé esto localmente y las siguientes entradas se analizan como se esperaba, sin importar dónde se encuentran los encabezados:
Entrada 1
UniqueCode,T,name,dogId
1,99,2,3
Produce
MyPOJO{code=''1'', name=''2'', someOtherId=''3''}
Entrada 2
cowId,Z,UniqueCode,T,name
4,99,5,99,6
Produce
MyPOJO{code=''5'', name=''6'', someOtherId=''4''}
Espero que esto ayude.