Spring:StaxEventItemReader返回具有空值的对象

时间:2016-10-22 17:04:01

标签: java xml spring spring-batch

我有一个Spring Batch作业,它读取XML文件并将其写入数据库。直到今天,一切都运转良好。但是,现在该作业将具有null属性的ProgramElement对象返回给处理器。我正在使用StaxEventItemReader和自定义分区程序。知道为什么读者会返回null属性吗?

编辑:我应该在将Java从版本102更新到112之后发生这种情况。

工作环境文件:

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:batch="http://www.springframework.org/schema/batch"
xmlns:task="http://www.springframework.org/schema/task" xmlns:file="http://www.springframework.org/schema/integration/file"
xmlns:p="http://www.springframework.org/schema/p" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans 
http://www.springframework.org/schema/beans/spring-beans.xsd    
http://www.springframework.org/schema/integration/file 
http://www.springframework.org/schema/integration/file/spring-integration-file.xsd
http://www.springframework.org/schema/beans 
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/batch 
http://www.springframework.org/schema/batch/spring-batch.xsd
http://www.springframework.org/schema/context 
http://www.springframework.org/schema/context/spring-context.xsd    
http://www.springframework.org/schema/util 
http://www.springframework.org/schema/util/spring-util.xsd
http://www.springframework.org/schema/task
http://www.springframework.org/schema/task/spring-task.xsd
http://www.springframework.org/schema/jdbc 
http://www.springframework.org/schema/jdbc/spring-jdbc.xsd">

<import resource="data-source-context.xml" />
<import resource="job-launcher-context.xml" />

<batch:job id="spa_r2_data_load">
    <batch:step id="loadData">
        <batch:partition step="loadDataStep" partitioner="filePartitioner" />
    </batch:step>
</batch:job>

<batch:step id="loadDataStep">
    <batch:tasklet>
        <batch:chunk reader="xmlItemReader" processor="peProcessor"
            writer="dbWriter" commit-interval="1" />
    </batch:tasklet>
    <batch:listeners>
        <batch:listener ref="listener"/>
    </batch:listeners>
</batch:step>

<bean id="listener" class="com.mason.seor.listener.FileListener" scope="step">
    <property name="fileName" value="#{stepExecutionContext['file.location']}"/>
</bean>

<bean id="filePartitioner" class="com.mason.seor.partitioner.FilePartitioner">
    <property name="fileLocationsProp" value="${file.location}" />
    <property name="fileNamesProp" value="${file.names:#{null}}" />
</bean>

<bean id="xmlItemReader" class="org.springframework.batch.item.xml.StaxEventItemReader" scope="step">
    <property name="resource" value="#{stepExecutionContext['file.location']}" />
    <property name="fragmentRootElementName" value="ProgramElement" />
    <property name="unmarshaller">
        <bean class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
            <property name="classesToBeBound">
                <list>
                    <value>com.mason.seor.model.r2.ProgramElement</value>
                    <value>com.mason.seor.model.r2.ProgramElementFunding</value>
                </list>
            </property>
        </bean>
    </property>
</bean>

<bean id="peProcessor" class="com.mason.seor.processor.R2Processor"
    scope="step"/>

<bean id="dbWriter"
    class="org.springframework.batch.item.database.HibernateItemWriter">
    <property name="sessionFactory" ref="sessionFactory" />
</bean>

文件分区程序:

package com.mason.seor.partitioner;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.springframework.batch.core.partition.support.Partitioner;
import org.springframework.batch.item.ExecutionContext;

public class FilePartitioner implements Partitioner {

String fileLocationsProp;
String fileNamesProp;

@Override
public Map<String, ExecutionContext> partition(int arg0){

    Map<String, ExecutionContext> partitionMap = new HashMap<>();
    String[] fileNames;
    if (fileNamesProp == null) {
        File filesDir = new File(fileLocationsProp.replace("file:", ""));
        if (!filesDir.isDirectory()) {
            throw new IllegalStateException("HEY! " + fileLocationsProp + " is not a directory!!!!!!!");
        }

        // create new filename filter
         FilenameFilter fileNameFilter = new FilenameFilter() {

            @Override
            public boolean accept(File dir, String name) {
               if(name.lastIndexOf('.')>0)
               {
                  // get last index for '.' char
                  int lastIndex = name.lastIndexOf('.');

                  // get extension
                  String str = name.substring(lastIndex);

                  // match path name extension
                  if(str.equals(".xml"))
                  {
                     return true;
                  }
               }
               return false;
            }
         };

        fileNames = filesDir.list(fileNameFilter);
    } else {
        fileNames = fileNamesProp.split(",");
    }
    int counter = 0;

    for (String fileName : fileNames) {

        //trimXmlTags(fileLocationsProp,fileName);

        ExecutionContext context = new ExecutionContext();
        context.put("file.location", fileLocationsProp + fileName);
        context.put("file.name", fileName);
        counter++;
        partitionMap.put("file" + counter, context);
    }

    return partitionMap;
}

private void trimXmlTags(String fileLocation, String fileName){
        File xml = new File(fileLocation.replace("file:", "")+fileName);
        String charset = "UTF-8";
        // need to get rid of these prefixes for the XML tags and attributes
        String[] delete = {"r2:",":r2"};
        String[] replace = {"",""};
        // we don't need these lines
        String throwOut = "jb:";
        try {
            File temp = File.createTempFile("temp", ".xml", xml.getParentFile());

            //open file for reading
            BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(xml), charset));
            //open temp file for writing
            PrintWriter writer = new PrintWriter(new OutputStreamWriter(new FileOutputStream(temp), charset));

            for (String line; (line = reader.readLine()) != null;) {
                line = StringUtils.replaceEach(line, delete, replace);
                if(!line.contains(throwOut)){
                    writer.println(line);
                }
            }

            reader.close();
            writer.close();

            xml.delete();
            temp.renameTo(xml);


        } catch (IOException e) {
            System.out.println("file location not found: "+xml.getParentFile());
            System.exit(1);
        }
}

public void setFileLocationsProp(String fileLocationsProp) {
    this.fileLocationsProp = fileLocationsProp;
}

public void setFileNamesProp(String fileNamesProp) {
    this.fileNamesProp = fileNamesProp;
}

}

ProgramElement类:

package com.mason.seor.model.r2;

import java.util.Date;

import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;

import com.mason.seor.data.SubmissionDateConverter;

@XmlRootElement(name = "ProgramElement",     namespace="http://www.dtic.mil/comptroller/xml/schema/022009/r2")
public class ProgramElement {

String monetaryUnit;
String programElementNumber;
String programElementTitle;
Integer r1LineNumber;
Integer budgetYear;
String budgetCycle;
Date submissionDate;
String serviceAgencyName;
String AppropriationCode;
String appropriationName;
Integer budgetActivityNumber;
String budgetActivityTitle;
ProgramElementFunding programElementFunding;

@XmlAttribute(name = "MonetaryUnit")
public String getMonetaryUnit() {
    return monetaryUnit;
}

public void setMonetaryUnit(String monetaryUnit) {
    this.monetaryUnit = monetaryUnit;
}

@XmlElement(name = "ProgramElementNumber")
public String getProgramElementNumber() {
    return programElementNumber;
}

public void setProgramElementNumber(String programelementNumber) {
    this.programElementNumber = programelementNumber;
}

@XmlElement(name = "ProgramElementTitle")
public String getProgramElementTitle() {
    return programElementTitle;
}

public void setProgramElementTitle(String programElementTitle) {
    this.programElementTitle = programElementTitle;
}

@XmlElement(name = "R1LineNumber")
public Integer getR1LineNumber() {
    return r1LineNumber;
}

public void setR1LineNumber(Integer r1LineNumber) {
    this.r1LineNumber = r1LineNumber;
}

@XmlElement(name = "BudgetYear")
public Integer getBudgetYear() {
    return budgetYear;
}

public void setBudgetYear(Integer budgetYear) {
    this.budgetYear = budgetYear;
}

@XmlElement(name = "BudgetCycle")
public String getBudgetCycle() {
    return budgetCycle;
}

public void setBudgetCycle(String budgetCycle) {
    this.budgetCycle = budgetCycle;
}

@XmlJavaTypeAdapter(type = Date.class, value = SubmissionDateConverter.class)
@XmlElement(name = "SubmissionDate")
public Date getSubmissionDate() {
    return submissionDate;
}

public void setSubmissionDate(Date submissionDate) {
    this.submissionDate = submissionDate;
}

@XmlElement(name = "ServiceAgencyName")
public String getServiceAgencyName() {
    return serviceAgencyName;
}

public void setServiceAgencyName(String serviceAgencyName) {
    this.serviceAgencyName = serviceAgencyName;
}

@XmlElement(name = "AppropriationCode")
public String getAppropriationCode() {
    return AppropriationCode;
}

public void setAppropriationCode(String appropriationCode) {
    AppropriationCode = appropriationCode;
}

@XmlElement(name = "AppropriationName")
public String getAppropriationName() {
    return appropriationName;
}

public void setAppropriationName(String appropriationName) {
    this.appropriationName = appropriationName;
}

@XmlElement(name = "BudgetActivityNumber")
public Integer getBudgetActivityNumber() {
    return budgetActivityNumber;
}

public void setBudgetActivityNumber(Integer budgetActivityNumber) {
    this.budgetActivityNumber = budgetActivityNumber;
}

@XmlElement(name = "BudgetActivityTitle")
public String getBudgetActivityTitle() {
    return budgetActivityTitle;
}

public void setBudgetActivityTitle(String budgetActivityTitle) {
    this.budgetActivityTitle = budgetActivityTitle;
}

@XmlElement(name = "ProgramElementFunding")
public ProgramElementFunding getProgramElementFunding() {
    return programElementFunding;
}

public void setProgramElementFunding(ProgramElementFunding programElementFunding) {
    this.programElementFunding = programElementFunding;
}

}

ProgramElementFunding类:

package com.mason.seor.model.r2;

import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlType;

@XmlType(name = "ProgramElementFunding")
public class ProgramElementFunding {

Double priorYear;
Double currentYear;
Double budgetYearOne;
Double budgetYearOneBase;
Double budgetYearTwo;
Double budgetYearThree;
Double budgetYearFour;
Double budgetYearFive;

@XmlElement(name = "PriorYear")
public Double getPriorYear() {
    return priorYear;
}
public void setPriorYear(Double priorYear) {
    this.priorYear = priorYear;
}
@XmlElement(name = "CurrentYear")
public Double getCurrentYear() {
    return currentYear;
}
public void setCurrentYear(Double currentYear) {
    this.currentYear = currentYear;
}
@XmlElement(name = "BudgetYearOne")
public Double getBudgetYearOne() {
    return budgetYearOne;
}
public void setBudgetYearOne(Double budgetYearOne) {
    this.budgetYearOne = budgetYearOne;
}
@XmlElement(name = "BudgetYearOneBase")
public Double getBudgetYearOneBase() {
    return budgetYearOneBase;
}
public void setBudgetYearOneBase(Double budgetYearOneBase) {
    this.budgetYearOneBase = budgetYearOneBase;
}
@XmlElement(name = "BudgetYearTwo")
public Double getBudgetYearTwo() {
    return budgetYearTwo;
}
public void setBudgetYearTwo(Double budgetYearTwo) {
    this.budgetYearTwo = budgetYearTwo;
}
@XmlElement(name = "BudgetYearThree")
public Double getBudgetYearThree() {
    return budgetYearThree;
}
public void setBudgetYearThree(Double budgetYearThree) {
    this.budgetYearThree = budgetYearThree;
}
@XmlElement(name = "BudgetYearFour")
public Double getBudgetYearFour() {
    return budgetYearFour;
}
public void setBudgetYearFour(Double budgetYearFour) {
    this.budgetYearFour = budgetYearFour;
}
@XmlElement(name = "BudgetYearFive")
public Double getBudgetYearFive() {
    return budgetYearFive;
}
public void setBudgetYearFive(Double budgetYearFive) {
    this.budgetYearFive = budgetYearFive;
}



}

XML示例:

<?xml version="1.0" encoding="UTF-8"?>
<ProgramElementList xmlns="http://www.dtic.mil/comptroller/xml/schema/022009/r2" targetSchemaVersion="1.0">
<ProgramElement monetaryUnit="Millions" classification="UNCLASSIFIED">
    <ProgramElementNumber>0601110D8Z</ProgramElementNumber>
    <ProgramElementTitle>Basic Research Initiatives</ProgramElementTitle>
    <R1LineNumber>3</R1LineNumber>
    <BudgetYear>2017</BudgetYear>
    <BudgetCycle>PB</BudgetCycle>
    <SubmissionDate>2016-02</SubmissionDate>
    <ServiceAgencyName>Office of the Secretary Of Defense</ServiceAgencyName>
    <AppropriationCode>0400</AppropriationCode>
    <AppropriationName>Research, Development, Test Evaluation, Defense-Wide</AppropriationName>
    <BudgetActivityNumber>1</BudgetActivityNumber>
    <BudgetActivityTitle>Basic Research</BudgetActivityTitle>
    <ProgramElementFunding>
        <PriorYear>41.054</PriorYear>
        <CurrentYear>71.940</CurrentYear>
        <BudgetYearOne>36.654</BudgetYearOne>
        <BudgetYearOneBase>36.654</BudgetYearOneBase>
        <BudgetYearTwo>40.649</BudgetYearTwo>
        <BudgetYearThree>42.988</BudgetYearThree>
        <BudgetYearFour>45.607</BudgetYearFour>
        <BudgetYearFive>46.500</BudgetYearFive>
        <CostToComplete>Continuing</CostToComplete>
        <TotalCost>Continuing</TotalCost>
    </ProgramElementFunding>
</ProgramElement>

1 个答案:

答案 0 :(得分:0)

显然问题在于XML中的命名空间;由于某种原因,命名空间变得无法访问,我想这会导致读者出现故障。我通过使用XStreamMarshaller的自定义实现来解决这个问题:

How to ignore namespace when unmarshalling XML file