Results 1 to 3 of 3

Thread: FormatterLineAggregator trouble with null date formatting

Hybrid View

  1. #1
    Join Date
    Feb 2007
    Posts
    11

    Default FormatterLineAggregator trouble with null date formatting

    Being a newbe in Spring-batch I'm facing a simple trouble when I try to generate a flat file with date formating.

    Versions
    JDK 1.5
    spring-batch-infrastructure-2.0.4.RELEASE.jar

    Context:
    Generating a flat file with data extracted using a SQL query.
    Some datas may be null (not mandatory)

    Trouble:
    When a date is null the formating can't be done it throws an exception :
    Code:
    IllegalFormatConversionException: Y != java.lang.String
    Question:
    Is there a way to cope with null dates when formatting?

    Configuration:
    Code:
    <bean id="cleFormateur"
    	class="org.springframework.batch.item.file.transform.FormatterLineAggregator">
    	<property name="fieldExtractor">
    		<bean
    			class="org.springframework.batch.item.file.transform.BeanWrapperFieldExtractor">
    			<property name="names"
    				value="id,soccle,matricule,blanc,codeBordereau,dateVali" />
    		</bean>
    	</property>
    	<property name="format" value="%09d%3.3s%-12.12s%6$tY-%6$tm-%6$td" />
    </bean>
    My opinion:
    According to me this is due to ExtractorLineAggregator.aggregate method line 58 because this method replaces null values from the result of the FieldExtractor by an empty String.
    Then the date formating can't be applied to a String.

    Here is the Spring source code for ExtractorLineAggregator.aggregate:
    Code:
    	/**
    	 * Extract fields from the given item using the {@link FieldExtractor} and
    	 * then aggregate them. Any null field returned by the extractor will be
    	 * replaced by an empty String. Null items are not allowed.
    	 * 
    	 * @see org.springframework.batch.item.file.transform.LineAggregator#aggregate(java.lang.Object)
    	 */
    	public String aggregate(T item) {
    		Assert.notNull(item);
    		Object[] fields = this.fieldExtractor.extract(item);
    
    		//
    		// Replace nulls with empty strings
    		//
    		Object[] args = new Object[fields.length];
    		for (int i = 0; i < fields.length; i++) {
    			if (fields[i] == null) {
    				args[i] = "";
    			}
    			else {
    				args[i] = fields[i];
    			}
    		}
    
    		return this.doAggregate(args);
    	}
    In my opinion, processing the result of FieldExtractor is a nonsense. If the behaviour of the FieldExtractor is not correct, just let the user write another implementation.

  2. #2
    Join Date
    Feb 2008
    Posts
    488

    Default

    The reason we transform null to empty string is that in the majority of cases, null should be represented in the output as blanks, not "null". Your case is special because you are using a date-based format. It would probably be easiest for you to create your own LineAggregator.

  3. #3
    Join Date
    Feb 2007
    Posts
    11

    Default workarraound using a custom FieldExtractor

    I managed to find a workarround this way:
    - Write a custom FieldExtractor
    - This one has a Map associating for all Date or Calendar fields with theire formatting.
    - It first convert non null fields to String
    - Then delegates the formating.

    Java
    Code:
    /**
     * @author <b>(sylvain.mougenot) </b>
     * @version 1.00, 9 déc. 2009
     */
    public class BeanWrapperFieldExtractorDateFormatting<T>
        implements FieldExtractor<T>, InitializingBean {
    
        private String[] names;
    
        private Map<String, String> dateFormatting;
    
        /**
         * @param names field names to be extracted by the {@link #extract(Object)} method.
         */
        public void setNames(final String[] names) {
            this.names = names;
        }
    
        /**
         * @param dateFormatting the dateFormatting to set
         */
        public void setDateFormatting(final Map<String, String> dateFormatting) {
            this.dateFormatting = dateFormatting;
        }
    
        /* (non-Javadoc)
         * @see org.springframework.batch.item.file.transform.FieldExtractor#extract(java.lang.Object)
         */
        public Object[] extract(final T item) {
            final List<Object> values = new ArrayList<Object>();
    
            final BeanWrapper bw = new BeanWrapperImpl(item);
            for (final String propertyName : this.names) {
                Object propertyValue = bw.getPropertyValue(propertyName);
                if (propertyValue != null) {
                    final String myFormat = dateFormatting.get(propertyName);
                    // Do we have a format
                    if (myFormat != null) {
                        // only format Date and Calendar Objects
                        if (propertyValue instanceof Date) {
                            propertyValue = DateFormatUtils.format((Date) propertyValue, myFormat);
                        } else if (propertyValue instanceof Calendar) {
                            propertyValue = DateFormatUtils.format(((Calendar) propertyValue).getTime(), myFormat);
                        }
                    }
                }
                values.add(propertyValue);
            }
            return values.toArray();
        }
    Bean config
    Code:
    <bean
    	class="org.springframework.batch.item.file.transform.FormatterLineAggregator">
    	<property name="fieldExtractor">
    		<bean
    			class="fr.mediapost.sirh.batch.distributeur.util.BeanWrapperFieldExtractorDateFormatting">
    			<!-- Bean de type DistributeurData -->
    			<property name="names"
    				value="dateEntreeSoci,typeContrat,dateSortieEtab,motifSortie,blanc,soccle,mtfcatehr,mtfcodehr" />
    			<property name="dateFormatting">
    				<map key-type="java.lang.String" value-type="java.lang.String">
    					<entry key="dateEntreeSoci" value="yyyy-MM-dd" />
    					<entry key="dateSortieEtab" value="yyyy-MM-dd" />
    				</map>
    			</property>
    		</bean>
    	</property>
    	<property name="format"
    		value="%10.10s%3.3S0001%10.10s%3.3S%3$10.10s%10sOO %3.3s%6.6S%6.6S%5$22sEMBAUC%2$-6.6S%5$10sDISTRIB%5$82s0%5$70s" />
    </bean>

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •