Чтение CSV с помощью Smooks - PullRequest
1 голос
/ 27 января 2012

Использование Smooks (1.4) для чтения CSV и преобразования их в Person POJO.

CSV состоит из записей, разделенных запятыми, в каждой строке, и каждая запись имеет разделенные каналом поля:

Smith | Джон | 45 | мужчина | Johnny | JSmith | JSmizzle

Smith | Jane | 43 | женщина | Джейни

и т.д.. Таким образом, каждая строка представляет другого человека для создания. Во-первых, POJO:

public class Person
{
    private String lastName;
    private String firstName;
    private int age;
    private boolean isMale;
    private List<String> aliases;
}

Моя проблема с List псевдонимами. Вот важные части моей конфигурации XML:

<reader class="org.milyn.csv.CSVReader">
    <param name="fields">lastName,fristName,age,gender,aliases</param>
    <param name="separator">&#124;</param>
    <param name="strict">false</param>
</reader>

<core:filterSettings type="SAX"/>

<jb:bean beanId="person" class="net.me.myproject.app.Person" createOnElement="csv-set/csv-record/">
    <jb:value property="lastName" data="csv-set/csv-record/lastName"/>
    <jb:value property="firstName" data="csv-set/csv-record/firstName"/>
    <jb:value property="isMale" data="csv-set/csv-record/gender"/>
    <jb:value property="age" data="csv-set/csv-record/age"/>
    <jb:wiring property="aliases" beanRefId="aliases"/>
</jb:bean>

<jb:bean beanId="aliases" class="java.util.ArrayList" createOnElement="???">
    <jb:wiring beanRefId="alias"/>
</jb:bean>

<jb:bean beanId="alias" class="java.util.String" createOnElement="???">
    ???
</jb:bean>

Так что я задыхаюсь в правильной настройке createOnElement для aliases ArrayList и каждой alias String. Заранее спасибо всем, кто может подтолкнуть меня в правильном направлении!

Ответы [ 2 ]

4 голосов
/ 31 января 2012

Прежде всего, ваш CSVReader атрибут " fields " будет мешаниной со всеми полями, содержащимися в CSV-файле, независимо от того, к какому POJO, списку или типу они относятся обратно , Таким образом, некоторые поля будут Person свойствами, а некоторые поля будут псевдонимами, которые на самом деле принадлежат отдельному компоненту aliases, который имеет тип java.util.ArrayList<String>.

Ваша задача - рассказать Smooks, как сопоставить каждое поле с соответствующим компонентом / списком / компонентом / типом / и т. Д., Что означает указание ему, что делать, когда оно встречается с каждым полем.

Smooks не поддерживает такого рода «динамическое» связывание полей, где вы можете иметь 0+ CSV-полей, сопоставляемых с ArrayList, который сам по себе будет либо пустым, либо заполненным. Вы должны перечислить каждое поле в CSVReader, что означает наличие ArrayList псевдонимов с фиксированным размером.

Значит, вы должны определить максимальное количество псевдонимов, которые могут быть связаны с каждым Person, и учесть их в списке полей:

<reader class="org.milyn.csv.CSVReader">
    <param name="fields">lastName,fristName,age,gender,alias1,alias2,alias3</param>
    <param name="separator">&#124;</param>
    <param name="strict">false</param>
</reader>

Это означает, что каждая запись CSV должна иметь достоверное значение для ваших трех псевдонимов. Я бы порекомендовал использовать значение «ignore», такое как «%%%IGNORE%%%», чтобы логика вашего приложения не могла удалить элементы списка, содержащие это значение (после того, как Smooks завершил выполнение преобразования).

Возможно, вы также захотите проверить встроенный токен Smooks $ignore$, который может уже сделать это или что-то в этом роде.

Последняя часть, перед тем как мы сможем связать все вместе в полном примере кода, - это просто принять печальный факт, что Smooks либо не (или не публично документирует) какую-либо возможность использовать List<String> в этом примере. Вы должны преобразовать ваш POJO, чтобы использовать либо List<StringBuffer>, либо List<StringBuilder> для псевдонимов, чтобы мы могли использовать атрибут Smooks-JavaBean value, называемый setterMethod.

Всего сейчас:

<jb:bean beanId="aliases" class="java.util.ArrayList" createOnElement="csv-set/csv-record">
    <jb:wiring beanRefId="alias1"/>
    <jb:wiring beanRefId="alias2"/>
    <jb:wiring beanRefId="alias3"/>
</jb:bean>

<jb:bean beanId="alias1" class="java.util.StringBuffer" createOnElement="csv-set/csv-record/alias1">
    <jb:value data="csv-set/csv-record/alias1" setterMethod="append" />
</jb:bean>

<jb:bean beanId="alias2" class="java.util.StringBuffer" createOnElement="csv-set/csv-record/alias2">
    <jb:value data="csv-set/csv-record/alias2" setterMethod="append" />
</jb:bean>

<jb:bean beanId="alias3" class="java.util.StringBuffer" createOnElement="csv-set/csv-record/alias3">
    <jb:value data="csv-set/csv-record/alias3" setterMethod="append" />
</jb:bean>

Таким образом, каждый раз, когда мы начинаем синтаксический анализ нового csv-record, мы создаем как bean-компонент person (как прекрасно показывает ваш пример исходного кода), так и bean-компонент aliases. Затем в ходе анализа этой записи мы найдем Person свойств, а также от alias1 до alias3. Поля aliasN сохраняются в bean-компоненте aliases, а другое поле Person сохраняется в bean-компоненте person. Наконец, Smooks знает, как «соединить» бины person и aliases вместе, чтобы создать объект Java Person.

0 голосов
/ 02 февраля 2012

Хороший ответ, Адам.

Что касается вопроса о Списке, который вы подняли там в конце ... Я не пробовал его, но хотел бы, чтобы следующее работало ...

<jb:bean beanId="aliases" class="java.util.ArrayList" createOnElement="csv-set/csv-record">
    <jb:value data="csv-set/csv-record/alias1" decoder="String"/>
    <jb:value data="csv-set/csv-record/alias2" decoder="String"/>
    <jb:value data="csv-set/csv-record/alias3" decoder="String"/>
</jb:bean>
...