需要将多个columNames映射到Univocity中的单个字段

时间:2016-04-15 12:59:51

标签: java csv annotations

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;
    }



}

现在我需要映射一个字段,例如someOtherId具有多个标题名称(例如:" dogId"," catId"," cowId"等)来自不同的csv文件。因此,假设文件 1.csv ,名为dogId的标题列应映射到POJO字段someOtherId,而在文件 2.csv 标题{{} 1}}应该映射到同一个字段,即catId。可能吗?怎么样?

1 个答案:

答案 0 :(得分:2)

如果someOtherId值的列始终位于同一位置,无论您使用的是哪个文件,都可以轻松解析此问题。

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;

    ...
}

如果每个输入文件中的列位置不同,您可以实现自己的行处理器。我创建了以下可能适合您的实现。它实质上将可能的标头映射到索引。这些索引应该与您的类中注释的索引匹配。

我打破细节,帮助你理解我的所作所为。

首先为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;

围绕现有的BeanProcessor实现创建一个包装器:

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();
    }
}

此自定义行处理器的预期用法:

//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();

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);
    }

我在本地对此进行了测试,无论头部位于何处,都会按预期解析以下输入:

输入1

UniqueCode,T,name,dogId
1,99,2,3

制作

MyPOJO{code='1', name='2', someOtherId='3'}

输入2

cowId,Z,UniqueCode,T,name
4,99,5,99,6

制作

MyPOJO{code='5', name='6', someOtherId='4'}

希望这有帮助。