如何解决java.lang.IllegalStateException:Marshaller 必须支持编组对象的类
我在 spring-boot 应用程序中使用 spring batch
。 Spring Boot 版本是 2.3.3.RELEASE
。
我有一个复杂的 XML,其中包含 header
(文件信息)和 body
(交易列表)。我使用 XJC tool
从 XSD
获取 java 类。
为了重现这个错误,我在 Github spring-batch-xml-to-xml
上添加了代码我需要做的:我必须阅读(unmarshal
) XML,在正文中做一些business logic on each transaction element
,然后最后写({{1} }) 具有相同标题和更新正文的 XML 文件。
当我尝试编组一个子元素对象时,我得到 IllegalStateException: Marshaller must support the class of the marshalled object。
示例 XML 文件
marshal
Spring 批量配置
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<reportFile xmlns="http://deutsche-boerse.com/DBRegHub" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://deutsche-boerse.com/DBRegHub regulatoryHubUpload_MiFIR_001.60.xsd">
<fileinformation>
<sender>11003220</sender>
<timestamp>2020-12-23T09:05:34Z</timestamp>
<environment>LOCAL</environment>
<version>1.0</version>
</fileinformation>
<record>
<transaction>
</transaction>
<transaction>
</transaction>
<transaction>
</transaction>
</record>
</reportFile>
package com.trax.europeangateway.config;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
import org.springframework.batch.core.configuration.annotation.JobScope;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepScope;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.batch.core.launch.support.RunIdIncrementer;
import org.springframework.batch.core.launch.support.SimpleJobLauncher;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.item.ExecutionContext;
import org.springframework.batch.item.itemprocessor;
import org.springframework.batch.item.ItemStreamReader;
import org.springframework.batch.item.support.Compositeitemprocessor;
import org.springframework.batch.item.support.CompositeItemWriter;
import org.springframework.batch.item.xml.StaxEventItemWriter;
import org.springframework.batch.item.xml.builder.StaxEventItemReaderBuilder;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
import org.springframework.core.task.TaskExecutor;
import org.springframework.oxm.jaxb.Jaxb2Marshaller;
import org.springframework.oxm.xstream.XStreamMarshaller;
import org.springframework.util.ClassUtils;
import org.springframework.web.client.RestTemplate;
import com.trax.europeangateway.itemprocessor.omegaxml.PIExtractoritemprocessor;
import com.trax.europeangateway.itemprocessor.omegaxml.PIRemoveritemprocessor;
import com.trax.europeangateway.itemwriter.omegaxml.EdsClientItemWriter;
import com.trax.europeangateway.itemwriter.omegaxml.ExtendedStaxEventItemWriter;
import com.trax.europeangateway.itemwriter.omegaxml.OmegaXmlFileWriter;
import com.trax.europeangateway.itemwriter.omegaxml.OmegaXmlFooterCallBack;
import com.trax.europeangateway.itemwriter.omegaxml.OmegaXmlHeaderCallBack;
import com.trax.europeangateway.listener.JobResultListener;
import com.trax.europeangateway.listener.StepResultListener;
import com.trax.europeangateway.model.dto.FileinformationHeaderDto;
import com.trax.europeangateway.model.dto.ProcessorWriterDto;
import com.trax.europeangateway.model.dto.xsd.omega.TransactionPositionReport;
import com.trax.europeangateway.service.ExtractHeaderOmegaXml;
import com.trax.europeangateway.util.FileUtils;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Configuration
@EnableBatchProcessing
public class BatchConfiguration {
@Autowired
PIExtractoritemprocessor pIExtractoritemprocessor;
@Autowired
StepResultListener stepResultListener;
@Autowired
JobBuilderFactory jobBuilderFactory;
@Autowired
StepBuilderFactory stepBuilderFactory;
@Autowired
private FileUtils fileUtils;
@Qualifier("europeanGatewayJobExecutor")
@Autowired
private TaskExecutor taskExecutor;
@Value( "${eugateway.batch.chunk.size}" )
private int chunkSize;
@Qualifier("euGatewayJobLauncher")
@Bean
public JobLauncher euGatewayJobLauncher(JobRepository jobRepository) throws Exception {
SimpleJobLauncher jobLauncher = new SimpleJobLauncher();
jobLauncher.setJobRepository(jobRepository);
jobLauncher.setTaskExecutor(taskExecutor);
jobLauncher.afterPropertiesSet();
return jobLauncher;
}
@JobScope
@Bean (name = "extractHeaderStep")
public Step extractHeaderStep(StepBuilderFactory steps,@Value("#{jobParameters['file.path']}") String path) {
return steps.get("extractHeaderStep")
.tasklet((contribution,chunkContext) -> {
FileinformationHeaderDto fileinformation = new ExtractHeaderOmegaXml().readHeader(path);
ExecutionContext jobExecutionContext = chunkContext.getStepContext().getStepExecution().getJobExecution().getExecutionContext();
jobExecutionContext.put("file.information",fileinformation);
return RepeatStatus.FINISHED;
}).build();
}
@JobScope
@Bean (name = "extractAndReplacePersonalDataStep")
public Step jobStep(ItemStreamReader<TransactionPositionReport> reader,Compositeitemprocessor<TransactionPositionReport,ProcessorWriterDto> processor,CompositeItemWriter<ProcessorWriterDto> writer,StepBuilderFactory stepBuilderFactory) {
return stepBuilderFactory.get("extractAndReplacePersonalDataStep")
.<TransactionPositionReport,ProcessorWriterDto>chunk(chunkSize)
.reader(reader)
.processor(processor)
.writer(writer)
.listener(stepResultListener)
.build();
}
@Qualifier("omegaXmlJob")
@Bean
public Job extractPersonalDataJob(Step extractHeaderStep,Step extractAndReplacePersonalDataStep,JobResultListener jobListener,JobBuilderFactory jobBuilderFactory) {
return jobBuilderFactory.get("extractAndReplacePersonalDataJob")
.incrementer(new RunIdIncrementer())
.start(extractHeaderStep)
.next(extractAndReplacePersonalDataStep)
.listener(jobListener)
.build();
}
@Bean
@StepScope
public ItemStreamReader<TransactionPositionReport> itemReader(@Value("#{jobParameters['file.path']}") String path) {
Jaxb2Marshaller transactionMarshaller = new Jaxb2Marshaller();
transactionMarshaller.setMappedClass(TransactionPositionReport.class);
transactionMarshaller.setPackagesToScan(ClassUtils.getPackageName(TransactionPositionReport.class));
transactionMarshaller.setSupportJaxbElementClass(true);
transactionMarshaller.setSupportDtd(true);
log.debug("Generating StaxEventItemReader");
return new StaxEventItemReaderBuilder<TransactionPositionReport>()
.name("transactionPositionReport")
.resource(new FileSystemResource(path))
.addFragmentRootElements("transaction")
.unmarshaller(transactionMarshaller)
.build();
}
@Bean
@JobScope
OmegaXmlHeaderCallBack getomegaXmlHeaderCallBack(@Value("#{jobExecutionContext['file.information']}") FileinformationHeaderDto fileinformation){
return new OmegaXmlHeaderCallBack(fileinformation);
}
@Bean
OmegaXmlFooterCallBack getomegaXmlFooterCallBack(){
return new OmegaXmlFooterCallBack();
}
@StepScope
@Bean(name = "staxTransactionWriter")
public StaxEventItemWriter<TransactionPositionReport> staxTransactionItemWriter(OmegaXmlHeaderCallBack omegaXmlHeaderCallBack,@Value("#{jobParameters['file.path']}") String path,@Value("#{jobParameters['submission.account']}") String submissionAccount) {
Resource exportFileResource = new FileSystemResource(fileUtils.getoutputFilePath(path,submissionAccount));
Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
marshaller.setSupportJaxbElementClass(true);
marshaller.setClassesToBeBound(TransactionPositionReport.class);
HashMap<String,String> rootElementAttribs = new HashMap<String,String>();
rootElementAttribs.put("xmlns","http://deutsche-boerse.com/DBRegHub");
rootElementAttribs.put("xmlns:xsi","http://www.w3.org/2001/XMLSchema-instance");
rootElementAttribs.put("xsi:schemaLocation","http://deutsche-boerse.com/DBRegHub regulatoryHubUpload_MiFIR_001.60.xsd");
ExtendedStaxEventItemWriter<TransactionPositionReport> writer = new ExtendedStaxEventItemWriter<TransactionPositionReport>();
writer.setName("transactionWriter");
writer.setVersion("1.0");
writer.setResource(exportFileResource);
writer.setMarshaller(marshaller);
writer.setRoottagName("reportFile");
writer.setRootElementAttributes(rootElementAttribs);
writer.setHeaderCallback(omegaXmlHeaderCallBack);
writer.setFooterCallback(getomegaXmlFooterCallBack());
writer.setShouldDeleteIfEmpty(true);
writer.setIndenting(true);
return writer;
}
@StepScope
@Bean
public PIExtractoritemprocessor extractitemprocessor() {
log.debug("Generating PIExtractoritemprocessor");
return new PIExtractoritemprocessor();
}
@Bean
public PIRemoveritemprocessor removeitemprocessor() {
log.debug("Generating PIRemoveritemprocessor");
return new PIRemoveritemprocessor();
}
@Bean
@StepScope
Compositeitemprocessor<TransactionPositionReport,ProcessorWriterDto> extractAndRemoveitemprocessor() {
log.debug("Generating Compositeitemprocessor");
Compositeitemprocessor<TransactionPositionReport,ProcessorWriterDto> itemprocessor = new Compositeitemprocessor<>();
itemprocessor.setDelegates((List<? extends itemprocessor<?,?>>) Arrays.asList(extractitemprocessor(),removeitemprocessor()));
return itemprocessor;
}
@Bean
public EdsClientItemWriter<ProcessorWriterDto> edsClientItemWriter() {
log.debug("Generating EdsClientItemWriter");
return new EdsClientItemWriter<>();
}
@Bean
@StepScope
public OmegaXmlFileWriter<ProcessorWriterDto> omegaXmlFileWriter(OmegaXmlHeaderCallBack omegaXmlHeaderCallBack,@Value("#{jobParameters['submission.account']}") String submissionAccount) {
log.debug("Generating OmegaXmlFileWriter");
return new OmegaXmlFileWriter(staxTransactionItemWriter(omegaXmlHeaderCallBack,path,submissionAccount));
}
@Bean
@StepScope
public CompositeItemWriter<ProcessorWriterDto> compositeItemWriter(OmegaXmlHeaderCallBack omegaXmlHeaderCallBack,@Value("#{jobParameters['submission.account']}") String submissionAccount) {
log.debug("Generating CompositeItemWriter");
CompositeItemWriter<ProcessorWriterDto> compositeItemWriter = new CompositeItemWriter<>();
compositeItemWriter.setDelegates(Arrays.asList(edsClientItemWriter(),omegaXmlFileWriter(omegaXmlHeaderCallBack,submissionAccount)));
return compositeItemWriter;
}
@Bean
public RestTemplate restTemplate() {
log.debug("Generating RestTemplate");
return new RestTemplate();
}
}
尝试编组时得到的异常堆栈跟踪
//
// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation,v2.2.8-b130911.1802
// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a>
// Any modifications to this file will be lost upon recompilation of the source schema.
// Generated on: 2021.05.18 at 02:21:55 PM BST
//
import javax.xml.bind.annotation.XmlAccesstype;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
/**
* <p>Java class for transactionPositionReport complex type.
*
* <p>The following schema fragment specifies the expected content contained within this class.
*
* <pre>
* <complexType name="transactionPositionReport">
* <complexContent>
* <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
* <sequence>
* <element name="processingDetails" type="{http://deutsche-boerse.com/DBRegHub}processingDetails"/>
* <element name="configurableFields" type="{http://deutsche-boerse.com/DBRegHub}configurableFields" minOccurs="0"/>
* <element name="mifir" type="{http://deutsche-boerse.com/DBRegHub}mifirDetails" minOccurs="0"/>
* </sequence>
* </restriction>
* </complexContent>
* </complexType>
* </pre>
*
*
*/
@XmlAccessorType(XmlAccesstype.FIELD)
@XmlType(name = "transactionPositionReport",propOrder = {
"processingDetails","configurableFields","mifir"
})
public class TransactionPositionReport {
@XmlElement(required = true)
protected ProcessingDetails processingDetails;
protected ConfigurableFields configurableFields;
protected MifirDetails mifir;
/**
* Gets the value of the processingDetails property.
*
* @return
* possible object is
* {@link ProcessingDetails }
*
*/
public ProcessingDetails getProcessingDetails() {
return processingDetails;
}
/**
* Sets the value of the processingDetails property.
*
* @param value
* allowed object is
* {@link ProcessingDetails }
*
*/
public void setProcessingDetails(ProcessingDetails value) {
this.processingDetails = value;
}
/**
* Gets the value of the configurableFields property.
*
* @return
* possible object is
* {@link ConfigurableFields }
*
*/
public ConfigurableFields getConfigurableFields() {
return configurableFields;
}
/**
* Sets the value of the configurableFields property.
*
* @param value
* allowed object is
* {@link ConfigurableFields }
*
*/
public void setConfigurableFields(ConfigurableFields value) {
this.configurableFields = value;
}
/**
* Gets the value of the mifir property.
*
* @return
* possible object is
* {@link MifirDetails }
*
*/
public MifirDetails getMifir() {
return mifir;
}
/**
* Sets the value of the mifir property.
*
* @param value
* allowed object is
* {@link MifirDetails }
*
*/
public void setMifir(MifirDetails value) {
this.mifir = value;
}
}
//
// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation,v2.2.8-b130911.1802
// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a>
// Any modifications to this file will be lost upon recompilation of the source schema.
// Generated on: 2021.05.18 at 02:21:55 PM BST
//
import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.annotation.XmlAccesstype;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlType;
/**
* <p>Java class for record complex type.
*
* <p>The following schema fragment specifies the expected content contained within this class.
*
* <pre>
* <complexType name="record">
* <complexContent>
* <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
* <choice>
* <element name="transaction" type="{http://deutsche-boerse.com/DBRegHub}transactionPositionReport" maxOccurs="unbounded" minOccurs="0"/>
* <element name="referencePartyDetails" type="{http://deutsche-boerse.com/DBRegHub}referencePartyDetails" maxOccurs="unbounded" minOccurs="0"/>
* </choice>
* </restriction>
* </complexContent>
* </complexType>
* </pre>
*
*
*/
@XmlAccessorType(XmlAccesstype.FIELD)
@XmlType(name = "record",propOrder = {
"transaction","referencePartyDetails"
})
public class Record {
protected List<TransactionPositionReport> transaction;
protected List<ReferencePartyDetails> referencePartyDetails;
/**
* Gets the value of the transaction property.
*
* <p>
* This accessor method returns a reference to the live list,* not a snapshot. Therefore any modification you make to the
* returned list will be present inside the JAXB object.
* This is why there is not a <CODE>set</CODE> method for the transaction property.
*
* <p>
* For example,to add a new item,do as follows:
* <pre>
* getTransaction().add(newItem);
* </pre>
*
*
* <p>
* Objects of the following type(s) are allowed in the list
* {@link TransactionPositionReport }
*
*
*/
public List<TransactionPositionReport> getTransaction() {
if (transaction == null) {
transaction = new ArrayList<TransactionPositionReport>();
}
return this.transaction;
}
public List<ReferencePartyDetails> getReferencePartyDetails() {
if (referencePartyDetails == null) {
referencePartyDetails = new ArrayList<ReferencePartyDetails>();
}
return this.referencePartyDetails;
}
}
import javax.xml.bind.annotation.XmlAccesstype;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
/**
* <p>Java class for anonymous complex type.
*
* <p>The following schema fragment specifies the expected content contained within this class.
*
* <pre>
* <complexType>
* <complexContent>
* <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
* <sequence>
* <element name="fileinformation" type="{http://deutsche-boerse.com/DBRegHub}fileinformation"/>
* <element name="record" type="{http://deutsche-boerse.com/DBRegHub}record"/>
* </sequence>
* </restriction>
* </complexContent>
* </complexType>
* </pre>
*
*
*/
@XmlAccessorType(XmlAccesstype.FIELD)
@XmlType(name = "",propOrder = {
"fileinformation","record"
})
@XmlRootElement(name = "reportFile")
public class ReportFile {
@XmlElement(required = true)
protected Fileinformation fileinformation;
@XmlElement(required = true)
protected Record record;
/**
* Gets the value of the fileinformation property.
*
* @return
* possible object is
* {@link Fileinformation }
*
*/
public Fileinformation getFileinformation() {
return fileinformation;
}
/**
* Sets the value of the fileinformation property.
*
* @param value
* allowed object is
* {@link Fileinformation }
*
*/
public void setFileinformation(Fileinformation value) {
this.fileinformation = value;
}
/**
* Gets the value of the record property.
*
* @return
* possible object is
* {@link Record }
*
*/
public Record getRecord() {
return record;
}
/**
* Sets the value of the record property.
*
* @param value
* allowed object is
* {@link Record }
*
*/
public void setRecord(Record value) {
this.record = value;
}
}
仅供参考:在生成的 Java 类中,只有 java.lang.IllegalStateException: Marshaller must support the class of the marshalled object
at org.springframework.util.Assert.state(Assert.java:76) ~[spring-core-5.2.8.RELEASE.jar:5.2.8.RELEASE]
at org.springframework.batch.item.xml.StaxEventItemWriter.write(StaxEventItemWriter.java:767) ~[spring-batch-infrastructure-4.2.4.RELEASE.jar:4.2.4.RELEASE]
at org.springframework.batch.item.xml.StaxEventItemWriter$$FastClassBySpringcglib$$d105dd1.invoke(<generated>) ~[spring-batch-infrastructure-4.2.4.RELEASE.jar:4.2.4.RELEASE]
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) ~[spring-core-5.2.8.RELEASE.jar:5.2.8.RELEASE]
at org.springframework.aop.framework.cglibAopProxy$cglibMethodInvocation.invokeJoinpoint(cglibAopProxy.java:771) ~[spring-aop-5.2.8.RELEASE.jar:5.2.8.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-5.2.8.RELEASE.jar:5.2.8.RELEASE]
at org.springframework.aop.framework.cglibAopProxy$cglibMethodInvocation.proceed(cglibAopProxy.java:749) ~[spring-aop-5.2.8.RELEASE.jar:5.2.8.RELEASE]
at org.springframework.aop.support.DelegatingIntroductionInterceptor.doProceed(DelegatingIntroductionInterceptor.java:136) ~[spring-aop-5.2.8.RELEASE.jar:5.2.8.RELEASE]
at org.springframework.aop.support.DelegatingIntroductionInterceptor.invoke(DelegatingIntroductionInterceptor.java:124) ~[spring-aop-5.2.8.RELEASE.jar:5.2.8.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.2.8.RELEASE.jar:5.2.8.RELEASE]
at org.springframework.aop.framework.cglibAopProxy$cglibMethodInvocation.proceed(cglibAopProxy.java:749) ~[spring-aop-5.2.8.RELEASE.jar:5.2.8.RELEASE]
at org.springframework.aop.framework.cglibAopProxy$DynamicAdvisedInterceptor.intercept(cglibAopProxy.java:691) ~[spring-aop-5.2.8.RELEASE.jar:5.2.8.RELEASE]
at org.springframework.batch.item.xml.StaxEventItemWriter$$EnhancerBySpringcglib$$25cb8145.write(<generated>) ~[spring-batch-infrastructure-4.2.4.RELEASE.jar:4.2.4.RELEASE]
at com.trax.europeangateway.itemwriter.omegaxml.OmegaXmlFileWriter.write(OmegaXmlFileWriter.java:37) ~[classes/:?]
at com.trax.europeangateway.itemwriter.omegaxml.OmegaXmlFileWriter$$FastClassBySpringcglib$$48e7f3da.invoke(<generated>) ~[classes/:?]
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) ~[spring-core-5.2.8.RELEASE.jar:5.2.8.RELEASE]
类使用 ReportFile
进行注释。但是如果我用 @XmlRootElement
注释 transaction
类,我可以生成一个 XML 文件,但是输出文件中的所有事务标记都带有命名空间信息。
@XmlRootElement
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。