SuperCSV,Dozer:写入csv文件。对于具有列表的对象到多个行 [英] SuperCSV, Dozer: Writing to a csv file. For Object with a list into multiple rows

查看:165
本文介绍了SuperCSV,Dozer:写入csv文件。对于具有列表的对象到多个行的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个A类,它有几个属性:

  class A {

private String col1;
private String col2;
私人名单< B> bList;

// setters和getters
}

B类{
private String b1;
private String b2;
// setters和getters
}

使用supercsv和dozer的csv文件。



csv应该具有与列表中的元素相同的行数bList中的BList。
并且应该有四



目前在映射文件中,我有一个列:

 < mapping type =one-waywildcard =falsemap-null =true> 
< class-a> package.a< / class-a>
< class-b> org.supercsv.io.dozer.CsvDozerBeanData< / class-b>
.....
< / mapping>

但它只将数据映射到一行。什么是更好的方式来做它没有映射到一个平庸的类。
在映射中可以将它从类A映射到CsvDozerBeanData的列表?



感谢。

解决方案

关系从 B 回到 A ?然后,您可以使用以下bean映射遍历每个List子节点:

  new String [] {a.col1 a.col2,b1,b2} 

d使用这个。请注意嵌套循环以遍历每个 A 中的每个 B

  public class DozerTest {

@Test
public final void test()throws IOException {
StringWriter out = new StringWriter );
ICsvDozerBeanWriter writer = new CsvDozerBeanWriter(out,
CsvPreference.STANDARD_PREFERENCE);
writer.configureBeanMapping(B.class,
new String [] {a.col1,a.col2,b1,b2});

for(A a:generateData()){
for(B b:a.getbList()){
writer.write(b);
}
}
writer.flush();
System.out.println(out.toString());
}

private List< A> generateData(){
List< A> data = new ArrayList< A>();

for(int i = 0; i <3; i ++){
A a = new A();
a.setCol1(col1 for a+ i);
a.setCol2(col2 for a+ i);

B firstB = new B();
firstB.setB1(first b1 for a+ i);
firstB.setB2(first b2 for a+ i);
firstB.setA(a);

B secondB = new B();
secondB.setB1(second b1 for a+ i);
secondB.setB2(second b2 for a+ i);
secondB.setA(a);

a.setbList(Arrays.asList(firstB,secondB));
data.add(a);
}

返回数据;
}

}



col1用于a0,col2用于a0,第一个b1用于a0,第一个b2用于a0
col1用于a0,col2用于a0, b1为a0,第二个b2为a0
col1为a1,col2为a1,第一个b1为a1,第一个b2为a1
col1为a1,col2为a1,第二个b1为a1,第二个b2为a1
col1 for a2,col2 for a2,first b1 for a2,first b2 for a2
col1 for a2,col2 for a2,second b1 for a2,second b2 for a2

更新到地址注释



添加关系,然后你可以使用CellProcessors(甚至不需要使用Dozer)。我刚刚创建了3个简单的单元格处理器:




  • ElementAt B

  • GetB2 - 获取 b2 字段 B



in action:

  @Test 
public final void test2()throws IOException {
StringWriter out = new StringWriter();
ICsvDozerBeanWriter writer = new CsvDozerBeanWriter(out,
CsvPreference.STANDARD_PREFERENCE)
writer.configureBeanMapping(A.class,
new String [] {col1,col2,bList,bList});

for(A a:generateData()){
for(int i = 0; i CellProcessor [] processor = new CellProcessor [] {null,null,
new ElementAt(i,new GetB1()),
new ElementAt(i,new GetB2()
writer.write(a,processors);
}
}
writer.flush();
System.out.println(out.toString());
}

类GetB1 extends CellProcessorAdaptor {
public Object execute(Object value,CsvContext context){
validateInputNotNull(value,context);
return((B)value).getB1();
}
}

类GetB2 extends CellProcessorAdaptor {
public Object execute(Object value,CsvContext context){
validateInputNotNull(value,context);
return((B)value).getB2();
}
}

class ElementAt extends CellProcessorAdaptor {

private final int index;

public ElementAt(int index){
this.index = index;
}

public ElementAt(int index,CellProcessor next){
super(next);
this.index = index;
}

public Object execute(Object value,CsvContext context){
validateInputNotNull(value,context);
Object element =((List<?>)value).get(index);
return next.execute(element,context);
}

}

输出:



col1用于a0,col2用于a0,第一个b1用于a0,第一个b2用于a0
col1用于a0,col2用于a0,对于a0,第二个b2为a0
col1为a1,col2为a1,第一个b1为a1,第一个b2为a1
col1为a1,col2为a1,第二个b1为a1,第二个b2为a1
col1 for a2,col2 for a2,first b1 for a2,first b2 for a2
col1 for a2,col2 for a2,second b1 for a2,second b2 for a2

ps我不建议提供自己的打瞌睡地图XML,除非你真的需要(在这种情况下似乎没有必要)。


I have a class A which has few properties:

class A {

private String col1;
private String col2;
private List<B> bList;

// setters and getters
}

Class B {
private String b1;
private String b2;
//setters and getters
}

I am trying to write this into a csv file using supercsv and dozer.

The csv should have the same number of rows as elements in the list bList from class A. And should have four columns col1, col2 (which would be common for all the rows) and b1, b2 from the list of class B in class A.

Currently in the mapping file I have:

<mapping type="one-way" wildcard="false" map-null="true">
                <class-a>package.a</class-a>
                <class-b>org.supercsv.io.dozer.CsvDozerBeanData</class-b>
.....
</mapping>

But it only maps the data into one row. What would be a better way to do it without mapping it into a flatter class. In the mappings can be map it from class A to a list of CsvDozerBeanData? Will that work?

Thanks.

解决方案

Can you add a relationship from B back to A? Then you could iterate over each List of children with the following bean mapping:

new String[] { "a.col1", "a.col2", "b1", "b2" }

Here's an example of how you'd use this. Note the nested loops to iterate over each B inside each A.

public class DozerTest {

    @Test
    public final void test() throws IOException {
        StringWriter out = new StringWriter();
        ICsvDozerBeanWriter writer = new CsvDozerBeanWriter(out, 
                CsvPreference.STANDARD_PREFERENCE);
        writer.configureBeanMapping(B.class, 
                new String[] { "a.col1", "a.col2", "b1", "b2" });

        for (A a : generateData()) {
            for (B b : a.getbList()) {
                writer.write(b);
            }
        }
        writer.flush();
        System.out.println(out.toString());
    }

    private List<A> generateData() {
        List<A> data = new ArrayList<A>();

        for (int i = 0; i < 3; i++) {
            A a = new A();
            a.setCol1("col1 for a" + i);
            a.setCol2("col2 for a" + i);

            B firstB = new B();
            firstB.setB1("first b1 for a" + i);
            firstB.setB2("first b2 for a" + i);
            firstB.setA(a);

            B secondB = new B();
            secondB.setB1("second b1 for a" + i);
            secondB.setB2("second b2 for a" + i);
            secondB.setA(a);

            a.setbList(Arrays.asList(firstB, secondB));
            data.add(a);
        }

        return data;
    }

}

This prints:

col1 for a0,col2 for a0,first b1 for a0,first b2 for a0
col1 for a0,col2 for a0,second b1 for a0,second b2 for a0
col1 for a1,col2 for a1,first b1 for a1,first b2 for a1
col1 for a1,col2 for a1,second b1 for a1,second b2 for a1
col1 for a2,col2 for a2,first b1 for a2,first b2 for a2
col1 for a2,col2 for a2,second b1 for a2,second b2 for a2

Update to address comments

If you can't add a relationship, then you can just use CellProcessors (and you don't even need to use Dozer). I've just created 3 simple cell processors:

  • ElementAt - just grabs the element at the desired index
  • GetB1 - gets the b1 field of a B
  • GetB2 - gets the b2 field of a B

And here they are in action:

@Test
public final void test2() throws IOException {
    StringWriter out = new StringWriter();
    ICsvDozerBeanWriter writer = new CsvDozerBeanWriter(out, 
        CsvPreference.STANDARD_PREFERENCE);
    writer.configureBeanMapping(A.class, 
        new String[] { "col1", "col2", "bList", "bList" });

    for (A a : generateData()) {
        for (int i = 0; i < a.getbList().size(); i++) {
            CellProcessor[] processors = new CellProcessor[] { null, null, 
                new ElementAt(i, new GetB1()),
                new ElementAt(i, new GetB2()) };
            writer.write(a, processors);
        }
    }
    writer.flush();
    System.out.println(out.toString());
}

class GetB1 extends CellProcessorAdaptor {
    public Object execute(Object value, CsvContext context) {
        validateInputNotNull(value, context);
        return ((B) value).getB1();
    }
}

class GetB2 extends CellProcessorAdaptor {
    public Object execute(Object value, CsvContext context) {
        validateInputNotNull(value, context);
        return ((B) value).getB2();
    }
}

class ElementAt extends CellProcessorAdaptor {

    private final int index;

    public ElementAt(int index) {
        this.index = index;
    }

    public ElementAt(int index, CellProcessor next) {
        super(next);
        this.index = index;
    }

    public Object execute(Object value, CsvContext context) {
        validateInputNotNull(value, context);
        Object element = ((List<?>) value).get(index);
        return next.execute(element, context);
    }

}

Output:

col1 for a0,col2 for a0,first b1 for a0,first b2 for a0
col1 for a0,col2 for a0,second b1 for a0,second b2 for a0
col1 for a1,col2 for a1,first b1 for a1,first b2 for a1
col1 for a1,col2 for a1,second b1 for a1,second b2 for a1
col1 for a2,col2 for a2,first b1 for a2,first b2 for a2
col1 for a2,col2 for a2,second b1 for a2,second b2 for a2

p.s. I wouldn't recommend supplying your own dozer mapping XML unless you really have to (and in this case it doesn't seem necessary).

这篇关于SuperCSV,Dozer:写入csv文件。对于具有列表的对象到多个行的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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