Java到CSV文件,SuperCSV Dozer:如何避免嵌套对象的循环 [英] Java to CSV file, SuperCSV Dozer: How to avoid looping for a nested object

查看:1255
本文介绍了Java到CSV文件,SuperCSV Dozer:如何避免嵌套对象的循环的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下类。

SurveyResponse.java

import java.util.List;

public class SurveyResponse {

private int age;

private Boolean consentGiven;

private List<Answer> answers;

public SurveyResponse() {
}

public SurveyResponse(final int age, final Boolean consentGiven, final List<Answer>   
answers) {
    this.age = age;
    this.consentGiven = consentGiven;
    this.answers = answers;
}

public int getAge() {
    return age;
}

public List<Answer> getAnswers() {
    return answers;
}

public Boolean getConsentGiven() {
    return consentGiven;
}

public void setAge(final int age) {
    this.age = age;
}

public void setAnswers(final List<Answer> answers) {
    this.answers = answers;
}

public void setConsentGiven(final Boolean consentGiven) {
    this.consentGiven = consentGiven;
}

@Override
public String toString() {
    return String.format("SurveyResponse [age=%s, consentGiven=%s, answers=%s]", age,
        consentGiven, answers);
}

}

Answer.java

public class Answer {
private Integer questionNo;

private String answer;

public Answer() {
}

public Answer(final Integer questionNo, final String answer) {
    this.questionNo = questionNo;
    this.answer = answer;
}

public String getAnswer() {
    return answer;
}

public Integer getQuestionNo() {
    return questionNo;
}

public void setAnswer(final String answer) {
    this.answer = answer;
}

public void setQuestionNo(final Integer questionNo) {
    this.questionNo = questionNo;
}

@Override
public String toString() {
    return String.format("Answer [questionNo=%s, answer=%s]", questionNo, answer);
}

}

/ strong>类与循环工作正常如下 -

and my Main class with the looping which works fine as below -

import java.io.FileWriter;
import java.util.Arrays;
import java.util.List;

import org.supercsv.cellprocessor.FmtBool;
import org.supercsv.cellprocessor.Optional;
import org.supercsv.cellprocessor.Token;
import org.supercsv.cellprocessor.constraint.NotNull;
import org.supercsv.cellprocessor.ift.CellProcessor;
import org.supercsv.io.dozer.CsvDozerBeanWriter;
import org.supercsv.io.dozer.ICsvDozerBeanWriter;
import org.supercsv.prefs.CsvPreference;


public class Main {

 private static final String[] FIELD_MAPPING = new String[] { "age", // simple field  
 mapping
                                                                    // (like  
 CsvBeanReader)
    "consentGiven", // as above
    "answers[0].questionNo", // indexed (first element) + deep mapping
    "answers[0].answer", "answers[1].questionNo", // indexed (second element) + deep   
mapping
    "answers[1].answer", "answers[2].questionNo", "answers[2].answer" };

/**
 * @param args
 * @throws Exception
 */
public static void main(final String[] args) throws Exception {
    writeWithDozerCsvBeanWriter();

}

private static void writeWithDozerCsvBeanWriter() throws Exception {

    final CellProcessor[] processors = new CellProcessor[] { new Token(0, null), // age
        new FmtBool("Y", "N"), // consent
        new NotNull(), // questionNo 1
        new Optional(), // answer 1
        new NotNull(), // questionNo 2
        new Optional(), // answer 2
        new NotNull(), // questionNo 3
        new Optional() }; // answer 4

    // create the survey responses to write
    final SurveyResponse response1 =
        new SurveyResponse(18, true, Arrays.asList(new Answer(1, "Twelve"), new 
Answer(2,
                "Albert Einstein"), new Answer(3, "Big Bang Theory")));
    final SurveyResponse response2 =
        new SurveyResponse(0, true, Arrays.asList(new Answer(1, "Thirteen"), new 
Answer(2,
                "Nikola Tesla"), new Answer(3, "Stargate")));
    final SurveyResponse response3 =
        new SurveyResponse(42, false, Arrays.asList(new Answer(1, null), new Answer(2,
                "Carl Sagan"), new Answer(3, "Star Wars")));
    final List<SurveyResponse> surveyResponses =
        Arrays.asList(response1, response2, response3);

    ICsvDozerBeanWriter beanWriter = null;
    try {
        beanWriter =
            new CsvDozerBeanWriter(new   
 FileWriter("C:\\Users\\Desktop\\Test.csv"),
                    CsvPreference.STANDARD_PREFERENCE);

        // configure the mapping from the fields to the CSV columns
        beanWriter.configureBeanMapping(SurveyResponse.class, FIELD_MAPPING);

        // write the header
        beanWriter.writeHeader("age", "consentGiven", "questionNo1", "answer1",
            "questionNo2", "answer2", "questionNo3", "answer3");

        // write the beans
        for (final SurveyResponse surveyResponse : surveyResponses) {
            beanWriter.write(surveyResponse, processors);
        }

    } finally {
        if (beanWriter != null) {
            beanWriter.close();
        }
    }
}

}

我想避免字段映射处理器数组中的循环,因为在我们的应用程序中,我们有大约100到1000个答案。所以我写下面这是不工作。

I want to avoid the looping in the field mapping and processors arrays because..in our app, we have around 100 to 1000 answers. so I wrote the below which is not working. Could someone shed some light as why the below is not working?

Main2.java

import java.io.FileWriter;
import java.util.Arrays;
import java.util.List;

import org.supercsv.cellprocessor.FmtBool;
import org.supercsv.cellprocessor.Optional;
import org.supercsv.cellprocessor.Token;
import org.supercsv.cellprocessor.constraint.NotNull;
import org.supercsv.cellprocessor.ift.CellProcessor;
import org.supercsv.io.dozer.CsvDozerBeanWriter;
import org.supercsv.io.dozer.ICsvDozerBeanWriter;
import org.supercsv.prefs.CsvPreference;

public class Main2 {

private static final String[] FIELD_MAPPING = new String[] { "age", "consentGiven",
    "answers.questionNo", "answers.answer" };

/**
 * @param args
 * @throws Exception
 */
public static void main(final String[] args) throws Exception {
    writeWithDozerCsvBeanWriter();

}

private static void writeWithDozerCsvBeanWriter() throws Exception {

    final CellProcessor[] processors = new CellProcessor[] { new Token(0, null), // age
        new FmtBool("Y", "N"), // consent
        new NotNull(), // questionNo
        new Optional() // answer
        };

    // create the survey responses to write
    final SurveyResponse response1 =
        new SurveyResponse(18, true, Arrays.asList(new Answer(1, "Twelve"), new 
       Answer(2,
                "Albert Einstein"), new Answer(3, "Big Bang Theory")));
    final SurveyResponse response2 =
        new SurveyResponse(0, true, Arrays.asList(new Answer(1, "Thirteen"), new 
       Answer(2,
                "Nikola Tesla"), new Answer(3, "Stargate")));
    final SurveyResponse response3 =
        new SurveyResponse(42, false, Arrays.asList(new Answer(1, null), new Answer(2,
                "Carl Sagan"), new Answer(3, "Star Wars")));
    final List<SurveyResponse> surveyResponses =
        Arrays.asList(response1, response2, response3);

    ICsvDozerBeanWriter beanWriter = null;
    try {
        beanWriter =
            new CsvDozerBeanWriter(new  
 FileWriter("C:\\Users\\Desktop\\Test.csv"),
                    CsvPreference.STANDARD_PREFERENCE);

        // configure the mapping from the fields to the CSV columns
        beanWriter.configureBeanMapping(SurveyResponse.class, FIELD_MAPPING);

        // write the header
        beanWriter.writeHeader("age", "consentGiven", "questionNo1", "answer1");

        // write the beans
        for (final SurveyResponse surveyResponse : surveyResponses) {
            beanWriter.write(surveyResponse, processors);
        }

    } finally {
        if (beanWriter != null) {
            beanWriter.close();
        }
    }
}

}

这是错误

6 [main] INFO org.dozer.config.GlobalSettings - Trying to find Dozer configuration   
file: dozer.properties

14 [main] WARN org.dozer.config.GlobalSettings - Dozer configuration file not found: 
dozer.properties.  Using defaults for all Dozer global properties.
 15 [main] INFO org.dozer.DozerInitializer - Initializing Dozer. Version: 5.4.0, Thread       
 Name: main

64 [main] INFO org.dozer.jmx.JMXPlatformImpl - Dozer JMX MBean 
[org.dozer.jmx:type=DozerStatisticsController] auto registered with the Platform MBean 
Server

65 [main] INFO org.dozer.jmx.JMXPlatformImpl - Dozer JMX MBean 
[org.dozer.jmx:type=DozerAdminController] auto registered with the Platform MBean 
Server

68 [main] INFO org.dozer.DozerBeanMapper - Initializing a new instance of dozer bean 
mapper.

 156 [main] ERROR org.dozer.MappingProcessor - Field mapping error -->

MapId: null
Type: null
Source parent class: SurveyResponse
Source field name: answers.questionNo
Source field type: null
 Source field value: null
Dest parent class: org.supercsv.io.dozer.CsvDozerBeanData
Dest field name: columns
Dest field type: java.util.List
java.lang.IllegalArgumentException: object is not an instance of declaring class
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at  
 sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.dozer.util.ReflectionUtils.invoke(ReflectionUtils.java:323)
at 
  org.dozer.propertydescriptor.GetterSetterPropertyDescriptor.
  getDeepSrcFieldValue(GetterSetterPropertyDescriptor.java:122)
at org.dozer.propertydescriptor.GetterSetterPropertyDescriptor.
 getPropertyValue(GetterSetterPropertyDescriptor.java:75)
at org.dozer.fieldmap.FieldMap.getSrcFieldValue(FieldMap.java:84)
at org.dozer.MappingProcessor.mapField(MappingProcessor.java:275)
at org.dozer.MappingProcessor.map(MappingProcessor.java:248)
at org.dozer.MappingProcessor.map(MappingProcessor.java:197)
at org.dozer.MappingProcessor.map(MappingProcessor.java:187)
at org.dozer.MappingProcessor.map(MappingProcessor.java:133)
at org.dozer.MappingProcessor.map(MappingProcessor.java:128)
at org.dozer.DozerBeanMapper.map(DozerBeanMapper.java:127)
at org.supercsv.io.dozer.CsvDozerBeanWriter.write(CsvDozerBeanWriter.java:132)
at MainAvoidIndexing.writeWithDozerCsvBeanWriter(MainAvoidIndexing.java:68)
at MainAvoidIndexing.main(MainAvoidIndexing.java:29)

     Exception in thread "main" java.lang.IllegalArgumentException: object is not an 
     instance of declaring class
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at 
        sun.reflect.DelegatingMethodAccessorImpl.
   invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.dozer.util.ReflectionUtils.invoke(ReflectionUtils.java:323)
at org.dozer.propertydescriptor.GetterSetterPropertyDescriptor.
   getDeepSrcFieldValue(GetterSetterPropertyDescriptor.java:122)
at  
  org.dozer.propertydescriptor.GetterSetterPropertyDescriptor.
  getPropertyValue(GetterSetterPr  
    opertyDescriptor.java:75)
at org.dozer.fieldmap.FieldMap.getSrcFieldValue(FieldMap.java:84)
at org.dozer.MappingProcessor.mapField(MappingProcessor.java:275)
at org.dozer.MappingProcessor.map(MappingProcessor.java:248)
at org.dozer.MappingProcessor.map(MappingProcessor.java:197)
at org.dozer.MappingProcessor.map(MappingProcessor.java:187)
at org.dozer.MappingProcessor.map(MappingProcessor.java:133)
at org.dozer.MappingProcessor.map(MappingProcessor.java:128)
at org.dozer.DozerBeanMapper.map(DozerBeanMapper.java:127)
at org.supercsv.io.dozer.CsvDozerBeanWriter.write(CsvDozerBeanWriter.java:132)
at MainAvoidIndexing.writeWithDozerCsvBeanWriter(MainAvoidIndexing.java:68)
at MainAvoidIndexing.main(MainAvoidIndexing.java:29)


推荐答案

中的回答字段为 List ,因此您必须使用索引映射来配置 CsvDozerBeanWriter 。索引映射实际上并不循环 - 这只是Dozer知道要填充List的哪个元素。这是非常重要的,如果你忽略一个列 - 它实际上会插入一个 null 元素。

The answers field in SurveyResponse is a List, so you have to use indexed mapping to configure CsvDozerBeanWriter. Indexed mapping is not actually looping - it's just how Dozer knows which element of a List to populate. This is extremely important if you were to ignore a column - it would actually insert a null element for that column.

如果你不使用索引映射(只需使用answers),那么你需要配置一个单元处理器,可以采用

If you don't use indexed mapping (and just use "answers") then you'd need to configure a cell processor that can take a List<Answer> and convert it to something that can be used as CSV.

动态配置字段映射

(不是您要求的结果,但我会留作将来参考)

(Not what you were asking as it turns out, but I'll leave for future reference)

这不意味着您必须使用静态String数组配置字段映射。您可以使用简单的for循环动态填充数组。例如,

That doesn't mean you have to configure the field mapping with a static String array. You can populate the array dynamically using a simple for-loop. For example,

    String[] fieldMapping = new String[10];
    fieldMapping[0] = "age";
    fieldMapping[1] = "consentGiven";
    int answerStartIndex = 2;
    int answerEndIndex = 8;
    for (int i = answerStartIndex; i <= answerEndIndex; i++){
        fieldMapping[i] = String.format("answers[%s].questionNo", 
            i - answerStartIndex);
    }
    fieldMapping[9] = "age";

这会给你一个fieldMapping:

Which will give you a fieldMapping of:

[age, consentGiven, answers[0].questionNo, answers[1].questionNo,
 answers[2].questionNo, answers[3].questionNo, answers[4].questionNo,
 answers[5].questionNo, answers[6].questionNo, age]

这篇关于Java到CSV文件,SuperCSV Dozer:如何避免嵌套对象的循环的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆