Spring Batch Tutorial: Reading Information From an XML File

Spring Batch Tutorial: Reading Information From an XML File

adminJuly 7, 202015min170
adminJuly 7, 202015min170
petrikainulainen
The previous part of my Spring Batch tutorial described how we can read information from a CSV File. This time we will learn to read the input data of our Spring Batch job from an XML file. After we have read this blog post, we: Can identify the dependencies which are required when we want […]


The previous part of my Spring Batch tutorial described how we can read information from a CSV File. This time we will learn to read the input data of our Spring Batch job from an XML file. After we have read this blog post, we:

  • Can identify the dependencies which are required when we want to read the input data of our batch job from an XML file.
  • Can get the required dependencies with Maven and Gradle.
  • Understand how we can configure an ItemReader bean which reads the input data of our batch job from an XML file.

Let’s start by taking a quick look at our example application.

This blog post assumes that:

  • You are familiar with Spring Batch
  • You can get the required dependencies with Maven or Gradle

Introduction to Our Example Application

During this blog post we will read the input data of our batch job from an XML file which contains the student information of an online course. To be more specific, the XML file contains a student list that provides the following information to our batch job:

  • The name of the student.
  • The email address of the student.
  • The name of the purchased package.

The content of our input file looks as follows:

<students>
    <student>
        <name>Tony Tester</name>
        <emailAddress>[email protected]</emailAddress>
        <purchasedPackage>master</purchasedPackage>
    </student>
    <student>
        <name>Nick Newbie</name>
        <emailAddress>[email protected]</emailAddress>
        <purchasedPackage>starter</purchasedPackage>
    </student>
    <student>
        <name>Ian Intermediate</name>
        <emailAddress>[email protected]</emailAddress>
        <purchasedPackage>intermediate</purchasedPackage>
    </student>
</students>

The ItemReader which reads the student list from an XML file must return StudentDTO objects. A StudentDTO class contains the information of a single student, and its source code looks as follows:

public class StudentDTO {
    private String emailAddress;
    private String name;
    private String purchasedPackage;
    public StudentDTO() {}
    public String getEmailAddress() {
        return emailAddress;
    }
    public String getName() {
        return name;
    }
    public String getPurchasedPackage() {
        return purchasedPackage;
    }
    public void setEmailAddress(String emailAddress) {
        this.emailAddress = emailAddress;
    }
    public void setName(String name) {
        this.name = name;
    }
    public void setPurchasedPackage(String purchasedPackage) {
        this.purchasedPackage = purchasedPackage;
    }
}

Next, we will get the required dependencies with Maven and Gradle.

Getting the Required Dependencies

Before we can read information from an XML file, we must get the following dependencies:

  • The spring-oxm dependency helps us to serialize objects to XML documents and deserialize XML documents to objects.
  • The jaxb-api depedency allows us to compile code which uses the JAXB API when we are using Java 11 or newer.
  • The jaxb-runtime dependency allows us to run an application which uses the JAXB API when we are using Java 11 or newer.

If we are using the dependency management of Spring Boot with Maven, we can get these dependencies by adding the following dependency declarations to the dependencies section of our POM file:

<dependency>
    <groupId>javax.xml.bind</groupId>
    <artifactId>jaxb-api</artifactId>
</dependency>
<dependency>
    <groupId>org.glassfish.jaxb</groupId>
    <artifactId>jaxb-runtime</artifactId>
    <scope>runtime</scope>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-oxm</artifactId>
</dependency>

If we are using the dependency management of Spring Boot with Gradle, we can get these dependencies by adding the following dependency declarations to our build.gradle file:

dependencies {
    implementation(
            'javax.xml.bind:jaxb-api',
            'org.springframework:spring-oxm'
    )
    runtimeOnly(
            'org.glassfish.jaxb:jaxb-runtime'
    )
}

Let’s move and find out how we can read the input data of our batch job from an XML file.

Reading the Input Data From an XML File

We can provide the input data for our batch job by configuring an ItemReader bean. Because we want to read the student information from an XML file, we have to configure this bean by following these steps:

First, we have to create the configuration class which contains the beans that describe the flow of our batch job. The source code of our configuration class looks as follows:

import org.springframework.context.annotation.Configuration;
@Configuration
public class SpringBatchExampleJobConfig {
}

Second, we have to create the method that configures our ItemReader bean and ensure that this method returns an ItemReader<StudentDTO> object. After we have created this method, the source code of our configuration class looks as follows:

import org.springframework.batch.item.ItemReader;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class SpringBatchExampleJobConfig {
    @Bean
    public ItemReader<StudentDTO> itemReader() {
        
    }
}

Third, we have to configure our ItemReader bean by following these steps:

  1. Create a new StaxEventItemReader<StudentDTO> object. This object reads the input data from an XML file by using StAX (the Streaming API for XML).
  2. Configure the location of the XML file which contains the input data of our batch job. Because I wanted to create an example application that’s as easy to run as possible, I ensured that the input file (data/students.xml) of our batch job is found from the classpath.
  3. Configure the name of the XML element (student) that contains the information of a single student.
  4. Ensure that the StaxEventItemReader<StudentDTO> object transforms the processed XML fragment into a StudentDTO object by using JAXB2.
  5. Return the created StaxEventItemReader<StudentDTO> object.

After we have configured our ItemReader bean, the source code of our configuration class looks as follows:

import org.springframework.batch.item.ItemReader;
import org.springframework.batch.item.xml.StaxEventItemReader;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.oxm.jaxb.Jaxb2Marshaller;
@Configuration
public class SpringBatchExampleJobConfig {
    @Bean
    public ItemReader<StudentDTO> itemReader() {
        StaxEventItemReader<StudentDTO> xmlFileReader = new StaxEventItemReader<>();
        xmlFileReader.setResource(new ClassPathResource("data/students.xml"));
        xmlFileReader.setFragmentRootElementName("student");
        Jaxb2Marshaller studentMarshaller = new Jaxb2Marshaller();
        studentMarshaller.setClassesToBeBound(StudentDTO.class);
        xmlFileReader.setUnmarshaller(studentMarshaller);
        return xmlFileReader;
    }
}
We must configure the location of our input file by creating a new ClassPathResource object because I wanted to create an example application that’s as easy to run as possible. Typically, the input file of our batch job is found from the file system. This means that we can configure its location by creating a new FileSystemResource object.

Additional Reading:

  • Lesson: Streaming API for XML
  • Spring Batch Reference Documentation: StaxEventItemReader

Before our ItemReader bean can transform the student information read from the student.xml file into StudentDTO objects, we have to configure the name of the fragment root element in the StudentDTO class. We can do this by following these steps:

  1. Annotate the class with the @XmlRootElement annotation.
  2. Configure the name of the root element by setting the value of the @XmlRootElement annotation’s name attribute to: ‘student’.

After we have made this change to the StudentDTO class, its source code looks as follows:

import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement(name="student")
public class StudentDTO {
    private String emailAddress;
    private String name;
    private String purchasedPackage;
    public StudentDTO() {}
    public String getEmailAddress() {
        return emailAddress;
    }
    public String getName() {
        return name;
    }
    public String getPurchasedPackage() {
        return purchasedPackage;
    }
    public void setEmailAddress(String emailAddress) {
        this.emailAddress = emailAddress;
    }
    public void setName(String name) {
        this.name = name;
    }
    public void setPurchasedPackage(String purchasedPackage) {
        this.purchasedPackage = purchasedPackage;
    }
}
Because the element names of the processed XML fragments are the same as the field names of the StudentDTO class, we don’t have to add additional annotations to the StudentDTO class. If the element names aren’t the same as the field names of the target class, or we have to use custom marshalling, we have to annotate our DTO class with JAXB annotations.

Additional Reading:

  • JAXB Users Guide: 3. Annotating Your Classes

We can now read the input data of our batch job from an XML file. Let’s summarize what we learned from this blog post.

Summary

This blog post has taught us five things:

  • The spring-oxm dependency helps us to serialize objects to XML documents and deserialize XML documents to objects.
  • The jaxb-api dependency allows us to compile code which uses the JAXB API when we are using Java 11 or newer.
  • The jaxb-runtime dependency allows us to run an application which uses the JAXB API when we are using Java 11 or newer.
  • We can read the input data of our batch job from an XML file by using the StaxEventItemReader class.
  • We must configure the name of the fragment root element by annotating our DTO class with the @XmlRootElement annotation.

P.S. You can get the example application of this blog post from Github.

    

Related Stories

  • Spring Batch Tutorial: Writing Information to a Database With JDBC
  • Spring From the Trenches: Cleaning Up Our Test Code With HTTP Request Builders
  • Spring From the Trenches: Disabling Cookie Management of Apache HTTP Client 4 and RestTemplate

 



Source link

Share it

Leave a Reply

Your email address will not be published. Required fields are marked *