SuperCSV, Dozer: запись в CSV-файл. Для объекта со списком в несколько строк

У меня есть класс А, который имеет несколько свойств:

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
}

Я пытаюсь записать это в CSV-файл, используя Supercsv и Dozer.

CSV должен иметь то же количество строк, что и элементы в списке bList из класса A. И должен иметь четыре столбца col1, col2 (которые будут общими для всех строк) и b1, b2 из списка класса B в классе A,

В настоящее время в файле отображения у меня есть:

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

Но это только отображает данные в один ряд. Что было бы лучшим способом сделать это, не отображая его в более плоский класс. В сопоставлениях можно отобразить его из класса A в список CsvDozerBeanData? Будет ли это работать?

Благодарю.

1 ответ

Решение

Можете ли вы добавить отношения из B вернуться к A? Затем вы можете перебрать каждый список потомков с помощью следующего сопоставления bean-компонентов:

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

Вот пример того, как вы могли бы использовать это. Обратите внимание на вложенные циклы для итерации по каждому B внутри каждого 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;
    }

}

Это печатает:

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

Обновление для адреса комментариев

Если вы не можете добавить связь, тогда вы можете просто использовать CellProcessors (и вам даже не нужно использовать Dozer). Я только что создал 3 простых клеточных процессора:

  • ElementAt - просто хватает элемент по нужному индексу
  • GetB1 - получает b1 поле B
  • GetB2 - получает b2 поле B

И вот они в действии:

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

}

Выход:

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

ps Я бы не советовал указывать ваш собственный XML-кодировку бульдозера, если вам действительно не нужно (и в этом случае это не кажется необходимым).

Другие вопросы по тегам