Announcement Announcement Module
Collapse
No announcement yet.
How to read collections in a comma separated flat file. Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • How to read collections in a comma separated flat file.

    Hello techsters -

    I have the following domain class:
    Code:
       public class Book {
    
        private String name;
       
        private Set<Author> authors = new HashSet<Author>();
    
       // getters and setters for the above
      }
    
      public class Author {
        
        private name;
        private String address    
    
        // getters and setters for the above.
    }
    I receive a flat file like the following that has the following contents:
    Pro Spring Batch, Dave Syer, Michelle T Minella
    Spring Integration In Action, Dave Syer, John Fisher


    Code:
     <beans:bean id="lineMapper" 		    
                class="org.springframework.batch.item.file.mapping.DefaultLineMapper">
    		<beans:property name="lineTokenizer" ref="lineTokenizer" />
    		<beans:property name="fieldSetMapper" ref="fieldSetMapper" />
    	</beans:bean>
    
       <beans:bean id="lineTokenizer"     
              class="org.springframework.batch.item.file.transform.DelimitedLineTokenizer">
       <beans:property name="names"  value="name,authors[0].name,authors[1].name"/>
        </beans:bean>
    	<beans:bean id="fieldSetMapper"
    		class="org.springframework.batch.item.file.mapping.BeanWrapperFieldSetMapper">
    		<beans:property name="prototypeBeanName" value="book" />
    	</beans:bean>
    
     <beans:bean id="book" class="org.app.Book" scope="prototype" />
    Basically I would want the framework to create a Book Instance with a set of authors when it reads each line. However, it seems it does not understand authors[0].name,authors[1].name and cannot load it in the set. It keeps saying it cannot add items to the set with size 0, which is understandable since the bean when instantiated has a set with size 0, but in java we can add elements to a set initialized with zero size. I am unable to figure out what is the framework's understanding and how we can load collections of other instances like the one stated above.

    Here is the error that I receive:
    Invalid property 'authors[0]' of bean class [org.app.Book]: Cannot get element with index 0 from Set of size 0, accessed using property path 'authors[0]'

    Can you please guide how I can achieve the above functionality ?

    Further if someone can explain me the following text as written in the spring documentation, it would be of great help:
    http://static.springsource.org/sprin...SetMapper.html

    "Nested property paths, including indexed properties in maps and collections, can be referenced by the FieldSet names. They will be converted to nested bean properties inside the prototype. The FieldSet and the prototype are thus tightly coupled by the fields that are available and those that can be initialized. If some of the nested properties are optional (e.g. collection members) they need to be removed by a post processor."

    Apparently what seems to be happening by saying authors[0].name is that framework understands it to get a value from the set. But my intention is to tell the framework to make a bean of type Author and add it to the set.

    If anyone is aware of how to do this with respect to the above documentation please do let me know or please do let me know if I have not understood what is written in the documentation.
    Last edited by Tams; Sep 26th, 2012, 10:34 PM.

  • #2
    The javadocs for setNames states:

    * Setter for column names. Optional, but if set, then all lines must have
    * as many or fewer tokens.


    You have:

    <beansroperty name="names" value="name,authors[0].name,authors[1].name"/>

    I suspect authors[0].name NOT a valid column name for the mapper?

    Here is where mapping happens in the BeanWrapperFieldSetMapper:

    Code:
    	/**
    	 * Map the {@link FieldSet} to an object retrieved from the enclosing Spring
    	 * context, or to a new instance of the required type if no prototype is
    	 * available.
    	 * @throws BindException if there is a type conversion or other error (if
    	 * the {@link DataBinder} from {@link #createBinder(Object)} has errors
    	 * after binding).
    	 * 
    	 * @throws NotWritablePropertyException if the {@link FieldSet} contains a
    	 * field that cannot be mapped to a bean property.
    	 * @see org.springframework.batch.item.file.mapping.FieldSetMapper#mapFieldSet(FieldSet)
    	 */
    	public T mapFieldSet(FieldSet fs) throws BindException {
    		T copy = getBean();
    		DataBinder binder = createBinder(copy);
    		binder.bind(new MutablePropertyValues(getBeanProperties(copy, fs.getProperties())));
    		if (binder.getBindingResult().hasErrors()) {
    			throw new BindException(binder.getBindingResult());
    		}
    		return copy;
    	}
    You might want to peak into the DataBinder while debugging.

    Jeff

    Comment


    • #3
      Thanks Jeff. My question is if a class contains a collection property and I want to use the capabiltiies of org.springframework.batch.item.file.mapping.BeanWr apperFieldSetMapper, how will I need to write my LineTokenzier property names such that it can add the objects in the collection apart from the main Bean.

      Since the documentation http://static.springsource.org/sprin...SetMapper.html

      says - Nested property paths, including indexed properties in maps and collections.....

      I am a little confused if this at all supported and if so how I can achieve it. I know if it works for a property like Customer.Id, but how to make it work for collections ?

      Regards.

      Comment

      Working...
      X