segment terminator in BeanIO

1.5k Views Asked by At

I'm interested in the recordTerminator parser property of BeanIO. Does it apply to segments too, like "segmentTerminator"? Namely, I have a stream of fixedlength format, containing of a single record with repeatable segments, and all stream is a single line. Hence, I have set recordTerminator="", but it still gives me

==> Invalid 'state':  Expected minimum 1 occurrences
==> Invalid 'city':  Expected minimum 1 occurrences
==> Invalid 'street':  Invalid field length, expected 35 characters
==> Invalid 'zip':  Expected minimum 1 occurrences

It doesn't complain about fields that precede to repeatable segment, and complaints about the fields in a repeatable segment are out of order defined in mapping.xml, that looks like this:

    <beanio  xmlns="http://www.beanio.org/2012/03" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.beanio.org/2012/03 http://www.beanio.org/2012/03/mapping.xsd">
      <stream name="employeeFile" format="fixedlength">
        <parser>
            <property name="recordTerminator" value="" />
        </parser>  
        <record name="employee" class="example.Employee">
          <field name="firstName" length="35" />
          <field name="lastName" length="35" />
          <field name="title" length="35" />
          <field name="salary" length="35" />
          <segment name="addressList" collection="list" minOccurs="1" maxOccurs="unbounded" class="example.Address">
            <field name="street" length="35" />
            <field name="city" length="35" />
            <field name="state" length="35" />      
            <field name="zip" length="10" />
          </segment>
        </record> 
      </stream>
    </beanio>

Class implementations is like this:

    package example;        
    public class Employee {
        String firstName;
        String lastName;
        String title;
        String salary;
        List<Address> addressList;

        // getters and setters not shown...
    }       

    package example;
    public class Address {
        private String street;
        private String city;
        private String state;
        private String zip;

        // getters and setters not shown...
    }       

If I remove all preceding fields to repetitive segment both from mapping.xml and the input string, remaining string is properly unmarshalled, and marshalled to json afterwards, I even didn't change implementation of java classes, so the preceding fields stay uninitialized, as expected, but properly printed out after marshalling. Where did I go wrong?

OK, my camel code is in spring xml, looks like this:

    <route id="simple-route">
        <!-- from id="request-file" uri="file://C:/mqdocuments/?fileName=response464.txt"/-->
        <from id="request-file" uri="file://C:/mqdocuments/?fileName=request464.txt"/>
        <log id="route-log-request" message="request: ${body}"/>
        <setHeader headerName="CamelJmsDestinationName" id="_setHeader1">
            <constant>queue://QM_TEST/INPUTQ?targetClient=1</constant>
        </setHeader>
        <to id="_to1" pattern="InOut" uri="websphere:queue:SYSTEM.DEFAULT.LOCAL.QUEUE?useMessageIDAsCorrelationID=true&amp;replyTo=REPLYQ"/>
        <log id="route-log-response" message="response: ${body}"/>
                    <transform>
                        <simple>${body}\0</simple>
                </transform>
        <unmarshal ref="parseTransactions464"/>
        <marshal ref="jack"/>
        <log id="route-log-json" message="jackson: ${body}"/>
</route>

So basically, when I uncomment input from file, in which the reponse is saved, and place in comment mq to endpoint, unmarshalling is OK, but if I put a request to a queue, and get response, then I hope to rectify the problem by a transform that simply adds EOF character, because without it, it gives me error that I reported in the first place. And transform doesn't help, because I don't know how to write EOF (ascii 26), but even if I figure that out, I'm not sure it will help.

2

There are 2 best solutions below

0
hdjur_jcv On BEST ANSWER

I was floating around trying to identify the problem, but in the end, I realized I should have set the charset with the encoding attribute of beanio dataFormat, which I couldn't do because of this defect:

http://camel.465427.n5.nabble.com/Re-Exhausted-after-delivery-attempt-1-caught-java-lang-NullPointerException-charset-tc5817807.html

http://camel.465427.n5.nabble.com/Exhausted-after-delivery-attempt-1-caught-java-lang-NullPointerException-charset-tc5817815.html

https://issues.apache.org/jira/browse/CAMEL-12284

Finally, I was instructed by Claus Ibsen to use such workaround:

    <bean class="org.apache.camel.dataformat.beanio.BeanIODataFormat" 
          id="some_bean_id"> 
        <property name="encoding" value="UTF-8"/> 
        <property name="mapping" value="mapping.xml"/> 
        <property name="streamName" value="some_stream_name"/> 
    </bean> 
15
nicoschl On

I'm going to attempt this as an answer, unfortunately I can't test this, I have nothing setup for use with Camel. First I would not change the default recordTerminator value for BeanIO and leave it to use the default which is any of CR, LF or CRLF.

Then in the transformation of the message, I'll append a newline (\n) instead of the \0. I don't quite understand why you would want to use the EOF character if you have control over it. Instead of:

<transform>
  <simple>${body}\0</simple>
</transform>

I would go for:

<transform>
  <simple>${body}\n</simple>
</transform>

See the section on "Using New Lines or Tabs in XML DSLs" close to the bottom of the page:

Using New Lines or Tabs in XML DSLs

Available from Camel 2.9.3

From Camel 2.9.3: it is easier to specify new lines or tabs in XML DSLs as you can escape the value now xml

<transform> <simple>The following text\nis on a new line</simple></transform>