Search code examples
xmlspringspring-batchstax

XML default namespace StaxEventItemWriter error


I have a Spring batch application with StaxEventItemWriter. All works, but i need to add xmlns="http://www.demandware.com/1212" to root element. When i create map and add attribute xmlns with value with my link and then set it as .rootElementAttributes(attrs) i have an exception while generating xml

Caused by: javax.xml.stream.XMLStreamException: xmlns has been already bound to . Rebinding it to http://www.demandware.com/1212 is an error

How can i add default namespace?


Solution

  • i need to add xmlns="http://www.demandware.com/1212" to root element

    Here is an example of how to add a custom namespace to the root element:

    import java.util.Arrays;
    import java.util.HashMap;
    
    import javax.xml.bind.annotation.XmlRootElement;
    
    import org.springframework.batch.core.Job;
    import org.springframework.batch.core.JobParameters;
    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.StepBuilderFactory;
    import org.springframework.batch.core.launch.JobLauncher;
    import org.springframework.batch.item.ItemReader;
    import org.springframework.batch.item.ItemWriter;
    import org.springframework.batch.item.support.ListItemReader;
    import org.springframework.batch.item.xml.builder.StaxEventItemWriterBuilder;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.annotation.AnnotationConfigApplicationContext;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.core.io.FileSystemResource;
    import org.springframework.oxm.jaxb.Jaxb2Marshaller;
    
    @Configuration
    @EnableBatchProcessing
    public class MyJob {
    
        @Autowired
        private JobBuilderFactory jobs;
    
        @Autowired
        private StepBuilderFactory steps;
    
        @Bean
        public ItemReader<Person> itemReader() {
            return new ListItemReader<>(Arrays.asList(
                    new Person(1, "foo"),
                    new Person(2, "bar"))
            );
        }
    
        @Bean
        public ItemWriter<Person> itemWriter() {
            Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
            marshaller.setClassesToBeBound(Person.class);
            HashMap<String, String> rootElementAttributes = new HashMap<String, String>() {{
                put("xmlns", "http://www.demandware.com/1212");
            }};
            return new StaxEventItemWriterBuilder<Person>()
                    .name("personWriter")
                    .resource(new FileSystemResource("persons.xml"))
                    .marshaller(marshaller)
                    .rootTagName("persons")
                    .rootElementAttributes(rootElementAttributes)
                    .build();
        }
    
        @Bean
        public Step step() {
            return steps.get("step")
                    .<Person, Person>chunk(5)
                    .reader(itemReader())
                    .writer(itemWriter())
                    .build();
        }
    
        @Bean
        public Job job() {
            return jobs.get("job")
                    .start(step())
                    .build();
        }
    
        public static void main(String[] args) throws Exception {
            ApplicationContext context = new AnnotationConfigApplicationContext(MyJob.class);
            JobLauncher jobLauncher = context.getBean(JobLauncher.class);
            Job job = context.getBean(Job.class);
            jobLauncher.run(job, new JobParameters());
        }
    
        @XmlRootElement
        public static class Person {
    
            private int id;
            private String name;
    
            public Person(int id, String name) {
                this.id = id;
                this.name = name;
            }
    
            public Person() {
            }
    
            public int getId() {
                return id;
            }
    
            public void setId(int id) {
                this.id = id;
            }
    
            public String getName() {
                return name;
            }
    
            public void setName(String name) {
                this.name = name;
            }
        }
    
    }
    

    It generates the following persons.xml:

    <?xml version='1.0' encoding='UTF-8'?>
    <persons xmlns="http://www.demandware.com/1212">
            <person>
                <id>1</id>
                <name>foo</name>
            </person>
            <person>
                <id>2</id>
                <name>bar</name>
            </person>
    </persons>
    

    Tested with Spring Batch v4.1.2.