write libreria commons java csv annotations

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.