Some trouble with a specific file (Multi line and multi element by line).

550 views
Skip to first unread message

Anthony Chablowski

unread,
Feb 10, 2017, 9:52:09 AM2/10/17
to beanio-users
Hello,

I have some problems with BeanIO. I need to get a group who contains a list of element (1 per line) who contains an object who has a list of element (Many elements in one line).
It's a bit difficult to explain, but below you will found an example file, the java class and the xml i tried to use. (The file format is obligatory like this).

What is wrong ? It's possible to do that ?

Thanks,

Regards.

Flat file : 
tTEACHER1
sSTUDENT1
mMATTER1    MATTER2    MATTER3    
sSTUDENT2
mMATTER1    MATTER2    MATTER3     MATTER4     
sSTUDENT3
mMATTER1    MATTER2    MATTER3     MATTER4      MATTER5 
tTEACHER2
sSTUDENT1
mMATTER1    MATTER2    MATTER3     MATTER4      MATTER5
sSTUDENT2
mMATTER1    MATTER2    MATTER3     MATTER5
sSTUDENT3
mMATTER1    MATTER2    MATTER3     
  

Java class :
public class Teacher {

    private String header;
    private String name;
    private List<Student> students;

    public class Student {
      private String name;
      private Agenda agenda;
    }
    
    public class Agenda {
        private String specialCode;
        private List<Matter> matters;
  }
    
    public class Matter {
        private String name;
        private String speciality;
  }
}


XML Test : 
<stream name="IRG" format="fixedlength">
  <group name="teacher" order="2" minOccurs="1" maxOccurs="unbounded"
    class="test.Teacher">
    <record name="teacher" minOccurs="1" maxOccurs="1" order="1">
      <field name="header" at="0" length="1" required="true" rid="true"
        literal="t" ignore="true" />
      <field name="name" at="1" length="1" minOccurs="0"
        required="false" lazy="true" />
    </record>
    <record name="students" order="2" minOccurs="1" maxOccurs="9" collection="list" class="test.Student">
      <field name="header" at="0" length="1" required="true" rid="true"
        literal="s" ignore="true" />
      <field name="name" at="1" length="1" minOccurs="0"
        required="false" lazy="true" />
      <segment name="agenda" class="test.Agenda">
        <field name="header" at="0" length="1" required="true" rid="true"
          literal="m" ignore="true" />
        <field name="specialCode" at="1" length="10" required="false"
          lazy="true" trim="false" keepPadding="true" />
        <segment name="matters" collection="list" minOccurs="1" maxOccurs="unbounded" class="test.Matter">
          <field name="name" at="0" length="3" required="false"
            lazy="true"  />
          <field name="speciality" at="3" length="4" required="false"
            lazy="true"  />
        </segment>
      </segment>
    </record>
  </group>
</stream>




Anthony Chablowski

unread,
Feb 10, 2017, 10:30:06 AM2/10/17
to beanio-users
It's like this example :
package example;
import java.util.Date;

public class Order {
    String id;
    Date date;
    BigDecimal amount;
    Customer customer;
    List<Item> items;
}

public class Customer {
    String firstName;
    String lastName;
}

public class Item {
    String name;
    int quantity;
    BigDecimal amount;
}

But i have to get a list of Items in Customer like that : 
package example;
import java.util.Date;

public class Order {
    String id;
    Date date;
    BigDecimal amount;
    Customer customer;
}

public class Customer {
    String firstName;
    List<Item> items;
}

public class Item {
    String name;
    int quantity;
    BigDecimal amount;
}

Anthony Chablowski

unread,
Feb 13, 2017, 3:44:10 AM2/13/17
to beanio-users
Hi,

There is no way to do that (That's exactly what i need) : 

tTEACHER1
sSTUDENT1
mMATTER1    MATTER2    MATTER3    
sSTUDENT2
mMATTER1    MATTER2    MATTER3     MATTER4    
sSTUDENT3
mMATTER1    MATTER2    MATTER3     MATTER4      MATTER5
tTEACHER2
sSTUDENT1
sSTUDENT2
sSTUDENT3
mMATTER1    MATTER2    MATTER3     MATTER4      MATTER5


Thanks in advance :)


Le vendredi 10 février 2017 15:52:09 UTC+1, Anthony Chablowski a écrit :

Nico Schlebusch

unread,
Feb 13, 2017, 5:13:17 PM2/13/17
to bea...@googlegroups.com
Hi Anthony,

I think it is possible to do what you are asking and the changes you made to be a List of "Item"s from the documentation is correct. There is most likely something small not correct in your mapping file. I'll try to have a look at it tomorrow, in the mean time, please provide us with the output you manage to generate, if not, then the error messages.

Kind regards,
Nico Schlebusch
nico...@gmail.com

--
You received this message because you are subscribed to the Google Groups "beanio-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to beanio+un...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Nico Schlebusch

unread,
Feb 13, 2017, 5:34:01 PM2/13/17
to bea...@googlegroups.com
Hi Anthony,

I had a quick look at the mapping file versus the sample output you provide, they don't exactly match... I don't see the use of test.Agenda.specialCode. If it is used together with the matters, I would suspect to see at least 10 empty spaces after 'm' and before the first 'MATTER1' or a new line after 'm'?
        <field name="header" at="0" length="1" required="true" rid="true" literal="m" ignore="true" />       
        <field name="specialCode" at="1" length="10" required="false" lazy="true" trim="false" keepPadding="true" />
        <segment name="matters" collection="list" minOccurs="1" maxOccurs="unbounded" class="test.Matter">

Also, I don't think you need the private String header field/property in both the Teacher & Student classes.

The "matters" segment mentions a name and speciality fields(both optional), is the empty space next to 'MATTER1' the speciality?

If possible, please update your expected result.


Kind regards,
Nico Schlebusch
nico...@gmail.com


Message has been deleted
Message has been deleted
Message has been deleted

Anthony Chablowski

unread,
Feb 14, 2017, 3:45:33 AM2/14/17
to beanio-users
Hi,
Thank you for your reply. It is a bit complicated for me to be clear in my request because I work with confidential data, I tried to reproduce an example faithful to my need.
Please see below : 

tTEACHER1
sSTUDENT1
mClass4 MATTER1 MATTER2
sSTUDENT2
mClass4 MATTER1 MATTER2 MATTER3 MATTER4
sSTUDENT3
mClass4 MATTER1 MATTER2 MATTER3 MATTER4 MATTER5
tTEACHER2
sSTUDENT1
sSTUDENT2
sSTUDENT3
mClass4 MATTER1 MATTER2 MATTER3 MATTER4 MATTER5


package test;


import java.util.List;


public class TeacherModel {



   
private String header;
   
private String name;

   
private List<StudentModel> students;
   
}  
package test;


import java.util.List;


public class StudentModel {



 
private String header;
 
private String name;

 
private AgendaModel agenda;
           
}  


package test;


import java.util.List;


public class AgendaModel{
   
private String header;
   
private String specialClass;
   
private List<MatterModel> matters;
     
}  


package test;


public class MatterModel{
 
private String name;      
}  




<?xml version='1.0' encoding='UTF-8' ?>
<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="TEST" format="fixedlength">
 
<group name="teacherModel" order="2" minOccurs="1" maxOccurs="unbounded"
 
class="test.TeacherModel">
 
<record name="teacherModel" minOccurs="1" maxOccurs="1" order="1">

 
<field name="header" at="0" length="1" required="true" rid="true"
 
literal="t" ignore="true" />

 
<field name="name" at="1" length="8" required="false" lazy="true" />
 
</record>
 
<record name="students" order="2" minOccurs="1" maxOccurs="9" collection="list" class="test.StudentModel">

 
<field name="header" at="0" length="1" required="true" rid="true"
 
literal="s" ignore="true" />

 
<field name="name" at="1" length="8" minOccurs="0"

 
required="false" lazy="true" />

 
<segment name="agenda" class="test.AgendaModel">

 
<field name="header" at="0" length="1" required="true" rid="true"
 
literal="m" ignore="true" />

 
<field name="specialClass" at="1" length="6" required="false"

 
lazy="true" trim="false" keepPadding="true" />

 
<segment name="matters" collection="list" minOccurs="1" maxOccurs="unbounded" class="test.MatterModel">
 
<field name="name" at="0" length="7" required="false"

 
lazy="true"  />
 
</segment>
 
</segment>
     
</record>
 
</group>
 
</stream>
</beanio>


And the error i get : 

java.lang.IndexOutOfBoundsException
 at org
.beanio.internal.parser.UnmarshallingContext.getRecordContext(UnmarshallingContext.java:230)
 at org
.beanio.internal.parser.BeanReaderImpl.getRecordContext(BeanReaderImpl.java:279)
 at com
.afklm.astrid.beanio.TestFile.testRecordGroup(TestFile.java:30)
 at sun
.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
 at sun
.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
 at sun
.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
 at java
.lang.reflect.Method.invoke(Method.java:483)
 at org
.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
 at org
.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
 at org
.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
 at org
.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
 at org
.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
 at org
.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
 at org
.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
 at org
.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
 at org
.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
 at org
.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
 at org
.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
 at org
.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
 at org
.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
 at org
.junit.runners.ParentRunner.run(ParentRunner.java:363)
 at org
.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
 at org
.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
 at org
.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
 at org
.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
 at org
.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
 at org
.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)



Thanks in advance,

Regards,

Nico Schlebusch

unread,
Feb 14, 2017, 5:46:11 PM2/14/17
to bea...@googlegroups.com
Hi Anthony,

Try the mapping file below. Note the extra class 'test.TeacherFile' I added to cater for multiple teachers as in your example output. This also requires an additional <group name="TeacherFile"> in the mapping.xml file. You then pass this TeacherFile object to the BeanWriter to create the file.
<?xml version='1.0' encoding='UTF-8' ?>
<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="TEST" format="fixedlength">
 
    <group name="FILE" maxOccurs="1" class="test.TeacherFile">
      <group name="teachers" minOccurs="1" maxOccurs="unbounded" collection="list" class="test.TeacherModel">

        <record name="teacherModel" minOccurs="1" maxOccurs="1" >
          <field name="header" at="0" length="1" rid="true" literal="t" ignore="true" />

          <field name="name" at="1" length="8" required="false" lazy="true" />
        </record>
       
        <group name="students" minOccurs="1" maxOccurs="9" collection="list" class="test.StudentModel">
          <record name="student">

            <field name="header" at="0" length="1" required="true" rid="true" literal="s" ignore="true" />
            <field name="name" at="1" length="8" minOccurs="0" required="false" lazy="true" />
          </record>
           
          <record name="agenda" class="test.AgendaModel" maxOccurs="1">

            <field name="header" at="0" length="1" required="true" rid="true" literal="m" ignore="true" />
            <field name="specialClass" at="1" length="6" required="false" lazy="true" trim="false" keepPadding="true" />
           
            <segment name="matters" collection="list" minOccurs="1" maxOccurs="unbounded" class="test.MatterModel">
              <field name="name" at="7" length="7" required="false" lazy="true" />
            </segment>
          </record>        
         
        </group>
       
      </group>
    </group>
  </stream>
 
</beanio>
Compare this mapping file with your last email. Note that the "name" field from the "matters" segment must start at="7" or whatever the correct value is, otherwise you will loose the first 6 characters from the "matters" segment.

Basically, each collection (list) of objects requires a <group> element in the mapping file where each element of the collection's output start on a new line. Otherwise, if you want them on the same line, you use a <segment> instead as you did with the "matters" segment.

Let me know if this works for you.


Kind regards,
Nico Schlebusch
nico...@gmail.com

Anthony Chablowski

unread,
Feb 15, 2017, 4:23:16 AM2/15/17
to beanio-users
Hi,

It works better thanks, but i have a last problem, in my segment i have optional field but if I set "required ="false"" I get error like "Expected minimum 1 occurences", then I tried to use "minOccurs=0" and I get error : "A repeating segment may not contain components where minOccurs=0".

How can I resolve ? Thanks.

Regards,

Le vendredi 10 février 2017 15:52:09 UTC+1, Anthony Chablowski a écrit :

Nico Schlebusch

unread,
Feb 15, 2017, 4:54:07 AM2/15/17
to bea...@googlegroups.com
Hi Anthony,

Can you perhaps assign a default value to that field? Even if it is all spaces so that you maintain your format.

Kind regards,
Nico Schlebusch
nico...@gmail.com


Anthony Chablowski

unread,
Feb 15, 2017, 5:01:26 AM2/15/17
to beanio-users
I tried : 
<segment name="matters" collection="list" minOccurs="1" maxOccurs="unbounded" class="com.afklm.astrid.beanio.antho.MatterModel">
              <field name="name" at="7" length="6" required="false" lazy="true" />
              <field name="number" at="13" length="1" default=""/>
            </segment>

Or :
<segment name="matters" collection="list" minOccurs="1" maxOccurs="unbounded" class="com.afklm.astrid.beanio.antho.MatterModel">
              <field name="name" at="7" length="6" required="false" lazy="true" />
              <field name="number" at="13" length="1" nillable="true"/>
            </segment>


Both don't work. Still the error "Expected minimum 1 Occurnces"
Any other idea ? thanks for helpful

Regards,


Le vendredi 10 février 2017 15:52:09 UTC+1, Anthony Chablowski a écrit :

Nico Schlebusch

unread,
Feb 15, 2017, 5:36:03 AM2/15/17
to bea...@googlegroups.com
What is the data type of the 'number' field ? Primitive or Wrapper class?

I can't reproduce the error on my side,
<field name="number" at="13" length="1" required="false"/>
works fine for me, whether the number is null or have an actual value, the extra character is catered for in the output.


Kind regards,
Nico Schlebusch
nico...@gmail.com


Anthony Chablowski

unread,
Feb 15, 2017, 5:46:56 AM2/15/17
to beanio-users
Yes but I need at least ONE time by teacher. This file works : 
tTEACHER1
sSTUDENT1
mClass4MATTER MATTER 
sSTUDENT2
mClass4MATTER MATTER MATTER MATTER 
sSTUDENT3
mClass4MATTER1MATTER2MATTER3MATTER4MATTER5
tTEACHER2
sSTUDENT1
sSTUDENT2
sSTUDENT3
mClass4MATTER1MATTER2MATTER3MATTER4MATTER5

But this not : 
tTEACHER1
sSTUDENT1
mClass4MATTER MATTER 
sSTUDENT2
mClass4MATTER MATTER MATTER MATTER 
sSTUDENT3
mClass4MATTER1MATTER2MATTER3MATTER4MATTER5
tTEACHER2
sSTUDENT1
sSTUDENT2
sSTUDENT3
mClass4MATTER MATTER MATTER MATTER MATTER

That's why I don't understand.. Thanks

Anthony Chablowski

unread,
Feb 15, 2017, 8:43:41 AM2/15/17
to beanio-users
Hi again,

It was my fault, my file is wrong, I had some extra spaces at the end of the line.

This request seems to be resolved, thank you.

Regards,
Reply all
Reply to author
Forward
0 new messages