Question

I'm using smooks library to parse csv files fast and easy, mapping them programmatically to POJOs. But I have troubles handling empty fields on POJO's Double attributes. For example, the java object has:

public class MulticashHeader {

        // ...
    private Double c06;
    private static Double c07;
    private Double c08;
    private Double c09;
    private String c10;
    // ...
    public Double getC06_SaldoInicial() {
        return c06_SaldoInicial;
    }
    /**
     * @param c06_SaldoInicial the c06_SaldoInicial to set
     */
    public void setC06_SaldoInicial(Double c06_SaldoInicial) {
        if (c06_SaldoInicial != null)
            this.c06_SaldoInicial = c06_SaldoInicial;
    }
    public void setC06_SaldoInicial(String c06_SaldoInicial) {
        if (c06_SaldoInicial != null && !"".equals(c06_SaldoInicial.trim()) ) {
            this.c06_SaldoInicial = new Double(c06_SaldoInicial.trim());
        } else {
            this.c06_SaldoInicial = Double.valueOf("0");
        }
    }
    /**
     * @return the c07_TotalDebitos
     */
    public Double getC07_TotalDebitos() {
        return c07_TotalDebitos;
    }
    /**
     * @param c07_TotalDebitos the c07_TotalDebitos to set
     */
    public void setC07_TotalDebitos(Double c07_TotalDebitos) {
        MulticashEncabezado.c07_TotalDebitos = c07_TotalDebitos;
    }
    public void setC07_TotalDebitos(String c07_TotalDebitos) {
        if (c07_TotalDebitos != null && !"".equals(c07_TotalDebitos.trim()) ) {
            MulticashEncabezado.c07_TotalDebitos = new Double(c07_TotalDebitos.trim());
        } else {
            MulticashEncabezado.c07_TotalDebitos = Double.valueOf("0");
        }
    }
    /**
     * @return the c08_TotalCreditos
     */
    public Double getC08_TotalCreditos() {
        return c08_TotalCreditos;
    }
    /**
     * @param c08_TotalCreditos the c08_TotalCreditos to set
     */
    public void setC08_TotalCreditos(Double c08_TotalCreditos) {
        if (c08_TotalCreditos != null)
            this.c08_TotalCreditos = c08_TotalCreditos;
    }
    public void setC08_TotalCreditos(String c08_TotalCreditos) {
        if (c08_TotalCreditos != null && !"".equals(c08_TotalCreditos.trim()) ) {
            this.c08_TotalCreditos = new Double( c08_TotalCreditos.trim() );
        } else {
            this.c08_TotalCreditos = Double.valueOf("0");
        }
    }
        // ...
}

And the smooks mapping goes like this:

private static final char CchrSeparator = ';';
// File mapping
private static final String CMulticashHeader = "c01_ClaveBanco,c02_Cuenta,c03_Consecutivo,c04_FechaMovimientos,c05_ClaveMoneda,c06_SaldoInicial,c07_TotalDebitos,"+
        "c08_TotalCreditos,c09_SaldoFinal,c10_TipoCuenta,c11,c12,c13,c14,c15,c16,c17,c18_NumeroMovs";
smooks.setReaderConfig( new CSVReaderConfigurator( CMulticashHeader ).setBinding( new CSVBinding(
                            "balanceList", MulticashHeader.class, CSVBindingType.LIST )).setSeparatorChar(CchrSeparator) );

But when processing a file with empty values for c_06, c_07, c_08 and c_09 (not just zeros but empty), which happen to be Double values, even setting function overloading on POJO's attribute setter does not work and throws

Unable to filter InputStream for target profile [org.milyn.profile.Profile#default_profile].
org.milyn.SmooksException: Unable to filter InputStream for target profile [org.milyn.profile.Profile#default_profile].
        at org.milyn.delivery.dom.SmooksDOMFilter.filter(SmooksDOMFilter.java:294)
        at org.milyn.delivery.dom.SmooksDOMFilter.doFilter(SmooksDOMFilter.java:243)
        at org.milyn.delivery.dom.SmooksDOMFilter.doFilter(SmooksDOMFilter.java:216)
        at org.milyn.Smooks._filter(Smooks.java:516)
        at org.milyn.Smooks.filterSource(Smooks.java:475)
        at com.example.CSVParserServicio.runSmooksTransform(CSVParserServicio.java:98)
        ...
Caused by: org.milyn.javabean.DataDecodeException: Failed to decode binding value '' for property 'c07_TotalDebitos' on bean '9b06d0eb-9231-
4c49-a612-75ace2b5d44c'.
        at org.milyn.javabean.BeanInstancePopulator.decodeDataString(BeanInstancePopulator.java:581)
        at org.milyn.javabean.BeanInstancePopulator.decodeAndSetPropertyValue(BeanInstancePopulator.java:482)
        at org.milyn.javabean.BeanInstancePopulator.bindDomDataValue(BeanInstancePopulator.java:384)
        at org.milyn.javabean.BeanInstancePopulator.visitAfter(BeanInstancePopulator.java:319)
        at org.milyn.delivery.dom.SmooksDOMFilter$ElementProcessor.processMapping(SmooksDOMFilter.java:778)
        at org.milyn.delivery.dom.SmooksDOMFilter$ElementProcessor.process(SmooksDOMFilter.java:717)
        at org.milyn.delivery.dom.SmooksDOMFilter$ElementProcessor.access$000(SmooksDOMFilter.java:666)
        at org.milyn.delivery.dom.SmooksDOMFilter.filter(SmooksDOMFilter.java:385)
        at org.milyn.delivery.dom.SmooksDOMFilter.filter(SmooksDOMFilter.java:317)
        at org.milyn.delivery.dom.SmooksDOMFilter.filter(SmooksDOMFilter.java:292)
        ... 27 more
Caused by: org.milyn.javabean.DataDecodeException: Failed to decode Double value ''.
        at org.milyn.javabean.decoders.DoubleDecoder.decode(DoubleDecoder.java:34)
        at org.milyn.javabean.BeanInstancePopulator.decodeDataString(BeanInstancePopulator.java:579)
        ... 36 more
Caused by: java.lang.NumberFormatException: empty String
        at sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:992)
        at java.lang.Double.parseDouble(Double.java:510)
        at org.milyn.javabean.decoders.DoubleDecoder.decode(DoubleDecoder.java:32)
        ... 37 more

Does anoyone how to avoid this trap keeping the programmatic approach?

----------------EDIT----------------: I'm testing this in the smooks example fro csv-to-java, using a config xml as Tom says. I have this and the error replicates:

<?xml version="1.0"?>
<smooks-resource-list xmlns="http://www.milyn.org/xsd/smooks-1.1.xsd"
                      xmlns:csv1="http://www.milyn.org/xsd/smooks/csv-1.3.xsd">

    <csv1:reader fields="firstName,lastName,gender,age,country" separator=";">
        <csv1:listBinding beanId="customerList" class="example.Customer"/>
    </csv1:reader>

</smooks-resource-list>

The file is

charles;moulliard;Male;43;belgium
maxence;dewil;Male;;belgium
eleonor;moulliard;Female;12;belgium

(note the empty age). And the java main class is

private static String messageIn = readInputMessage();

Smooks smooks = new Smooks("/route/to/smooks-config.xml");

        try {
            ExecutionContext executionContext = smooks.createExecutionContext();
            JavaResult result = new JavaResult();
            smooks.filterSource(executionContext, new StringSource(messageIn), result);
            return (List) result.getBean("customerList");
        } finally {
            smooks.close();
        }
        ...

I found out that it's Tom's example (!!!), so I ask: how to map csv fields to POJO attributes using <jb:bean>?

---------------- EDIT2 ----------------: I tried something I found in a codehaus' JIRA thread and I got the following config file:

<?xml version="1.0"?>
<smooks-resource-list xmlns="http://www.milyn.org/xsd/smooks-1.1.xsd"
                      xmlns:csv1="http://www.milyn.org/xsd/smooks/csv-1.3.xsd"
                      xmlns:jb="http://www.milyn.org/xsd/smooks/javabean-1.1.xsd">

    <csv1:reader fields="firstName,lastName,gender,age,country" separator=";" />

    <jb:bindings beanId="customer" class="example.Customer" createOnElement="csv-record">
        <jb:value property="firstName" data="csv-record/firstName" />
        <jb:value property="lastName" data="csv-record/lastName" />
        <jb:value property="gender" data="csv-record/gender" />
        <jb:value property="age" data="csv-record/age" decoder="Integer" default="0"  />
        <jb:value property="country" data="csv-record/country" />
    </jb:bindings>

    <jb:bindings beanId="customerList" class="java.util.ArrayList" createOnElement="csv-set">
        <jb:wiring beanIdRef="customer" />
    </jb:bindings>

</smooks-resource-list>

It works using the CSV with the empty Integer (age) shown before BUT it fails when I update javabean xsd above 1.1. Throws the error

Exception in thread "main" org.xml.sax.SAXParseException: cvc-complex-type.2.4.a: Invalid content was found starting with element 'jb:bindings'. One of '{"http://www.milyn.org/xsd/smooks-1.1.xsd":abstract-reader, "http://www.milyn.org/xsd/smooks-1.1.xsd":abstract-resource-config}' is expected

¿Did I miss something?

Was it helpful?

Solution

You are using the CSV shorthand binding mechanism there, which doesn't allow you to specify defaults. I think your options will be...

  1. Modify the CSVBinding code to meet your needs.
  2. Use one of the more verbose config mechansism i.e. the xml <jb:bean> configs or the programmatic config. Either of these will let you specify a default value.
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top