Java到CSV文件,SuperCSV Dozer:如何避免嵌套对象的循环 [英] Java to CSV file, SuperCSV Dozer: How to avoid looping for a nested object
问题描述
我有以下类。
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屋!